From 5f13e7ec5c1d98f4a63a3a79e66b2b121051f5ac Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 16 May 2005 08:53:52 -0700 Subject: [PATCH] smc91x needs settable IRQ trigger type For boards that invert the SMC91x IRQ line (maybe an FPGA inverts it), the set_irq_type() call can't assume IRQT_RISING. These particular boards currently use OMAP-specific calls to change the trigger type, but the boards break when set_irq_type() stops being a NOP. Signed-off-by: David Brownell --- drivers/net/smc91x.c | 2 +- drivers/net/smc91x.h | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index cfb9d3cdb04..1438fdd2082 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1998,7 +1998,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) if (retval) goto err_out; - set_irq_type(dev->irq, IRQT_RISING); + set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE); #ifdef SMC_USE_PXA_DMA { diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 946528e6b74..7089d86e857 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -182,6 +182,16 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) #define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) +#include +#include + +#define SMC_IRQ_TRIGGER_TYPE (( \ + machine_is_omap_h2() \ + || machine_is_omap_h3() \ + || (machine_is_omap_innovator() && !cpu_is_omap150()) \ + ) ? IRQT_FALLING : IRQT_RISING) + + #elif defined(CONFIG_SH_SH4202_MICRODEV) #define SMC_CAN_USE_8BIT 0 @@ -300,6 +310,9 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l) #endif +#ifndef SMC_IRQ_TRIGGER_TYPE +#define SMC_IRQ_TRIGGER_TYPE IRQT_RISING +#endif #ifdef SMC_USE_PXA_DMA /* -- cgit v1.2.3 From cac8c81a59bd3b6815871b3172e8ccf15a3431e0 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 16 May 2005 19:15:11 +0200 Subject: [PATCH] Use pci_set_dma_mask() instead of direct assignment of DMA mask The amd8111e driver directly assigns the DMA mask to the dma_mask member of the struct pci_dev instead of using pci_set_dma_mask(). This makes the call to pci_dma_supported() redundant as pci_set_dma_mask() does this check. I do not own this device so I only compile-tested this patch. Signed-off-by: Tobias Klauser --- drivers/net/amd8111e.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index b7dd7260caf..8618012df06 100755 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -87,6 +87,7 @@ Revision History: #include #include #include +#include #include #include @@ -2006,12 +2007,11 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, } /* Initialize DMA */ - if(!pci_dma_supported(pdev, 0xffffffff)){ + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) < 0) { printk(KERN_ERR "amd8111e: DMA not supported," "exiting.\n"); - goto err_free_reg; - } else - pdev->dma_mask = 0xffffffff; + goto err_free_reg; + } reg_addr = pci_resource_start(pdev, 0); reg_len = pci_resource_len(pdev, 0); -- cgit v1.2.3 From c903e41e67046e7f52bbc404bd5aa654d12540cc Mon Sep 17 00:00:00 2001 From: Komuro Date: Mon, 27 Jun 2005 23:23:05 -0400 Subject: drivers/net/at1700: remove incorrect comment "Allied Telesis RE1000 Plus" is not supported at all by kernel 2.6.12. Signed-off-by: komurojun-mbn@nifty.com --- drivers/net/at1700.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index b8ab2b6355e..e613cc28974 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -34,10 +34,6 @@ only is it difficult to detect, it also moves around in I/O space in response to inb()s from other device probes! */ -/* - 99/03/03 Allied Telesis RE1000 Plus support by T.Hagawa - 99/12/30 port to 2.3.35 by K.Takai -*/ #include #include -- cgit v1.2.3 From e922256ae4bb6ef954bd7e0740d9753460e0ab72 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 28 Jun 2005 00:03:37 -0400 Subject: libata: update DMA blacklist Contributions from Alan Cox and maximilian attems. --- drivers/scsi/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 36b401fee1f..fd66f56fd61 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1920,6 +1920,7 @@ static const char * ata_dma_blacklist [] = { "HITACHI CDR-8335", "HITACHI CDR-8435", "Toshiba CD-ROM XM-6202B", + "TOSHIBA CD-ROM XM-1702BC", "CD-532E-A", "E-IDE CD-ROM CR-840", "CD-ROM Drive/F5A", @@ -1927,7 +1928,6 @@ static const char * ata_dma_blacklist [] = { "SAMSUNG CD-ROM SC-148C", "SAMSUNG CD-ROM SC", "SanDisk SDP3B-64", - "SAMSUNG CD-ROM SN-124", "ATAPI CD-ROM DRIVE 40X MAXIMUM", "_NEC DV5800A", }; -- cgit v1.2.3 From 62ba2841f2a51848f7cb0499edae3f6803764f2c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 26 Jun 2005 23:27:19 +0900 Subject: [PATCH] libata: lengthen COMMRESET delay This patch lengthens the delay between DET setting and clearing for COMMRESET from 400us to 1ms. I couldn't find any requiremen regarding the duration of COMMRESET in SATA I/II specs but AHCI-1.1 10.4.2 states that it should be at least 1ms. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index fd66f56fd61..cb535fa185b 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1408,7 +1408,9 @@ void __sata_phy_reset(struct ata_port *ap) if (ap->flags & ATA_FLAG_SATA_RESET) { /* issue phy wake/reset */ scr_write_flush(ap, SCR_CONTROL, 0x301); - udelay(400); /* FIXME: a guess */ + /* Couldn't find anything in SATA I/II specs, but + * AHCI-1.1 10.4.2 says at least 1 ms. */ + mdelay(1); } scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */ -- cgit v1.2.3 From 0a139e79976b9eb60517edec63406236a789f812 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 26 Jun 2005 23:52:50 +0900 Subject: [PATCH] libata: ahci: remove ata_port_start/stop() calls This patch removes unnecessary ata_port_start/stop() calls from ahci_port_start/stop(). Signed-off-by: Tejun Heo --- drivers/scsi/ahci.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 9a547ca9c86..c5623694d10 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -304,26 +304,19 @@ static int ahci_port_start(struct ata_port *ap) struct device *dev = ap->host_set->dev; struct ahci_host_priv *hpriv = ap->host_set->private_data; struct ahci_port_priv *pp; - int rc; void *mem, *mmio = ap->host_set->mmio_base; void *port_mmio = ahci_port_base(mmio, ap->port_no); dma_addr_t mem_dma; - rc = ata_port_start(ap); - if (rc) - return rc; - pp = kmalloc(sizeof(*pp), GFP_KERNEL); - if (!pp) { - rc = -ENOMEM; - goto err_out; - } + if (!pp) + return -ENOMEM; memset(pp, 0, sizeof(*pp)); mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); if (!mem) { - rc = -ENOMEM; - goto err_out_kfree; + kfree(pp); + return -ENOMEM; } memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); @@ -373,12 +366,6 @@ static int ahci_port_start(struct ata_port *ap) readl(port_mmio + PORT_CMD); /* flush */ return 0; - -err_out_kfree: - kfree(pp); -err_out: - ata_port_stop(ap); - return rc; } @@ -404,7 +391,6 @@ static void ahci_port_stop(struct ata_port *ap) dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, pp->cmd_slot, pp->cmd_slot_dma); kfree(pp); - ata_port_stop(ap); } static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) -- cgit v1.2.3 From 881a8c120acf7ec09c90289e2996b7c70f51e996 Mon Sep 17 00:00:00 2001 From: Amit Gud Date: Tue, 12 Apr 2005 19:03:33 +0530 Subject: [PATCH] pci: remove deprecates Replace pci_find_device() with more safer pci_get_device(). Signed-off-by: Amit Gud Signed-off-by: Greg Kroah-Hartman --- drivers/char/moxa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 7c24fbe831f..95f7046ff05 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -451,7 +451,7 @@ static int __init moxa_init(void) int n = (sizeof(moxa_pcibrds) / sizeof(moxa_pcibrds[0])) - 1; i = 0; while (i < n) { - while ((p = pci_find_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL) + while ((p = pci_get_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL) { if (pci_enable_device(p)) continue; -- cgit v1.2.3 From efe1ec27837d6639eae82e1f5876910ba6433c3f Mon Sep 17 00:00:00 2001 From: Amit Gud Date: Tue, 12 Apr 2005 19:04:27 +0530 Subject: [PATCH] pci: remove deprecates Replace pci_find_device() with more safer pci_get_device(). Signed-off-by: Amit Gud Signed-off-by: Greg Kroah-Hartman --- drivers/char/rio/rio_linux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 7db3370f497..d7d484024e2 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -1095,7 +1095,7 @@ static int __init rio_init(void) #ifdef CONFIG_PCI /* First look for the JET devices: */ - while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, + while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, pdev))) { if (pci_enable_device(pdev)) continue; @@ -1169,7 +1169,7 @@ static int __init rio_init(void) */ /* Then look for the older RIO/PCI devices: */ - while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, + while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_RIO, pdev))) { if (pci_enable_device(pdev)) continue; -- cgit v1.2.3 From c431ada45d65b305a6aab4557067e564b23ce5a5 Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:45 -0700 Subject: [PATCH] acpi bridge hotadd: ACPI based root bridge hot-add When you hot-plug a (root) bridge hierarchy, it may have p2p bridges and devices attached to it that have not been configured by firmware. In this case, we need to configure the devices before starting them. This patch separates device start from device scan so that we can introduce the configuration step in the middle. I kept the existing semantics for pci_scan_bus() since there are a huge number of callers to that function. Also, I have no way of testing the changes I made to the parisc files, so this needs review by those folks. Sorry for the massive cross-post, this touches files in many different places. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/pci_bind.c | 16 +++++++++++++++- drivers/acpi/pci_root.c | 24 +++++++++++++++++++++++- drivers/parisc/dino.c | 1 + drivers/parisc/lba_pci.c | 2 ++ drivers/pci/probe.c | 2 -- 5 files changed, 41 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 5d19b39e9e2..7753df1f9fb 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -129,6 +129,8 @@ acpi_pci_bind ( char *pathname = NULL; struct acpi_buffer buffer = {0, NULL}; acpi_handle handle = NULL; + struct pci_dev *dev; + struct pci_bus *bus; ACPI_FUNCTION_TRACE("acpi_pci_bind"); @@ -193,8 +195,20 @@ acpi_pci_bind ( * Locate matching device in PCI namespace. If it doesn't exist * this typically means that the device isn't currently inserted * (e.g. docking station, port replicator, etc.). + * We cannot simply search the global pci device list, since + * PCI devices are added to the global pci list when the root + * bridge start ops are run, which may not have happened yet. */ - data->dev = pci_find_slot(data->id.bus, PCI_DEVFN(data->id.device, data->id.function)); + bus = pci_find_bus(data->id.segment, data->id.bus); + if (bus) { + list_for_each_entry(dev, &bus->devices, bus_list) { + if (dev->devfn == PCI_DEVFN(data->id.device, + data->id.function)) { + data->dev = dev; + break; + } + } + } if (!data->dev) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %02x:%02x:%02x.%02x not present in PCI namespace\n", diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 7e6b8e3b2ed..5d2f77fcd50 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -46,6 +46,7 @@ ACPI_MODULE_NAME ("pci_root") static int acpi_pci_root_add (struct acpi_device *device); static int acpi_pci_root_remove (struct acpi_device *device, int type); +static int acpi_pci_root_start (struct acpi_device *device); static struct acpi_driver acpi_pci_root_driver = { .name = ACPI_PCI_ROOT_DRIVER_NAME, @@ -54,6 +55,7 @@ static struct acpi_driver acpi_pci_root_driver = { .ops = { .add = acpi_pci_root_add, .remove = acpi_pci_root_remove, + .start = acpi_pci_root_start, }, }; @@ -169,6 +171,7 @@ acpi_pci_root_add ( if (!root) return_VALUE(-ENOMEM); memset(root, 0, sizeof(struct acpi_pci_root)); + INIT_LIST_HEAD(&root->node); root->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); @@ -298,12 +301,31 @@ acpi_pci_root_add ( root->id.bus); end: - if (result) + if (result) { + if (!list_empty(&root->node)) + list_del(&root->node); kfree(root); + } return_VALUE(result); } +static int +acpi_pci_root_start ( + struct acpi_device *device) +{ + struct acpi_pci_root *root; + + ACPI_FUNCTION_TRACE("acpi_pci_root_start"); + + list_for_each_entry(root, &acpi_pci_roots, node) { + if (root->handle == device->handle) { + pci_bus_add_devices(root->bus); + return_VALUE(0); + } + } + return_VALUE(-ENODEV); +} static int acpi_pci_root_remove ( diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index b0d2a73d1d4..2f2dbef2c3b 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -993,6 +993,7 @@ dino_driver_callback(struct parisc_device *dev) bus = pci_scan_bus_parented(&dev->dev, dino_current_bus, &dino_cfg_ops, NULL); if(bus) { + pci_bus_add_devices(bus); /* This code *depends* on scanning being single threaded * if it isn't, this global bus number count will fail */ diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index dc838804c0d..7fdd80b7eb4 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1570,6 +1570,8 @@ lba_driver_probe(struct parisc_device *dev) lba_bus = lba_dev->hba.hba_bus = pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start, cfg_ops, NULL); + if (lba_bus) + pci_bus_add_devices(lba_bus); /* This is in lieu of calling pci_assign_unassigned_resources() */ if (is_pdc_pat()) { diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index fd48b201eb5..3dc00f0ca8a 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -911,8 +911,6 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, b->subordinate = pci_scan_child_bus(b); - pci_bus_add_devices(b); - return b; sys_create_link_err: -- cgit v1.2.3 From cc57450f5c044270d2cf1dd437c1850422262109 Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:47 -0700 Subject: [PATCH] acpi bridge hotadd: Prevent duplicate bus numbers when scanning PCI bridge When hot-plugging a root bridge, as we try to assign bus numbers we may find that the hotplugged hieratchy has more PCI to PCI bridges (i.e. bus requirements) than available. Make sure we don't step over an existing bus when that happens. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 3dc00f0ca8a..6186f4d7b11 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -411,7 +411,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max { struct pci_bus *child; int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); - u32 buses; + u32 buses, i; u16 bctl; pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); @@ -470,6 +470,10 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max /* Clear errors */ pci_write_config_word(dev, PCI_STATUS, 0xffff); + /* Prevent assigning a bus number that already exists. + * This can happen when a bridge is hot-plugged */ + if (pci_find_bus(pci_domain_nr(bus), max+1)) + return max; child = pci_alloc_child_bus(bus, dev, ++max); buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) @@ -501,7 +505,11 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max * as cards with a PCI-to-PCI bridge can be * inserted later. */ - max += CARDBUS_RESERVE_BUSNR; + for (i=0; i Date: Thu, 28 Apr 2005 00:25:48 -0700 Subject: [PATCH] acpi bridge hotadd: Take the PCI lock when modifying pci bus or device lists With root bridge and pci bridge hot-plug, new buses and devices can be added or removed at run time. Protect the pci bus and device lists with the pci lock when doing so. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6186f4d7b11..7d171f83257 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -374,8 +374,11 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de struct pci_bus *child; child = pci_alloc_child_bus(parent, dev, busnr); - if (child) + if (child) { + spin_lock(&pci_bus_lock); list_add_tail(&child->node, &parent->children); + spin_unlock(&pci_bus_lock); + } return child; } @@ -765,7 +768,9 @@ pci_scan_single_device(struct pci_bus *bus, int devfn) * and the bus list for fixup functions, etc. */ INIT_LIST_HEAD(&dev->global_list); + spin_lock(&pci_bus_lock); list_add_tail(&dev->bus_list, &bus->devices); + spin_unlock(&pci_bus_lock); return dev; } @@ -886,7 +891,9 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); goto err_out; } + spin_lock(&pci_bus_lock); list_add_tail(&b->node, &pci_root_buses); + spin_unlock(&pci_bus_lock); memset(dev, 0, sizeof(*dev)); dev->parent = parent; @@ -928,7 +935,9 @@ class_dev_create_file_err: class_dev_reg_err: device_unregister(dev); dev_reg_err: + spin_lock(&pci_bus_lock); list_del(&b->node); + spin_unlock(&pci_bus_lock); err_out: kfree(dev); kfree(b); -- cgit v1.2.3 From 6ef6f0e33c4645fc8d23201ad5a6a289b4303cbb Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:49 -0700 Subject: [PATCH] acpi bridge hotadd: Link newly created pci child bus to its parent on creation When a pci child bus is created, add it to the parent's children list immediately rather than waiting till pci_bus_add_devices(). For hot-plug bridges/devices, pci_bus_add_devices() may be called much later, after they have been properly configured. In the meantime, this allows us to use the normal pci bus search functions for the hot-plug bridges/buses. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/bus.c | 11 +++++++---- drivers/pci/probe.c | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index dbd33605cc1..fedae89d8f7 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -121,10 +121,13 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) * If there is an unattached subordinate bus, attach * it and then scan for unattached PCI devices. */ - if (dev->subordinate && list_empty(&dev->subordinate->node)) { - spin_lock(&pci_bus_lock); - list_add_tail(&dev->subordinate->node, &dev->bus->children); - spin_unlock(&pci_bus_lock); + if (dev->subordinate) { + if (list_empty(&dev->subordinate->node)) { + spin_lock(&pci_bus_lock); + list_add_tail(&dev->subordinate->node, + &dev->bus->children); + spin_unlock(&pci_bus_lock); + } pci_bus_add_devices(dev->subordinate); sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge"); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 7d171f83257..6a0a82f0508 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -450,7 +450,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max return max; } - child = pci_alloc_child_bus(bus, dev, busnr); + child = pci_add_new_bus(bus, dev, busnr); if (!child) return max; child->primary = buses & 0xFF; @@ -477,7 +477,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max * This can happen when a bridge is hot-plugged */ if (pci_find_bus(pci_domain_nr(bus), max+1)) return max; - child = pci_alloc_child_bus(bus, dev, ++max); + child = pci_add_new_bus(bus, dev, ++max); buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) -- cgit v1.2.3 From 091ca9f06382e46d77213c35a97f7d0be9e350d2 Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:49 -0700 Subject: [PATCH] acpi bridge hotadd: Make the PCI remove routines safe for failed hot-plug When a root bridge hierarchy is hot-plugged, resource requirements for the new devices may be greater than what the root bridge is decoding. In this case, we want to remove devices that did not get needed resources. These devices have been scanned into bus specific lists but not yet added to the global device list. Make sure the pci remove functions can handle this case. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/remove.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 96f077f9a65..27a294b6965 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -18,17 +18,21 @@ static void pci_free_resources(struct pci_dev *dev) static void pci_destroy_dev(struct pci_dev *dev) { - pci_proc_detach_device(dev); - pci_remove_sysfs_dev_files(dev); - device_unregister(&dev->dev); + if (!list_empty(&dev->global_list)) { + pci_proc_detach_device(dev); + pci_remove_sysfs_dev_files(dev); + device_unregister(&dev->dev); + spin_lock(&pci_bus_lock); + list_del(&dev->global_list); + dev->global_list.next = dev->global_list.prev = NULL; + spin_unlock(&pci_bus_lock); + } /* Remove the device from the device lists, and prevent any further * list accesses from this device */ spin_lock(&pci_bus_lock); list_del(&dev->bus_list); - list_del(&dev->global_list); dev->bus_list.next = dev->bus_list.prev = NULL; - dev->global_list.next = dev->global_list.prev = NULL; spin_unlock(&pci_bus_lock); pci_free_resources(dev); -- cgit v1.2.3 From 542df5de56a23bf2d94b75e2b304ab0e5a5508a8 Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:50 -0700 Subject: [PATCH] acpi bridge hotadd: Remove hot-plugged devices that could not be allocated resources When hot-plugging an I/O hierarchy that contains many bridges and leaf devices, it's possible that there are not enough resources to start all the device present. If we fail to assign a resource, clear the corresponding value in the pci_dev structure, so other code can take corrective action. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/setup-bus.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 1ba84be0b4c..6b628de948a 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -72,7 +72,10 @@ pbus_assign_resources_sorted(struct pci_bus *bus) for (list = head.next; list;) { res = list->res; idx = res - &list->dev->resource[0]; - pci_assign_resource(list->dev, idx); + if (pci_assign_resource(list->dev, idx)) { + res->start = 0; + res->flags = 0; + } tmp = list; list = list->next; kfree(tmp); -- cgit v1.2.3 From 3fb02738b0fd36f47710a2bf207129efd2f5daa2 Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:52 -0700 Subject: [PATCH] acpi bridge hotadd: Allow ACPI .add and .start operations to be done independently Create new interfaces to recursively add an acpi namespace object to the acpi device list, and recursively start the namespace object. This is needed for ACPI based hotplug of a root bridge hierarchy where the add operation must be performed first and the start operation must be performed separately after the hot-plugged devices have been properly configured. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/container.c | 2 +- drivers/acpi/processor_core.c | 2 +- drivers/acpi/scan.c | 126 +++++++++++++++++++++++++++++++++--------- 3 files changed, 103 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 5a0adbf8bc0..97013ddfa20 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -153,7 +153,7 @@ container_device_add(struct acpi_device **device, acpi_handle handle) return_VALUE(-ENODEV); } - result = acpi_bus_scan(*device); + result = acpi_bus_start(*device); return_VALUE(result); } diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index f4778747e88..76156ac91bd 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -723,7 +723,7 @@ int acpi_processor_device_add( return_VALUE(-ENODEV); } - acpi_bus_scan(*device); + acpi_bus_start(*device); pr = acpi_driver_data(*device); if (!pr) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e8588559328..337d49b5564 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -553,20 +553,29 @@ acpi_bus_driver_init ( * upon possible configuration and currently allocated resources. */ + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); + return_VALUE(0); +} + +int +acpi_start_single_object ( + struct acpi_device *device) +{ + int result = 0; + struct acpi_driver *driver; + + ACPI_FUNCTION_TRACE("acpi_start_single_object"); + + if (!(driver = device->driver)) + return_VALUE(0); + if (driver->ops.start) { result = driver->ops.start(device); if (result && driver->ops.remove) driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); - return_VALUE(result); } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); - - if (driver->ops.scan) { - driver->ops.scan(device); - } - - return_VALUE(0); + return_VALUE(result); } static int acpi_driver_attach(struct acpi_driver * drv) @@ -586,6 +595,7 @@ static int acpi_driver_attach(struct acpi_driver * drv) if (!acpi_bus_match(dev, drv)) { if (!acpi_bus_driver_init(dev, drv)) { + acpi_start_single_object(dev); atomic_inc(&drv->references); count++; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", @@ -1009,8 +1019,8 @@ acpi_bus_remove ( } -int -acpi_bus_add ( +static int +acpi_add_single_object ( struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, @@ -1019,7 +1029,7 @@ acpi_bus_add ( int result = 0; struct acpi_device *device = NULL; - ACPI_FUNCTION_TRACE("acpi_bus_add"); + ACPI_FUNCTION_TRACE("acpi_add_single_object"); if (!child) return_VALUE(-EINVAL); @@ -1140,7 +1150,7 @@ acpi_bus_add ( * * TBD: Assumes LDM provides driver hot-plug capability. */ - acpi_bus_find_driver(device); + result = acpi_bus_find_driver(device); end: if (!result) @@ -1153,10 +1163,10 @@ end: return_VALUE(result); } -EXPORT_SYMBOL(acpi_bus_add); -int acpi_bus_scan (struct acpi_device *start) +static int acpi_bus_scan (struct acpi_device *start, + struct acpi_bus_ops *ops) { acpi_status status = AE_OK; struct acpi_device *parent = NULL; @@ -1229,9 +1239,20 @@ int acpi_bus_scan (struct acpi_device *start) continue; } - status = acpi_bus_add(&child, parent, chandle, type); - if (ACPI_FAILURE(status)) - continue; + if (ops->acpi_op_add) + status = acpi_add_single_object(&child, parent, + chandle, type); + else + status = acpi_bus_get_device(chandle, &child); + + if (ACPI_FAILURE(status)) + continue; + + if (ops->acpi_op_start) { + status = acpi_start_single_object(child); + if (ACPI_FAILURE(status)) + continue; + } /* * If the device is present, enabled, and functioning then @@ -1257,8 +1278,50 @@ int acpi_bus_scan (struct acpi_device *start) return_VALUE(0); } -EXPORT_SYMBOL(acpi_bus_scan); +int +acpi_bus_add ( + struct acpi_device **child, + struct acpi_device *parent, + acpi_handle handle, + int type) +{ + int result; + struct acpi_bus_ops ops; + + ACPI_FUNCTION_TRACE("acpi_bus_add"); + + result = acpi_add_single_object(child, parent, handle, type); + if (!result) { + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + result = acpi_bus_scan(*child, &ops); + } + return_VALUE(result); +} +EXPORT_SYMBOL(acpi_bus_add); + +int +acpi_bus_start ( + struct acpi_device *device) +{ + int result; + struct acpi_bus_ops ops; + + ACPI_FUNCTION_TRACE("acpi_bus_start"); + + if (!device) + return_VALUE(-EINVAL); + + result = acpi_start_single_object(device); + if (!result) { + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_start = 1; + result = acpi_bus_scan(device, &ops); + } + return_VALUE(result); +} +EXPORT_SYMBOL(acpi_bus_start); static int acpi_bus_trim(struct acpi_device *start, @@ -1331,13 +1394,19 @@ acpi_bus_scan_fixed ( /* * Enumerate all fixed-feature devices. */ - if (acpi_fadt.pwr_button == 0) - result = acpi_bus_add(&device, acpi_root, + if (acpi_fadt.pwr_button == 0) { + result = acpi_add_single_object(&device, acpi_root, NULL, ACPI_BUS_TYPE_POWER_BUTTON); + if (!result) + result = acpi_start_single_object(device); + } - if (acpi_fadt.sleep_button == 0) - result = acpi_bus_add(&device, acpi_root, + if (acpi_fadt.sleep_button == 0) { + result = acpi_add_single_object(&device, acpi_root, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON); + if (!result) + result = acpi_start_single_object(device); + } return_VALUE(result); } @@ -1346,6 +1415,7 @@ acpi_bus_scan_fixed ( static int __init acpi_scan_init(void) { int result; + struct acpi_bus_ops ops; ACPI_FUNCTION_TRACE("acpi_scan_init"); @@ -1357,17 +1427,23 @@ static int __init acpi_scan_init(void) /* * Create the root device in the bus's device tree */ - result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, + result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SYSTEM); if (result) goto Done; + result = acpi_start_single_object(acpi_root); + /* * Enumerate devices in the ACPI namespace. */ result = acpi_bus_scan_fixed(acpi_root); - if (!result) - result = acpi_bus_scan(acpi_root); + if (!result) { + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + ops.acpi_op_start = 1; + result = acpi_bus_scan(acpi_root, &ops); + } if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); -- cgit v1.2.3 From 4ce448e5fae62689b06027b46f470b944e5c2193 Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:53 -0700 Subject: [PATCH] acpi bridge hotadd: Export the interface to get PCI id for an ACPI handle Export an acpi interface to get PCI domain/bus/devfn information from the corresponding namespace handle. Used by acpiphp code to transpate the device handle of the hot-plugged root bridge to the corresponding pci location information. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/pci_bind.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 7753df1f9fb..5148f3c10b5 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -61,15 +61,14 @@ acpi_pci_data_handler ( /** - * acpi_os_get_pci_id + * acpi_get_pci_id * ------------------ * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem) * to resolve PCI information for ACPI-PCI devices defined in the namespace. * This typically occurs when resolving PCI operation region information. */ -#ifdef ACPI_FUTURE_USAGE acpi_status -acpi_os_get_pci_id ( +acpi_get_pci_id ( acpi_handle handle, struct acpi_pci_id *id) { @@ -78,7 +77,7 @@ acpi_os_get_pci_id ( struct acpi_device *device = NULL; struct acpi_pci_data *data = NULL; - ACPI_FUNCTION_TRACE("acpi_os_get_pci_id"); + ACPI_FUNCTION_TRACE("acpi_get_pci_id"); if (!id) return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -92,7 +91,7 @@ acpi_os_get_pci_id ( } status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data); - if (ACPI_FAILURE(status) || !data || !data->dev) { + if (ACPI_FAILURE(status) || !data) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid ACPI-PCI context for device %s\n", acpi_device_bid(device))); @@ -115,7 +114,7 @@ acpi_os_get_pci_id ( return_ACPI_STATUS(AE_OK); } -#endif /* ACPI_FUTURE_USAGE */ +EXPORT_SYMBOL(acpi_get_pci_id); int -- cgit v1.2.3 From 42f49a6ae5dca90cd0594475502bf1c43ff1dc07 Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:53 -0700 Subject: [PATCH] acpi hotplug: convert acpiphp to use generic resource code This patch converts acpiphp to use the generic PCI resource assignment code. It's quite large, but most of it is deleting the acpiphp_pci and acpiphp_res files. It's tested on an hp Integrity rx8620 (which won't work without this patch). Testers with other hardware welcomed. Signed-off-by: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/Makefile | 4 +- drivers/pci/hotplug/acpiphp.h | 47 +-- drivers/pci/hotplug/acpiphp_core.c | 9 +- drivers/pci/hotplug/acpiphp_glue.c | 455 +++++++----------------- drivers/pci/hotplug/acpiphp_pci.c | 449 ------------------------ drivers/pci/hotplug/acpiphp_res.c | 700 ------------------------------------- 6 files changed, 134 insertions(+), 1530 deletions(-) delete mode 100644 drivers/pci/hotplug/acpiphp_pci.c delete mode 100644 drivers/pci/hotplug/acpiphp_res.c (limited to 'drivers') diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 93c120ddbd3..3e632ff8c71 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -36,9 +36,7 @@ ibmphp-objs := ibmphp_core.o \ ibmphp_hpc.o acpiphp-objs := acpiphp_core.o \ - acpiphp_glue.o \ - acpiphp_pci.o \ - acpiphp_res.o + acpiphp_glue.o rpaphp-objs := rpaphp_core.o \ rpaphp_pci.o \ diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index d9499874c8a..293603e1b7c 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -7,6 +7,8 @@ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (C) 2002,2003 NEC Corporation + * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) + * Copyright (C) 2003-2005 Hewlett Packard * * All rights reserved. * @@ -52,7 +54,6 @@ struct acpiphp_bridge; struct acpiphp_slot; -struct pci_resource; /* * struct slot - slot information for each *physical* slot @@ -65,15 +66,6 @@ struct slot { struct acpiphp_slot *acpi_slot; }; -/* - * struct pci_resource - describes pci resource (mem, pfmem, io, bus) - */ -struct pci_resource { - struct pci_resource * next; - u64 base; - u32 length; -}; - /** * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters * @cache_line_size in DWORD @@ -101,10 +93,6 @@ struct acpiphp_bridge { int type; int nr_slots; - u8 seg; - u8 bus; - u8 sub; - u32 flags; /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */ @@ -117,12 +105,6 @@ struct acpiphp_bridge { struct hpp_param hpp; spinlock_t res_lock; - - /* available resources on this bus */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; }; @@ -163,12 +145,6 @@ struct acpiphp_func { u8 function; /* pci function# */ u32 flags; /* see below */ - - /* resources used for this function */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; }; /** @@ -243,25 +219,6 @@ extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); extern u32 acpiphp_get_address (struct acpiphp_slot *slot); -/* acpiphp_pci.c */ -extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn); -extern int acpiphp_configure_slot (struct acpiphp_slot *slot); -extern int acpiphp_configure_function (struct acpiphp_func *func); -extern void acpiphp_unconfigure_function (struct acpiphp_func *func); -extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge); -extern int acpiphp_init_func_resource (struct acpiphp_func *func); - -/* acpiphp_res.c */ -extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size); -extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size); -extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size); -extern int acpiphp_resource_sort_and_combine (struct pci_resource **head); -extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length); -extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to); -extern void acpiphp_free_resource (struct pci_resource **res); -extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */ -extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */ - /* variables */ extern int acpiphp_debug; diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 4539e61a3dc..60c4c38047a 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -7,6 +7,8 @@ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (C) 2002,2003 NEC Corporation + * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) + * Copyright (C) 2003-2005 Hewlett Packard * * All rights reserved. * @@ -53,8 +55,8 @@ int acpiphp_debug; static int num_slots; static struct acpiphp_attention_info *attention_info; -#define DRIVER_VERSION "0.4" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " +#define DRIVER_VERSION "0.5" +#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi , Matthew Wilcox " #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" MODULE_AUTHOR(DRIVER_AUTHOR); @@ -281,8 +283,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) /** * get_address - get pci address of a slot * @hotplug_slot: slot to get status - * @busdev: pointer to struct pci_busdev (seg, bus, dev) - * + * @value: pointer to struct pci_busdev (seg, bus, dev) */ static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) { diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e7f41294f81..41c3eb28b69 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -4,6 +4,8 @@ * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (C) 2002,2003 NEC Corporation + * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) + * Copyright (C) 2003-2005 Hewlett Packard * * All rights reserved. * @@ -26,6 +28,16 @@ * */ +/* + * Lifetime rules for pci_dev: + * - The one in acpiphp_func has its refcount elevated by pci_get_slot() + * when the driver is loaded or when an insertion event occurs. It loses + * a refcount when its ejected or the driver unloads. + * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot() + * when the bridge is scanned and it loses a refcount when the bridge + * is removed. + */ + #include #include @@ -178,21 +190,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) bridge->nr_slots++; - dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n", - slot->bridge->bus, slot->device, slot->sun); + dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n", + slot->sun, pci_domain_nr(bridge->pci_bus), + bridge->pci_bus->number, slot->device); } newfunc->slot = slot; list_add_tail(&newfunc->sibling, &slot->funcs); /* associate corresponding pci_dev */ - newfunc->pci_dev = pci_find_slot(bridge->bus, + newfunc->pci_dev = pci_get_slot(bridge->pci_bus, PCI_DEVFN(device, function)); if (newfunc->pci_dev) { - if (acpiphp_init_func_resource(newfunc) < 0) { - kfree(newfunc); - return AE_ERROR; - } slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); } @@ -227,62 +236,6 @@ static int detect_ejectable_slots(acpi_handle *bridge_handle) } -/* decode ACPI _CRS data and convert into our internal resource list - * TBD: _TRA, etc. - */ -static acpi_status -decode_acpi_resource(struct acpi_resource *resource, void *context) -{ - struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context; - struct acpi_resource_address64 address; - struct pci_resource *res; - - if (resource->id != ACPI_RSTYPE_ADDRESS16 && - resource->id != ACPI_RSTYPE_ADDRESS32 && - resource->id != ACPI_RSTYPE_ADDRESS64) - return AE_OK; - - acpi_resource_to_address64(resource, &address); - - if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) { - dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type, - (unsigned long long)address.min_address_range, - (unsigned long long)address.max_address_range); - res = acpiphp_make_resource(address.min_address_range, - address.address_length); - if (!res) { - err("out of memory\n"); - return AE_OK; - } - - switch (address.resource_type) { - case ACPI_MEMORY_RANGE: - if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) { - res->next = bridge->p_mem_head; - bridge->p_mem_head = res; - } else { - res->next = bridge->mem_head; - bridge->mem_head = res; - } - break; - case ACPI_IO_RANGE: - res->next = bridge->io_head; - bridge->io_head = res; - break; - case ACPI_BUS_NUMBER_RANGE: - res->next = bridge->bus_head; - bridge->bus_head = res; - break; - default: - /* invalid type */ - kfree(res); - break; - } - } - - return AE_OK; -} - /* decode ACPI 2.0 _HPP hot plug parameters */ static void decode_hpp(struct acpiphp_bridge *bridge) { @@ -346,9 +299,6 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) /* decode ACPI 2.0 _HPP (hot plug parameters) */ decode_hpp(bridge); - /* subtract all resources already allocated */ - acpiphp_detect_pci_resource(bridge); - /* register all slot objects under this bridge */ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, register_slot, bridge, NULL); @@ -364,16 +314,12 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) } list_add(&bridge->list, &bridge_list); - - dbg("Bridge resource:\n"); - acpiphp_dump_resource(bridge); } /* allocate and initialize host bridge data structure */ -static void add_host_bridge(acpi_handle *handle, int seg, int bus) +static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) { - acpi_status status; struct acpiphp_bridge *bridge; bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); @@ -384,52 +330,19 @@ static void add_host_bridge(acpi_handle *handle, int seg, int bus) bridge->type = BRIDGE_TYPE_HOST; bridge->handle = handle; - bridge->seg = seg; - bridge->bus = bus; - bridge->pci_bus = pci_find_bus(seg, bus); + bridge->pci_bus = pci_bus; spin_lock_init(&bridge->res_lock); - /* to be overridden when we decode _CRS */ - bridge->sub = bridge->bus; - - /* decode resources */ - - status = acpi_walk_resources(handle, METHOD_NAME__CRS, - decode_acpi_resource, bridge); - - if (ACPI_FAILURE(status)) { - err("failed to decode bridge resources\n"); - kfree(bridge); - return; - } - - acpiphp_resource_sort_and_combine(&bridge->io_head); - acpiphp_resource_sort_and_combine(&bridge->mem_head); - acpiphp_resource_sort_and_combine(&bridge->p_mem_head); - acpiphp_resource_sort_and_combine(&bridge->bus_head); - - dbg("ACPI _CRS resource:\n"); - acpiphp_dump_resource(bridge); - - if (bridge->bus_head) { - bridge->bus = bridge->bus_head->base; - bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1; - } - init_bridge_misc(bridge); } /* allocate and initialize PCI-to-PCI bridge data structure */ -static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int fn) +static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) { struct acpiphp_bridge *bridge; - u8 tmp8; - u16 tmp16; - u64 base64, limit64; - u32 base, limit, base32u, limit32u; bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); if (bridge == NULL) { @@ -441,133 +354,22 @@ static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int f bridge->type = BRIDGE_TYPE_P2P; bridge->handle = handle; - bridge->seg = seg; - bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn)); - if (!bridge->pci_dev) { - err("Can't get pci_dev\n"); - kfree(bridge); - return; - } - - bridge->pci_bus = bridge->pci_dev->subordinate; + bridge->pci_dev = pci_dev_get(pci_dev); + bridge->pci_bus = pci_dev->subordinate; if (!bridge->pci_bus) { err("This is not a PCI-to-PCI bridge!\n"); - kfree(bridge); - return; + goto err; } spin_lock_init(&bridge->res_lock); - bridge->bus = bridge->pci_bus->number; - bridge->sub = bridge->pci_bus->subordinate; - - /* - * decode resources under this P2P bridge - */ - - /* I/O resources */ - pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8); - base = tmp8; - pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8); - limit = tmp8; - - switch (base & PCI_IO_RANGE_TYPE_MASK) { - case PCI_IO_RANGE_TYPE_16: - base = (base << 8) & 0xf000; - limit = ((limit << 8) & 0xf000) + 0xfff; - bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->io_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("16bit I/O range: %04x-%04x\n", - (u32)bridge->io_head->base, - (u32)(bridge->io_head->base + bridge->io_head->length - 1)); - break; - case PCI_IO_RANGE_TYPE_32: - pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16); - base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000); - pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16); - limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff; - bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->io_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit I/O range: %08x-%08x\n", - (u32)bridge->io_head->base, - (u32)(bridge->io_head->base + bridge->io_head->length - 1)); - break; - case 0x0f: - dbg("I/O space unsupported\n"); - break; - default: - warn("Unknown I/O range type\n"); - } - - /* Memory resources (mandatory for P2P bridge) */ - pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16); - base = (tmp16 & 0xfff0) << 16; - pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16); - limit = ((tmp16 & 0xfff0) << 16) | 0xfffff; - bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit Memory range: %08x-%08x\n", - (u32)bridge->mem_head->base, - (u32)(bridge->mem_head->base + bridge->mem_head->length-1)); - - /* Prefetchable Memory resources (optional) */ - pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16); - base = tmp16; - pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16); - limit = tmp16; - - switch (base & PCI_MEMORY_RANGE_TYPE_MASK) { - case PCI_PREF_RANGE_TYPE_32: - base = (base & 0xfff0) << 16; - limit = ((limit & 0xfff0) << 16) | 0xfffff; - bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->p_mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit Prefetchable memory range: %08x-%08x\n", - (u32)bridge->p_mem_head->base, - (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1)); - break; - case PCI_PREF_RANGE_TYPE_64: - pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u); - pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u); - base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16); - limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff; - - bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1); - if (!bridge->p_mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n", - (u32)(bridge->p_mem_head->base >> 32), - (u32)(bridge->p_mem_head->base & 0xffffffff), - (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32), - (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff)); - break; - case 0x0f: - break; - default: - warn("Unknown prefetchale memory type\n"); - } - init_bridge_misc(bridge); + return; + err: + pci_dev_put(pci_dev); + kfree(bridge); + return; } @@ -577,14 +379,10 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; acpi_handle dummy_handle; - unsigned long *segbus = context; unsigned long tmp; - int seg, bus, device, function; + int device, function; struct pci_dev *dev; - - /* get PCI address */ - seg = (*segbus >> 8) & 0xff; - bus = *segbus & 0xff; + struct pci_bus *pci_bus = context; status = acpi_get_handle(handle, "_ADR", &dummy_handle); if (ACPI_FAILURE(status)) @@ -599,20 +397,19 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) device = (tmp >> 16) & 0xffff; function = tmp & 0xffff; - dev = pci_find_slot(bus, PCI_DEVFN(device, function)); - - if (!dev) - return AE_OK; + dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function)); - if (!dev->subordinate) - return AE_OK; + if (!dev || !dev->subordinate) + goto out; /* check if this bridge has ejectable slots */ if (detect_ejectable_slots(handle) > 0) { dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); - add_p2p_bridge(handle, seg, bus, device, function); + add_p2p_bridge(handle, dev); } + out: + pci_dev_put(dev); return AE_OK; } @@ -624,6 +421,7 @@ static int add_bridge(acpi_handle handle) unsigned long tmp; int seg, bus; acpi_handle dummy_handle; + struct pci_bus *pci_bus; /* if the bridge doesn't have _STA, we assume it is always there */ status = acpi_get_handle(handle, "_STA", &dummy_handle); @@ -653,18 +451,22 @@ static int add_bridge(acpi_handle handle) bus = 0; } + pci_bus = pci_find_bus(seg, bus); + if (!pci_bus) { + err("Can't find bus %04x:%02x\n", seg, bus); + return 0; + } + /* check if this bridge has ejectable slots */ if (detect_ejectable_slots(handle) > 0) { dbg("found PCI host-bus bridge with hot-pluggable slots\n"); - add_host_bridge(handle, seg, bus); + add_host_bridge(handle, pci_bus); return 0; } - tmp = seg << 8 | bus; - /* search P2P bridges under this host bridge */ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - find_p2p_bridge, &tmp, NULL); + find_p2p_bridge, pci_bus, NULL); if (ACPI_FAILURE(status)) warn("find_p2p_bridge faied (error code = 0x%x)\n",status); @@ -672,10 +474,59 @@ static int add_bridge(acpi_handle handle) return 0; } +static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) +{ + struct list_head *head; + list_for_each(head, &bridge_list) { + struct acpiphp_bridge *bridge = list_entry(head, + struct acpiphp_bridge, list); + if (bridge->handle == handle) + return bridge; + } + + return NULL; +} static void remove_bridge(acpi_handle handle) { - /* No-op for now .. */ + struct list_head *list, *tmp; + struct acpiphp_bridge *bridge; + struct acpiphp_slot *slot; + acpi_status status; + + bridge = acpiphp_handle_to_bridge(handle); + if (!bridge) { + err("Could not find bridge for handle %p\n", handle); + return; + } + + status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + + slot = bridge->slots; + while (slot) { + struct acpiphp_slot *next = slot->next; + list_for_each_safe (list, tmp, &slot->funcs) { + struct acpiphp_func *func; + func = list_entry(list, struct acpiphp_func, sibling); + status = acpi_remove_notify_handler(func->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + pci_dev_put(func->pci_dev); + list_del(list); + kfree(func); + } + kfree(slot); + slot = next; + } + + pci_dev_put(bridge->pci_dev); + list_del(&bridge->list); + kfree(bridge); } @@ -782,70 +633,56 @@ static int power_off_slot(struct acpiphp_slot *slot) */ static int enable_device(struct acpiphp_slot *slot) { - u8 bus; struct pci_dev *dev; - struct pci_bus *child; + struct pci_bus *bus = slot->bridge->pci_bus; struct list_head *l; struct acpiphp_func *func; int retval = 0; - int num; + int num, max, pass; if (slot->flags & SLOT_ENABLED) goto err_exit; /* sanity check: dev should be NULL when hot-plugged in */ - dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); + dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); if (dev) { /* This case shouldn't happen */ err("pci_dev structure already exists.\n"); + pci_dev_put(dev); retval = -1; goto err_exit; } - /* allocate resources to device */ - retval = acpiphp_configure_slot(slot); - if (retval) - goto err_exit; - - /* returned `dev' is the *first function* only! */ - num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0)); - if (num) - pci_bus_add_devices(slot->bridge->pci_bus); - dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); - - if (!dev) { + num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); + if (num == 0) { err("No new device found\n"); retval = -1; goto err_exit; } - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus); - child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus); - pci_do_scan_bus(child); + max = bus->secondary; + for (pass = 0; pass < 2; pass++) { + list_for_each_entry(dev, &bus->devices, bus_list) { + if (PCI_SLOT(dev->devfn) != slot->device) + continue; + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + max = pci_scan_bridge(bus, dev, max, pass); + } } + pci_bus_assign_resources(bus); + pci_bus_add_devices(bus); + /* associate pci_dev to our representation */ list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - - func->pci_dev = pci_find_slot(slot->bridge->bus, - PCI_DEVFN(slot->device, + func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, func->function)); - if (!func->pci_dev) - continue; - - /* configure device */ - retval = acpiphp_configure_function(func); - if (retval) - goto err_exit; } slot->flags |= SLOT_ENABLED; - dbg("Available resources:\n"); - acpiphp_dump_resource(slot->bridge); - err_exit: return retval; } @@ -866,9 +703,12 @@ static int disable_device(struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); + if (!func->pci_dev) + continue; - if (func->pci_dev) - acpiphp_unconfigure_function(func); + pci_remove_bus_device(func->pci_dev); + pci_dev_put(func->pci_dev); + func->pci_dev = NULL; } slot->flags &= (~SLOT_ENABLED); @@ -1116,46 +956,6 @@ int __init acpiphp_glue_init(void) */ void __exit acpiphp_glue_exit(void) { - struct list_head *l1, *l2, *n1, *n2; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot, *next; - struct acpiphp_func *func; - acpi_status status; - - list_for_each_safe (l1, n1, &bridge_list) { - bridge = (struct acpiphp_bridge *)l1; - slot = bridge->slots; - while (slot) { - next = slot->next; - list_for_each_safe (l2, n2, &slot->funcs) { - func = list_entry(l2, struct acpiphp_func, sibling); - acpiphp_free_resource(&func->io_head); - acpiphp_free_resource(&func->mem_head); - acpiphp_free_resource(&func->p_mem_head); - acpiphp_free_resource(&func->bus_head); - status = acpi_remove_notify_handler(func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - kfree(func); - } - kfree(slot); - slot = next; - } - status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - - acpiphp_free_resource(&bridge->io_head); - acpiphp_free_resource(&bridge->mem_head); - acpiphp_free_resource(&bridge->p_mem_head); - acpiphp_free_resource(&bridge->bus_head); - - kfree(bridge); - } - acpi_pci_unregister_driver(&acpi_pci_hp_driver); } @@ -1173,11 +973,14 @@ int __init acpiphp_get_num_slots(void) list_for_each (node, &bridge_list) { bridge = (struct acpiphp_bridge *)node; - dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots); + dbg("Bus %04x:%02x has %d slot%s\n", + pci_domain_nr(bridge->pci_bus), + bridge->pci_bus->number, bridge->nr_slots, + bridge->nr_slots == 1 ? "" : "s"); num_slots += bridge->nr_slots; } - dbg("Total %dslots\n", num_slots); + dbg("Total %d slots\n", num_slots); return num_slots; } @@ -1274,13 +1077,6 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) if (retval) goto err_exit; - acpiphp_resource_sort_and_combine(&slot->bridge->io_head); - acpiphp_resource_sort_and_combine(&slot->bridge->mem_head); - acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head); - acpiphp_resource_sort_and_combine(&slot->bridge->bus_head); - dbg("Available resources:\n"); - acpiphp_dump_resource(slot->bridge); - err_exit: up(&slot->crit_sect); return retval; @@ -1335,9 +1131,10 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) u32 acpiphp_get_address(struct acpiphp_slot *slot) { u32 address; + struct pci_bus *pci_bus = slot->bridge->pci_bus; - address = ((slot->bridge->seg) << 16) | - ((slot->bridge->bus) << 8) | + address = (pci_domain_nr(pci_bus) << 16) | + (pci_bus->number << 8) | slot->device; return address; diff --git a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c deleted file mode 100644 index 54d97c9d1df..00000000000 --- a/drivers/pci/hotplug/acpiphp_pci.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * ACPI PCI HotPlug PCI configuration space management - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001,2002 IBM Corp. - * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) - * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (C) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include - -#include -#include -#include -#include "../pci.h" -#include "pci_hotplug.h" -#include "acpiphp.h" - -#define MY_NAME "acpiphp_pci" - - -/* allocate mem/pmem/io resource to a new function */ -static int init_config_space (struct acpiphp_func *func) -{ - u32 bar, len; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct acpiphp_bridge *bridge; - struct pci_resource *res; - struct pci_bus *pbus; - int bus, device, function; - unsigned int devfn; - u16 tmp; - - bridge = func->slot->bridge; - pbus = bridge->pci_bus; - bus = bridge->bus; - device = func->slot->device; - function = func->function; - devfn = PCI_DEVFN(device, function); - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_bus_write_config_dword(pbus, devfn, - address[count], 0xFFFFFFFF); - pci_bus_read_config_dword(pbus, devfn, address[count], &bar); - - if (!bar) /* This BAR is not implemented */ - continue; - - dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar); - - if (bar & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - - len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); - len = len & ~(len - 1); - - dbg("len in IO %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_io_resource(&bridge->io_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested io for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - res->next = func->io_head; - func->io_head = res; - - } else { - /* This is Memory */ - if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len = bar & 0xFFFFFFF0; - len = ~len + 1; - - dbg("len in PFMEM %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource(&bridge->p_mem_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - - if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("inside the pfmem 64 case, count %d\n", count); - count += 1; - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)(res->base >> 32)); - } - - res->next = func->p_mem_head; - func->p_mem_head = res; - - } else { - /* regular memory */ - - len = bar & 0xFFFFFFF0; - len = ~len + 1; - - dbg("len in MEM %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource(&bridge->mem_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - - if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("inside mem 64 case, reg. mem, count %d\n", count); - count += 1; - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)(res->base >> 32)); - } - - res->next = func->mem_head; - func->mem_head = res; - - } - } - } - - /* disable expansion rom */ - pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000); - - /* set PCI parameters from _HPP */ - pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE, - bridge->hpp.cache_line_size); - pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER, - bridge->hpp.latency_timer); - - pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp); - if (bridge->hpp.enable_SERR) - tmp |= PCI_COMMAND_SERR; - if (bridge->hpp.enable_PERR) - tmp |= PCI_COMMAND_PARITY; - pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp); - - return 0; -} - -/* detect_used_resource - subtract resource under dev from bridge */ -static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev) -{ - int count; - - dbg("Device %s\n", pci_name(dev)); - - for (count = 0; count < DEVICE_COUNT_RESOURCE; count++) { - struct pci_resource *res; - struct pci_resource **head; - unsigned long base = dev->resource[count].start; - unsigned long len = dev->resource[count].end - base + 1; - unsigned long flags = dev->resource[count].flags; - - if (!flags) - continue; - - dbg("BAR[%d] 0x%lx - 0x%lx (0x%lx)\n", count, base, - base + len - 1, flags); - - if (flags & IORESOURCE_IO) { - head = &bridge->io_head; - } else if (flags & IORESOURCE_PREFETCH) { - head = &bridge->p_mem_head; - } else { - head = &bridge->mem_head; - } - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); - } - - return 0; -} - - -/** - * acpiphp_detect_pci_resource - detect resources under bridge - * @bridge: detect all resources already used under this bridge - * - * collect all resources already allocated for all devices under a bridge. - */ -int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge) -{ - struct list_head *l; - struct pci_dev *dev; - - list_for_each (l, &bridge->pci_bus->devices) { - dev = pci_dev_b(l); - detect_used_resource(bridge, dev); - } - - return 0; -} - - -/** - * acpiphp_init_slot_resource - gather resource usage information of a slot - * @slot: ACPI slot object to be checked, should have valid pci_dev member - * - * TBD: PCI-to-PCI bridge case - * use pci_dev->resource[] - */ -int acpiphp_init_func_resource (struct acpiphp_func *func) -{ - u64 base; - u32 bar, len; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct pci_resource *res; - struct pci_dev *dev; - - dev = func->pci_dev; - dbg("Hot-pluggable device %s\n", pci_name(dev)); - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_read_config_dword(dev, address[count], &bar); - - if (!bar) /* This BAR is not implemented */ - continue; - - pci_write_config_dword(dev, address[count], 0xFFFFFFFF); - pci_read_config_dword(dev, address[count], &len); - - if (len & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - base = bar & 0xFFFFFFFC; - len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); - len = len & ~(len - 1); - - dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); - - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->io_head; - func->io_head = res; - - } else { - /* This is Memory */ - base = bar & 0xFFFFFFF0; - if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("prefetch mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->p_mem_head; - func->p_mem_head = res; - - } else { - /* regular memory */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->mem_head; - func->mem_head = res; - - } - } - - pci_write_config_dword(dev, address[count], bar); - } -#if 1 - acpiphp_dump_func_resource(func); -#endif - - return 0; - - no_memory: - err("out of memory\n"); - acpiphp_free_resource(&func->io_head); - acpiphp_free_resource(&func->mem_head); - acpiphp_free_resource(&func->p_mem_head); - - return -1; -} - - -/** - * acpiphp_configure_slot - allocate PCI resources - * @slot: slot to be configured - * - * initializes a PCI functions on a device inserted - * into the slot - * - */ -int acpiphp_configure_slot (struct acpiphp_slot *slot) -{ - struct acpiphp_func *func; - struct list_head *l; - u8 hdr; - u32 dvid; - int retval = 0; - int is_multi = 0; - - pci_bus_read_config_byte(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, 0), - PCI_HEADER_TYPE, &hdr); - - if (hdr & 0x80) - is_multi = 1; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - if (is_multi || func->function == 0) { - pci_bus_read_config_dword(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, - func->function), - PCI_VENDOR_ID, &dvid); - if (dvid != 0xffffffff) { - retval = init_config_space(func); - if (retval) - break; - } - } - } - - return retval; -} - -/** - * acpiphp_configure_function - configure PCI function - * @func: function to be configured - * - * initializes a PCI functions on a device inserted - * into the slot - * - */ -int acpiphp_configure_function (struct acpiphp_func *func) -{ - /* all handled by the pci core now */ - return 0; -} - -/** - * acpiphp_unconfigure_function - unconfigure PCI function - * @func: function to be unconfigured - * - */ -void acpiphp_unconfigure_function (struct acpiphp_func *func) -{ - struct acpiphp_bridge *bridge; - - /* if pci_dev is NULL, ignore it */ - if (!func->pci_dev) - return; - - pci_remove_bus_device(func->pci_dev); - - /* free all resources */ - bridge = func->slot->bridge; - - spin_lock(&bridge->res_lock); - acpiphp_move_resource(&func->io_head, &bridge->io_head); - acpiphp_move_resource(&func->mem_head, &bridge->mem_head); - acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head); - acpiphp_move_resource(&func->bus_head, &bridge->bus_head); - spin_unlock(&bridge->res_lock); -} diff --git a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c deleted file mode 100644 index f54b1fa7b75..00000000000 --- a/drivers/pci/hotplug/acpiphp_res.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - * ACPI PCI HotPlug Utility functions - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) - * Copyright (C) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to , - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "pci_hotplug.h" -#include "acpiphp.h" - -#define MY_NAME "acpiphp_res" - - -/* - * sort_by_size - sort nodes by their length, smallest first - */ -static int sort_by_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return 1; - - if (!((*head)->next)) - return 0; - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length > (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length > current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return 0; -} - -#if 0 -/* - * sort_by_max_size - sort nodes by their length, largest first - */ -static int sort_by_max_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return 1; - - if (!((*head)->next)) - return 0; - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length < (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length < current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return 0; -} -#endif - -/** - * get_io_resource - get resource for I/O ports - * - * this function sorts the resource list by size and then - * returns the first node of "size" length that is not in the - * ISA aliasing window. If it finds a node larger than "size" - * it will split it up. - * - * size must be a power of two. - * - * difference from get_resource is handling of ISA aliasing space. - * - */ -struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_size(head)) - return NULL; - - for (node = *head; node; node = node->next) { - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - /* For IO make sure it's not in the ISA aliasing space */ - if ((node->base & 0x300L) && !(node->base & 0xfffff000)) - continue; - - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - - return node; -} - - -#if 0 -/** - * get_max_resource - get the largest resource - * - * Gets the largest node that is at least "size" big from the - * list pointed to by head. It aligns the node on top and bottom - * to "size" alignment before returning it. - */ -static struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *max; - struct pci_resource *temp; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_max_size(head)) - return NULL; - - for (max = *head;max; max = max->next) { - - /* If not big enough we could probably just bail, - instead we'll continue to the next. */ - if (max->length < size) - continue; - - if (max->base & (size - 1)) { - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (max->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((max->length - (temp_qword - max->base)) < size) - continue; - - split_node = acpiphp_make_resource(max->base, temp_qword - max->base); - - if (!split_node) - return NULL; - - max->base = temp_qword; - max->length -= split_node->length; - - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - } - - if ((max->base + max->length) & (size - 1)) { - /* this one isn't end aligned properly at the top - so we'll make a new entry and split it up */ - temp_qword = ((max->base + max->length) & ~(size - 1)); - - split_node = acpiphp_make_resource(temp_qword, - max->length + max->base - temp_qword); - - if (!split_node) - return NULL; - - max->length -= split_node->length; - - /* Put it in the list */ - split_node->next = max->next; - max->next = split_node; - } - - /* Make sure it didn't shrink too much when we aligned it */ - if (max->length < size) - continue; - - /* Now take it out of the list */ - temp = (struct pci_resource*) *head; - if (temp == max) { - *head = max->next; - } else { - while (temp && temp->next != max) { - temp = temp->next; - } - - temp->next = max->next; - } - - max->next = NULL; - return max; - } - - /* If we get here, we couldn't find one */ - return NULL; -} -#endif - -/** - * get_resource - get resource (mem, pfmem) - * - * this function sorts the resource list by size and then - * returns the first node of "size" length. If it finds a node - * larger than "size" it will split it up. - * - * size must be a power of two. - * - */ -struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_size(head)) - return NULL; - - for (node = *head; node; node = node->next) { - dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", - __FUNCTION__, size, node, (u32)node->base, node->length); - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg("%s: got one!!!\n", __FUNCTION__); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return node; -} - -/** - * get_resource_with_base - get resource with specific base address - * - * this function - * returns the first node of "size" length located at specified base address. - * If it finds a node larger than "size" it will split it up. - * - * size must be a power of two. - * - */ -struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - for (node = *head; node; node = node->next) { - dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", - (u32)base, size, node, (u32)node->base, node->length); - if (node->base > base) - continue; - - if ((node->base + node->length) < (base + size)) - continue; - - if (node->base < base) { - dbg(": split 1\n"); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = base; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } - - dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n", - (u32)base, size, node, (u32)node->base, node->length); - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg(": split 2\n"); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg(": got one!!!\n"); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return node; -} - - -/** - * acpiphp_resource_sort_and_combine - * - * Sorts all of the nodes in the list in ascending order by - * their base addresses. Also does garbage collection by - * combining adjacent nodes. - * - * returns 0 if success - */ -int acpiphp_resource_sort_and_combine (struct pci_resource **head) -{ - struct pci_resource *node1; - struct pci_resource *node2; - int out_of_order = 1; - - if (!(*head)) - return 1; - - dbg("*head->next = %p\n",(*head)->next); - - if (!(*head)->next) - return 0; /* only one item on the list, already sorted! */ - - dbg("*head->base = 0x%x\n",(u32)(*head)->base); - dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base); - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->base > (*head)->next->base)) { - node1 = *head; - (*head) = (*head)->next; - node1->next = (*head)->next; - (*head)->next = node1; - out_of_order++; - } - - node1 = (*head); - - while (node1->next && node1->next->next) { - if (node1->next->base > node1->next->next->base) { - out_of_order++; - node2 = node1->next; - node1->next = node1->next->next; - node1 = node1->next; - node2->next = node1->next; - node1->next = node2; - } else - node1 = node1->next; - } - } /* End of out_of_order loop */ - - node1 = *head; - - while (node1 && node1->next) { - if ((node1->base + node1->length) == node1->next->base) { - /* Combine */ - dbg("8..\n"); - node1->length += node1->next->length; - node2 = node1->next; - node1->next = node1->next->next; - kfree(node2); - } else - node1 = node1->next; - } - - return 0; -} - - -/** - * acpiphp_make_resource - make resource structure - * @base: base address of a resource - * @length: length of a resource - */ -struct pci_resource *acpiphp_make_resource (u64 base, u32 length) -{ - struct pci_resource *res; - - res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (res) { - memset(res, 0, sizeof(struct pci_resource)); - res->base = base; - res->length = length; - } - - return res; -} - - -/** - * acpiphp_move_resource - move linked resources from one to another - * @from: head of linked resource list - * @to: head of linked resource list - */ -void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to) -{ - struct pci_resource *tmp; - - while (*from) { - tmp = (*from)->next; - (*from)->next = *to; - *to = *from; - *from = tmp; - } - - /* *from = NULL is guaranteed */ -} - - -/** - * acpiphp_free_resource - free all linked resources - * @res: head of linked resource list - */ -void acpiphp_free_resource (struct pci_resource **res) -{ - struct pci_resource *tmp; - - while (*res) { - tmp = (*res)->next; - kfree(*res); - *res = tmp; - } - - /* *res = NULL is guaranteed */ -} - - -/* debug support functions; will go away sometime :) */ -static void dump_resource(struct pci_resource *head) -{ - struct pci_resource *p; - int cnt; - - p = head; - cnt = 0; - - while (p) { - dbg("[%02d] %08x - %08x\n", - cnt++, (u32)p->base, (u32)p->base + p->length - 1); - p = p->next; - } -} - -void acpiphp_dump_resource(struct acpiphp_bridge *bridge) -{ - dbg("I/O resource:\n"); - dump_resource(bridge->io_head); - dbg("MEM resource:\n"); - dump_resource(bridge->mem_head); - dbg("PMEM resource:\n"); - dump_resource(bridge->p_mem_head); - dbg("BUS resource:\n"); - dump_resource(bridge->bus_head); -} - -void acpiphp_dump_func_resource(struct acpiphp_func *func) -{ - dbg("I/O resource:\n"); - dump_resource(func->io_head); - dbg("MEM resource:\n"); - dump_resource(func->mem_head); - dbg("PMEM resource:\n"); - dump_resource(func->p_mem_head); - dbg("BUS resource:\n"); - dump_resource(func->bus_head); -} -- cgit v1.2.3 From 364d5094a43ff2ceff3d19e40c4199771cb6cb8f Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:54 -0700 Subject: [PATCH] acpi hotplug: clean up notify handlers on acpiphp unload A root bridge may not have directly attached hotpluggable slots under it. Instead, it may have p2p bridges with slots under it. In this case, we need to clean up the p2p bridges and slots properly too. Patch below applies on top of the original patch, and fixes this problem. Without this, acpiphp leaves behind notify handlers on module unload, and subsequent module load attempts don't work properly too. Patch was tested on an ia64 Tiger4 box. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 41c3eb28b69..2f72e50eca2 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -487,18 +487,12 @@ static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) return NULL; } -static void remove_bridge(acpi_handle handle) +static void cleanup_bridge(struct acpiphp_bridge *bridge) { struct list_head *list, *tmp; - struct acpiphp_bridge *bridge; struct acpiphp_slot *slot; acpi_status status; - - bridge = acpiphp_handle_to_bridge(handle); - if (!bridge) { - err("Could not find bridge for handle %p\n", handle); - return; - } + acpi_handle handle = bridge->handle; status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge); @@ -529,6 +523,30 @@ static void remove_bridge(acpi_handle handle) kfree(bridge); } +static acpi_status +cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + struct acpiphp_bridge *bridge; + + if (!(bridge = acpiphp_handle_to_bridge(handle))) + return AE_OK; + cleanup_bridge(bridge); + return AE_OK; +} + +static void remove_bridge(acpi_handle handle) +{ + struct acpiphp_bridge *bridge; + + bridge = acpiphp_handle_to_bridge(handle); + if (bridge) { + cleanup_bridge(bridge); + } else { + /* clean-up p2p bridges under this host bridge */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + (u32)1, cleanup_p2p_bridge, NULL, NULL); + } +} static int power_on_slot(struct acpiphp_slot *slot) { -- cgit v1.2.3 From 2f523b15901f654a9448bbd47ebe1e783ec3195b Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:55 -0700 Subject: [PATCH] acpi hotplug: fix slot power-down problem with acpiphp Earlier I reported that Matthew's acpiphp rewrite had problem in powering down slot on my i386 system. The following patch is needed to get the acpiphp rewrite properly powering down the slot. Signed-off-by: Dely Sy Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 2f72e50eca2..1501eb26af3 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -600,7 +600,7 @@ static int power_off_slot(struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->pci_dev && (func->flags & FUNC_HAS_PS3)) { + if (func->flags & FUNC_HAS_PS3) { status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS3 failed\n", __FUNCTION__); @@ -615,7 +615,7 @@ static int power_off_slot(struct acpiphp_slot *slot) func = list_entry(l, struct acpiphp_func, sibling); /* We don't want to call _EJ0 on non-existing functions. */ - if (func->pci_dev && (func->flags & FUNC_HAS_EJ0)) { + if (func->flags & FUNC_HAS_EJ0) { /* _EJ0 method take one argument */ arg_list.count = 1; arg_list.pointer = &arg; -- cgit v1.2.3 From 8e7561cfbdf00fb1cee694cef0e825d0548aedbc Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:56 -0700 Subject: [PATCH] acpi hotplug: aCPI based root bridge hot-add acpiphp changes to support acpi based root bridge hot-add. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 211 +++++++++++++++++++++++++++++++++++-- 1 file changed, 202 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 1501eb26af3..a6270cc218f 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -6,6 +6,8 @@ * Copyright (C) 2002,2003 NEC Corporation * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) * Copyright (C) 2003-2005 Hewlett Packard + * Copyright (C) 2005 Rajesh Shah (rajesh.shah@intel.com) + * Copyright (C) 2005 Intel Corporation * * All rights reserved. * @@ -304,13 +306,15 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) register_slot, bridge, NULL); /* install notify handler */ - status = acpi_install_notify_handler(bridge->handle, + if (bridge->type != BRIDGE_TYPE_HOST) { + status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge, bridge); - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); + if (ACPI_FAILURE(status)) { + err("failed to register interrupt notify handler\n"); + } } list_add(&bridge->list, &bridge_list); @@ -820,6 +824,143 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) return retval; } +static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) +{ + u16 pci_cmd, pci_bctl; + struct pci_dev *cdev; + + /* Program hpp values for this device */ + if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || + (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) + return; + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, + bridge->hpp.cache_line_size); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, + bridge->hpp.latency_timer); + pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); + if (bridge->hpp.enable_SERR) + pci_cmd |= PCI_COMMAND_SERR; + else + pci_cmd &= ~PCI_COMMAND_SERR; + if (bridge->hpp.enable_PERR) + pci_cmd |= PCI_COMMAND_PARITY; + else + pci_cmd &= ~PCI_COMMAND_PARITY; + pci_write_config_word(dev, PCI_COMMAND, pci_cmd); + + /* Program bridge control value and child devices */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, + bridge->hpp.latency_timer); + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); + if (bridge->hpp.enable_SERR) + pci_bctl |= PCI_BRIDGE_CTL_SERR; + else + pci_bctl &= ~PCI_BRIDGE_CTL_SERR; + if (bridge->hpp.enable_PERR) + pci_bctl |= PCI_BRIDGE_CTL_PARITY; + else + pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); + if (dev->subordinate) { + list_for_each_entry(cdev, &dev->subordinate->devices, + bus_list) + program_hpp(cdev, bridge); + } + } +} + +static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) +{ + struct acpiphp_bridge bridge; + struct pci_dev *dev; + + memset(&bridge, 0, sizeof(bridge)); + bridge.handle = handle; + decode_hpp(&bridge); + list_for_each_entry(dev, &bus->devices, bus_list) + program_hpp(dev, &bridge); + +} + +/* + * Remove devices for which we could not assign resources, call + * arch specific code to fix-up the bus + */ +static void acpiphp_sanitize_bus(struct pci_bus *bus) +{ + struct pci_dev *dev; + int i; + unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; + + list_for_each_entry(dev, &bus->devices, bus_list) { + for (i=0; iresource[i]; + if ((res->flags & type_mask) && !res->start && + res->end) { + /* Could not assign a required resources + * for this device, remove it */ + pci_remove_bus_device(dev); + break; + } + } + } +} + +/* Program resources in newly inserted bridge */ +static int acpiphp_configure_bridge (acpi_handle handle) +{ + struct acpi_pci_id pci_id; + struct pci_bus *bus; + + if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) { + err("cannot get PCI domain and bus number for bridge\n"); + return -EINVAL; + } + bus = pci_find_bus(pci_id.segment, pci_id.bus); + if (!bus) { + err("cannot find bus %d:%d\n", + pci_id.segment, pci_id.bus); + return -EINVAL; + } + + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + acpiphp_sanitize_bus(bus); + acpiphp_set_hpp_values(handle, bus); + pci_enable_bridges(bus); + return 0; +} + +static void handle_bridge_insertion(acpi_handle handle, u32 type) +{ + struct acpi_device *device, *pdevice; + acpi_handle phandle; + + if ((type != ACPI_NOTIFY_BUS_CHECK) && + (type != ACPI_NOTIFY_DEVICE_CHECK)) { + err("unexpected notification type %d\n", type); + return; + } + + acpi_get_parent(handle, &phandle); + if (acpi_bus_get_device(phandle, &pdevice)) { + dbg("no parent device, assuming NULL\n"); + pdevice = NULL; + } + if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { + err("cannot add bridge to acpi list\n"); + return; + } + if (!acpiphp_configure_bridge(handle) && + !acpi_bus_start(device)) + add_bridge(handle); + else + err("cannot configure and start bridge\n"); + +} + /* * ACPI event handlers */ @@ -840,8 +981,19 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; + struct acpi_device *device; - bridge = (struct acpiphp_bridge *)context; + if (acpi_bus_get_device(handle, &device)) { + /* This bridge must have just been physically inserted */ + handle_bridge_insertion(handle, type); + return; + } + + bridge = acpiphp_handle_to_bridge(handle); + if (!bridge) { + err("cannot get bridge info\n"); + return; + } acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -941,6 +1093,47 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex } } +static int is_root_bridge(acpi_handle handle) +{ + acpi_status status; + struct acpi_device_info *info; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + int i; + + status = acpi_get_object_info(handle, &buffer); + if (ACPI_SUCCESS(status)) { + info = buffer.pointer; + if ((info->valid & ACPI_VALID_HID) && + !strcmp(PCI_ROOT_HID_STRING, + info->hardware_id.value)) { + acpi_os_free(buffer.pointer); + return 1; + } + if (info->valid & ACPI_VALID_CID) { + for (i=0; i < info->compatibility_id.count; i++) { + if (!strcmp(PCI_ROOT_HID_STRING, + info->compatibility_id.id[i].value)) { + acpi_os_free(buffer.pointer); + return 1; + } + } + } + } + return 0; +} + +static acpi_status +find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + + if (is_root_bridge(handle)) { + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge, NULL); + (*count)++; + } + return AE_OK ; +} static struct acpi_pci_driver acpi_pci_hp_driver = { .add = add_bridge, @@ -953,15 +1146,15 @@ static struct acpi_pci_driver acpi_pci_hp_driver = { */ int __init acpiphp_glue_init(void) { - int num; - - if (list_empty(&pci_root_buses)) - return -1; + int num = 0; - num = acpi_pci_register_driver(&acpi_pci_hp_driver); + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_root_bridges, &num, NULL); if (num <= 0) return -1; + else + acpi_pci_register_driver(&acpi_pci_hp_driver); return 0; } -- cgit v1.2.3 From 8d50e332c8bd4f4e8cc76e8ed7326aa6f18182aa Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Thu, 28 Apr 2005 00:25:57 -0700 Subject: [PATCH] acpi hotplug: decouple slot power state changes from physical hotplug Current acpiphp code does not distinguish between the physical presence and power state of a device/slot. That is, if a device has to be disabled, it also tries to physically ejects the device. This patch decouples power state from physical presence. You can now echo to the corresponding sysfs power control file to repeatedly enable and disable a device without having to physically re-insert it. Signed-off-by: Rajesh Shah Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 69 +++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a6270cc218f..b4a92123625 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -592,8 +592,6 @@ static int power_off_slot(struct acpiphp_slot *slot) acpi_status status; struct acpiphp_func *func; struct list_head *l; - struct acpi_object_list arg_list; - union acpi_object arg; int retval = 0; @@ -615,27 +613,6 @@ static int power_off_slot(struct acpiphp_slot *slot) } } - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - /* We don't want to call _EJ0 on non-existing functions. */ - if (func->flags & FUNC_HAS_EJ0) { - /* _EJ0 method take one argument */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _EJ0 failed\n", __FUNCTION__); - retval = -1; - goto err_exit; - } else - break; - } - } - /* TBD: evaluate _STA to check if the slot is disabled */ slot->flags &= (~SLOT_POWEREDON); @@ -781,6 +758,39 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) return (unsigned int)sta; } +/** + * acpiphp_eject_slot - physically eject the slot + */ +static int acpiphp_eject_slot(struct acpiphp_slot *slot) +{ + acpi_status status; + struct acpiphp_func *func; + struct list_head *l; + struct acpi_object_list arg_list; + union acpi_object arg; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + /* We don't want to call _EJ0 on non-existing functions. */ + if ((func->flags & FUNC_HAS_EJ0)) { + /* _EJ0 method take one argument */ + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _EJ0 failed\n", __FUNCTION__); + return -1; + } else + break; + } + } + return 0; +} + /** * acpiphp_check_bridge - re-enumerate devices * @@ -804,6 +814,8 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) if (retval) { err("Error occurred in disabling\n"); goto err_exit; + } else { + acpiphp_eject_slot(slot); } disabled++; } else { @@ -1041,7 +1053,6 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont } } - /** * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) * @@ -1084,7 +1095,8 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); - acpiphp_disable_slot(func->slot); + if (!(acpiphp_disable_slot(func->slot))) + acpiphp_eject_slot(func->slot); break; default: @@ -1268,7 +1280,6 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) return retval; } - /** * acpiphp_disable_slot - power off slot */ @@ -1300,11 +1311,7 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) */ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) { - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta & ACPI_STA_ENABLED) ? 1 : 0; + return (slot->flags & SLOT_POWEREDON); } -- cgit v1.2.3 From a0d399a808916d22c1c222c6b5ca4e8edd6d91a9 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 28 Apr 2005 00:25:59 -0700 Subject: [PATCH] ACPI based I/O APIC hot-plug: acpiphp support This patch adds PCI based I/O xAPIC hot-add support to ACPIPHP driver. When PCI root bridge is hot-added, all PCI based I/O xAPICs under the root bridge are hot-added by this patch. Hot-remove support is TBD. Signed-off-by: Kenji Kaneshige Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 127 +++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b4a92123625..424e7de181a 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -552,6 +552,132 @@ static void remove_bridge(acpi_handle handle) } } +static struct pci_dev * get_apic_pci_info(acpi_handle handle) +{ + struct acpi_pci_id id; + struct pci_bus *bus; + struct pci_dev *dev; + + if (ACPI_FAILURE(acpi_get_pci_id(handle, &id))) + return NULL; + + bus = pci_find_bus(id.segment, id.bus); + if (!bus) + return NULL; + + dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function)); + if (!dev) + return NULL; + + if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) && + (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC)) + { + pci_dev_put(dev); + return NULL; + } + + return dev; +} + +static int get_gsi_base(acpi_handle handle, u32 *gsi_base) +{ + acpi_status status; + int result = -1; + unsigned long gsb; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + void *table; + + status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb); + if (ACPI_SUCCESS(status)) { + *gsi_base = (u32)gsb; + return 0; + } + + status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer); + if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer) + return -1; + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_BUFFER) + goto out; + + table = obj->buffer.pointer; + switch (((acpi_table_entry_header *)table)->type) { + case ACPI_MADT_IOSAPIC: + *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base; + result = 0; + break; + case ACPI_MADT_IOAPIC: + *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base; + result = 0; + break; + default: + break; + } + out: + acpi_os_free(buffer.pointer); + return result; +} + +static acpi_status +ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + unsigned long sta; + acpi_handle tmp; + struct pci_dev *pdev; + u32 gsi_base; + u64 phys_addr; + + /* Evaluate _STA if present */ + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) + return AE_CTRL_DEPTH; + + /* Scan only PCI bus scope */ + status = acpi_get_handle(handle, "_HID", &tmp); + if (ACPI_SUCCESS(status)) + return AE_CTRL_DEPTH; + + if (get_gsi_base(handle, &gsi_base)) + return AE_OK; + + pdev = get_apic_pci_info(handle); + if (!pdev) + return AE_OK; + + if (pci_enable_device(pdev)) { + pci_dev_put(pdev); + return AE_OK; + } + + pci_set_master(pdev); + + if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) { + pci_disable_device(pdev); + pci_dev_put(pdev); + return AE_OK; + } + + phys_addr = pci_resource_start(pdev, 0); + if (acpi_register_ioapic(handle, phys_addr, gsi_base)) { + pci_release_region(pdev, 0); + pci_disable_device(pdev); + pci_dev_put(pdev); + return AE_OK; + } + + return AE_OK; +} + +static int acpiphp_configure_ioapics(acpi_handle handle) +{ + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + ACPI_UINT32_MAX, ioapic_add, NULL, NULL); + return 0; +} + static int power_on_slot(struct acpiphp_slot *slot) { acpi_status status; @@ -942,6 +1068,7 @@ static int acpiphp_configure_bridge (acpi_handle handle) acpiphp_sanitize_bus(bus); acpiphp_set_hpp_values(handle, bus); pci_enable_bridges(bus); + acpiphp_configure_ioapics(handle); return 0; } -- cgit v1.2.3 From 2311b1f2bbd36fa5f366a7448c718b2556e0f02c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 13 May 2005 17:44:10 +1000 Subject: [PATCH] PCI: fix-pci-mmap-on-ppc-and-ppc64.patch This is an updated version of Ben's fix-pci-mmap-on-ppc-and-ppc64.patch which is in 2.6.12-rc4-mm1. It fixes the patch to work on PPC iSeries, removes some debug printks at Ben's request, and incorporates your fix-pci-mmap-on-ppc-and-ppc64-fix.patch also. Originally from Benjamin Herrenschmidt This patch was discussed at length on linux-pci and so far, the last iteration of it didn't raise any comment. It's effect is a nop on architecture that don't define the new pci_resource_to_user() callback anyway. It allows architecture like ppc who put weird things inside of PCI resource structures to convert to some different value for user visible ones. It also fixes mmap'ing of IO space on those archs. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-sysfs.c | 26 +++++++++++++++++++++----- drivers/pci/proc.c | 14 ++++++++++---- 2 files changed, 31 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index a15f94072a6..cc9d65388e6 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -60,15 +60,18 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf) char * str = buf; int i; int max = 7; + u64 start, end; if (pci_dev->subordinate) max = DEVICE_COUNT_RESOURCE; for (i = 0; i < max; i++) { - str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n", - pci_resource_start(pci_dev,i), - pci_resource_end(pci_dev,i), - pci_resource_flags(pci_dev,i)); + struct resource *res = &pci_dev->resource[i]; + pci_resource_to_user(pci_dev, i, res, &start, &end); + str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n", + (unsigned long long)start, + (unsigned long long)end, + (unsigned long long)res->flags); } return (str - buf); } @@ -313,8 +316,21 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, struct device, kobj)); struct resource *res = (struct resource *)attr->private; enum pci_mmap_state mmap_type; + u64 start, end; + int i; - vma->vm_pgoff += res->start >> PAGE_SHIFT; + for (i = 0; i < PCI_ROM_RESOURCE; i++) + if (res == &pdev->resource[i]) + break; + if (i >= PCI_ROM_RESOURCE) + return -ENODEV; + + /* pci_mmap_page_range() expects the same kind of entry as coming + * from /proc/bus/pci/ which is a "user visible" value. If this is + * different from the resource itself, arch will do necessary fixup. + */ + pci_resource_to_user(pdev, i, res, &start, &end); + vma->vm_pgoff += start >> PAGE_SHIFT; mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; return pci_mmap_page_range(pdev, vma, mmap_type, 0); diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index e68bbfb1e7c..7988fc8df3f 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -355,14 +355,20 @@ static int show_device(struct seq_file *m, void *v) dev->device, dev->irq); /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */ - for(i=0; i<7; i++) + for (i=0; i<7; i++) { + u64 start, end; + pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); seq_printf(m, LONG_FORMAT, - dev->resource[i].start | + ((unsigned long)start) | (dev->resource[i].flags & PCI_REGION_FLAG_MASK)); - for(i=0; i<7; i++) + } + for (i=0; i<7; i++) { + u64 start, end; + pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); seq_printf(m, LONG_FORMAT, dev->resource[i].start < dev->resource[i].end ? - dev->resource[i].end - dev->resource[i].start + 1 : 0); + (unsigned long)(end - start) + 1 : 0); + } seq_putc(m, '\t'); if (drv) seq_printf(m, "%s", drv->name); -- cgit v1.2.3 From 70549ad9cf074e12f12cdc931b29b2616dfb873a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 6 Jun 2005 23:07:46 -0700 Subject: [PATCH] PCI: clean up the MSI code a bit. Mostly just cleans up the irq handling logic to be smaller and a bit more descriptive as to what it really does. Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 88 +++++++++++++++++++++---------------------------------- drivers/pci/msi.h | 9 +++--- 2 files changed, 37 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 30206ac43c4..b5ab9aa6ff7 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -28,10 +28,10 @@ static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; static kmem_cache_t* msi_cachep; static int pci_msi_enable = 1; -static int last_alloc_vector = 0; -static int nr_released_vectors = 0; +static int last_alloc_vector; +static int nr_released_vectors; static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS; -static int nr_msix_devices = 0; +static int nr_msix_devices; #ifndef CONFIG_X86_IO_APIC int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; @@ -170,44 +170,30 @@ static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector) return 0; /* never anything pending */ } -static void release_msi(unsigned int vector); -static void shutdown_msi_irq(unsigned int vector) -{ - release_msi(vector); -} - -#define shutdown_msi_irq_wo_maskbit shutdown_msi_irq -static void enable_msi_irq_wo_maskbit(unsigned int vector) {} -static void disable_msi_irq_wo_maskbit(unsigned int vector) {} -static void ack_msi_irq_wo_maskbit(unsigned int vector) {} -static void end_msi_irq_wo_maskbit(unsigned int vector) +static unsigned int startup_msi_irq_w_maskbit(unsigned int vector) { - move_msi(vector); - ack_APIC_irq(); + startup_msi_irq_wo_maskbit(vector); + unmask_MSI_irq(vector); + return 0; /* never anything pending */ } -static unsigned int startup_msi_irq_w_maskbit(unsigned int vector) +static void shutdown_msi_irq(unsigned int vector) { struct msi_desc *entry; unsigned long flags; spin_lock_irqsave(&msi_lock, flags); entry = msi_desc[vector]; - if (!entry || !entry->dev) { - spin_unlock_irqrestore(&msi_lock, flags); - return 0; - } - entry->msi_attrib.state = 1; /* Mark it active */ + if (entry && entry->dev) + entry->msi_attrib.state = 0; /* Mark it not active */ spin_unlock_irqrestore(&msi_lock, flags); - - unmask_MSI_irq(vector); - return 0; /* never anything pending */ } -#define shutdown_msi_irq_w_maskbit shutdown_msi_irq -#define enable_msi_irq_w_maskbit unmask_MSI_irq -#define disable_msi_irq_w_maskbit mask_MSI_irq -#define ack_msi_irq_w_maskbit mask_MSI_irq +static void end_msi_irq_wo_maskbit(unsigned int vector) +{ + move_msi(vector); + ack_APIC_irq(); +} static void end_msi_irq_w_maskbit(unsigned int vector) { @@ -216,6 +202,10 @@ static void end_msi_irq_w_maskbit(unsigned int vector) ack_APIC_irq(); } +static void do_nothing(unsigned int vector) +{ +} + /* * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices, * which implement the MSI-X Capability Structure. @@ -223,10 +213,10 @@ static void end_msi_irq_w_maskbit(unsigned int vector) static struct hw_interrupt_type msix_irq_type = { .typename = "PCI-MSI-X", .startup = startup_msi_irq_w_maskbit, - .shutdown = shutdown_msi_irq_w_maskbit, - .enable = enable_msi_irq_w_maskbit, - .disable = disable_msi_irq_w_maskbit, - .ack = ack_msi_irq_w_maskbit, + .shutdown = shutdown_msi_irq, + .enable = unmask_MSI_irq, + .disable = mask_MSI_irq, + .ack = mask_MSI_irq, .end = end_msi_irq_w_maskbit, .set_affinity = set_msi_irq_affinity }; @@ -239,10 +229,10 @@ static struct hw_interrupt_type msix_irq_type = { static struct hw_interrupt_type msi_irq_w_maskbit_type = { .typename = "PCI-MSI", .startup = startup_msi_irq_w_maskbit, - .shutdown = shutdown_msi_irq_w_maskbit, - .enable = enable_msi_irq_w_maskbit, - .disable = disable_msi_irq_w_maskbit, - .ack = ack_msi_irq_w_maskbit, + .shutdown = shutdown_msi_irq, + .enable = unmask_MSI_irq, + .disable = mask_MSI_irq, + .ack = mask_MSI_irq, .end = end_msi_irq_w_maskbit, .set_affinity = set_msi_irq_affinity }; @@ -255,10 +245,10 @@ static struct hw_interrupt_type msi_irq_w_maskbit_type = { static struct hw_interrupt_type msi_irq_wo_maskbit_type = { .typename = "PCI-MSI", .startup = startup_msi_irq_wo_maskbit, - .shutdown = shutdown_msi_irq_wo_maskbit, - .enable = enable_msi_irq_wo_maskbit, - .disable = disable_msi_irq_wo_maskbit, - .ack = ack_msi_irq_wo_maskbit, + .shutdown = shutdown_msi_irq, + .enable = do_nothing, + .disable = do_nothing, + .ack = do_nothing, .end = end_msi_irq_wo_maskbit, .set_affinity = set_msi_irq_affinity }; @@ -407,7 +397,7 @@ static struct msi_desc* alloc_msi_entry(void) { struct msi_desc *entry; - entry = (struct msi_desc*) kmem_cache_alloc(msi_cachep, SLAB_KERNEL); + entry = kmem_cache_alloc(msi_cachep, SLAB_KERNEL); if (!entry) return NULL; @@ -796,18 +786,6 @@ void pci_disable_msi(struct pci_dev* dev) } } -static void release_msi(unsigned int vector) -{ - struct msi_desc *entry; - unsigned long flags; - - spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[vector]; - if (entry && entry->dev) - entry->msi_attrib.state = 0; /* Mark it not active */ - spin_unlock_irqrestore(&msi_lock, flags); -} - static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) { struct msi_desc *entry; @@ -924,7 +902,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) /** * pci_enable_msix - configure device's MSI-X capability structure * @dev: pointer to the pci_dev data structure of MSI-X device function - * @data: pointer to an array of MSI-X entries + * @entries: pointer to an array of MSI-X entries * @nvec: number of MSI-X vectors requested for allocation by device driver * * Setup the MSI-X capability structure of device function with the number diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index bef21ae3cbd..390f1851c0f 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -41,11 +41,11 @@ static inline void move_msi(int vector) {} #define PCI_MSIX_FLAGS_BIRMASK (7 << 0) #define PCI_MSIX_FLAGS_BITMASK (1 << 0) -#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0 -#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4 -#define PCI_MSIX_ENTRY_DATA_OFFSET 8 -#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12 #define PCI_MSIX_ENTRY_SIZE 16 +#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0 +#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4 +#define PCI_MSIX_ENTRY_DATA_OFFSET 8 +#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12 #define msi_control_reg(base) (base + PCI_MSI_FLAGS) #define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO) @@ -64,7 +64,6 @@ static inline void move_msi(int vector) {} #define msi_enable(control, num) multi_msi_enable(control, num); \ control |= PCI_MSI_FLAGS_ENABLE -#define msix_control_reg msi_control_reg #define msix_table_offset_reg(base) (base + 0x04) #define msix_pba_offset_reg(base) (base + 0x08) #define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE -- cgit v1.2.3 From 4002307d2b563a6ab317ca4d7eb1d201a6673d37 Mon Sep 17 00:00:00 2001 From: Keith Moore Date: Thu, 2 Jun 2005 12:42:37 +0200 Subject: [PATCH] cpqphp: fix oops during unload without probe drivers/pci/hotplug/cpqphp_core.c calls cpqphp_event_start_thread() in one_time_init(), which is called whenever the hardware is probed. Unfortunately, cpqphp_event_stop_thread() is *always* called when the module is unloaded. If the hardware is never probed, then cpqphp_event_stop_thread() tries to manipulate a couple of uninitialized mutexes. Signed-off-by: Keith Moore Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpqphp_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index afbccfa5217..8c6d3987d46 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -60,6 +60,7 @@ static void __iomem *smbios_start; static void __iomem *cpqhp_rom_start; static int power_mode; static int debug; +static int initialized; #define DRIVER_VERSION "0.9.8" #define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman " @@ -1271,7 +1272,6 @@ static int one_time_init(void) { int loop; int retval = 0; - static int initialized = 0; if (initialized) return 0; @@ -1441,7 +1441,8 @@ static void __exit unload_cpqphpd(void) } // Stop the notification mechanism - cpqhp_event_stop_thread(); + if (initialized) + cpqhp_event_stop_thread(); //unmap the rom address if (cpqhp_rom_start) -- cgit v1.2.3 From d18c3db58bc544fce6662ca7edba616ca9788a70 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 23 Jun 2005 17:35:56 -0700 Subject: [PATCH] PCI: make drivers use the pci shutdown callback instead of the driver core callback. Now we can change the pci core to always set this pointer, as pci drivers should use it, not the driver core callback. Signed-off-by: Greg Kroah-Hartman --- drivers/message/fusion/mptfc.c | 4 +--- drivers/message/fusion/mptscsih.c | 10 +++++----- drivers/message/fusion/mptscsih.h | 2 +- drivers/message/fusion/mptspi.c | 4 +--- drivers/net/e100.c | 9 ++------- drivers/net/via-rhine.c | 11 ++++------- drivers/scsi/3w-9xxx.c | 8 +++----- drivers/scsi/3w-xxxx.c | 8 +++----- drivers/scsi/ipr.c | 10 ++++------ drivers/scsi/megaraid.c | 8 +++----- 10 files changed, 27 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index d8d65397e06..353deb25e39 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -364,9 +364,7 @@ static struct pci_driver mptfc_driver = { .id_table = mptfc_pci_table, .probe = mptfc_probe, .remove = __devexit_p(mptscsih_remove), - .driver = { - .shutdown = mptscsih_shutdown, - }, + .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, .resume = mptscsih_resume, diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index a0078ae5b9b..4f973a49be4 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -170,7 +170,7 @@ static void mptscsih_fillbuf(char *buffer, int size, int index, int width); #endif void mptscsih_remove(struct pci_dev *); -void mptscsih_shutdown(struct device *); +void mptscsih_shutdown(struct pci_dev *); #ifdef CONFIG_PM int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state); int mptscsih_resume(struct pci_dev *pdev); @@ -988,7 +988,7 @@ mptscsih_remove(struct pci_dev *pdev) #endif #endif - mptscsih_shutdown(&pdev->dev); + mptscsih_shutdown(pdev); sz1=0; @@ -1026,9 +1026,9 @@ mptscsih_remove(struct pci_dev *pdev) * */ void -mptscsih_shutdown(struct device * dev) +mptscsih_shutdown(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(to_pci_dev(dev)); + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct Scsi_Host *host = ioc->sh; MPT_SCSI_HOST *hd; @@ -1054,7 +1054,7 @@ mptscsih_shutdown(struct device * dev) int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state) { - mptscsih_shutdown(&pdev->dev); + mptscsih_shutdown(pdev); return mpt_suspend(pdev,state); } diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index d73aec33e16..5ea89bf0df1 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -82,7 +82,7 @@ #endif extern void mptscsih_remove(struct pci_dev *); -extern void mptscsih_shutdown(struct device *); +extern void mptscsih_shutdown(struct pci_dev *); #ifdef CONFIG_PM extern int mptscsih_suspend(struct pci_dev *pdev, u32 state); extern int mptscsih_resume(struct pci_dev *pdev); diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 5f9a61b85b3..e0c0ee5bc96 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -419,9 +419,7 @@ static struct pci_driver mptspi_driver = { .id_table = mptspi_pci_table, .probe = mptspi_probe, .remove = __devexit_p(mptscsih_remove), - .driver = { - .shutdown = mptscsih_shutdown, - }, + .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, .resume = mptscsih_resume, diff --git a/drivers/net/e100.c b/drivers/net/e100.c index cfaa6b2bf34..be973a1c3c5 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2440,9 +2440,8 @@ static int e100_resume(struct pci_dev *pdev) #endif -static void e100_shutdown(struct device *dev) +static void e100_shutdown(struct pci_dev *pdev) { - struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); @@ -2463,11 +2462,7 @@ static struct pci_driver e100_driver = { .suspend = e100_suspend, .resume = e100_resume, #endif - - .driver = { - .shutdown = e100_shutdown, - } - + .shutdown = e100_shutdown, }; static int __init e100_init_module(void) diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 6200cfc4244..16212e69a49 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -507,7 +507,7 @@ static struct net_device_stats *rhine_get_stats(struct net_device *dev); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct ethtool_ops netdev_ethtool_ops; static int rhine_close(struct net_device *dev); -static void rhine_shutdown (struct device *gdev); +static void rhine_shutdown (struct pci_dev *pdev); #define RHINE_WAIT_FOR(condition) do { \ int i=1024; \ @@ -1895,9 +1895,8 @@ static void __devexit rhine_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } -static void rhine_shutdown (struct device *gendev) +static void rhine_shutdown (struct pci_dev *pdev) { - struct pci_dev *pdev = to_pci_dev(gendev); struct net_device *dev = pci_get_drvdata(pdev); struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; @@ -1956,7 +1955,7 @@ static int rhine_suspend(struct pci_dev *pdev, pm_message_t state) pci_save_state(pdev); spin_lock_irqsave(&rp->lock, flags); - rhine_shutdown(&pdev->dev); + rhine_shutdown(pdev); spin_unlock_irqrestore(&rp->lock, flags); free_irq(dev->irq, dev); @@ -2010,9 +2009,7 @@ static struct pci_driver rhine_driver = { .suspend = rhine_suspend, .resume = rhine_resume, #endif /* CONFIG_PM */ - .driver = { - .shutdown = rhine_shutdown, - } + .shutdown = rhine_shutdown, }; diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 34dbc37a79d..bc6e4627c7a 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1916,9 +1916,9 @@ static void __twa_shutdown(TW_Device_Extension *tw_dev) } /* End __twa_shutdown() */ /* Wrapper for __twa_shutdown */ -static void twa_shutdown(struct device *dev) +static void twa_shutdown(struct pci_dev *pdev) { - struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); + struct Scsi_Host *host = pci_get_drvdata(pdev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; __twa_shutdown(tw_dev); @@ -2140,9 +2140,7 @@ static struct pci_driver twa_driver = { .id_table = twa_pci_tbl, .probe = twa_probe, .remove = twa_remove, - .driver = { - .shutdown = twa_shutdown - } + .shutdown = twa_shutdown }; /* This function is called on driver initialization */ diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index b6dc576da43..973c51fb0fe 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -2264,9 +2264,9 @@ static void __tw_shutdown(TW_Device_Extension *tw_dev) } /* End __tw_shutdown() */ /* Wrapper for __tw_shutdown */ -static void tw_shutdown(struct device *dev) +static void tw_shutdown(struct pci_dev *pdev) { - struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); + struct Scsi_Host *host = pci_get_drvdata(pdev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; __tw_shutdown(tw_dev); @@ -2451,9 +2451,7 @@ static struct pci_driver tw_driver = { .id_table = tw_pci_tbl, .probe = tw_probe, .remove = tw_remove, - .driver = { - .shutdown = tw_shutdown - } + .shutdown = tw_shutdown, }; /* This function is called on driver initialization */ diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 80d022625c8..babd4836340 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6012,7 +6012,7 @@ static int __devinit ipr_probe(struct pci_dev *pdev, /** * ipr_shutdown - Shutdown handler. - * @dev: device struct + * @pdev: pci device struct * * This function is invoked upon system shutdown/reboot. It will issue * an adapter shutdown to the adapter to flush the write cache. @@ -6020,9 +6020,9 @@ static int __devinit ipr_probe(struct pci_dev *pdev, * Return value: * none **/ -static void ipr_shutdown(struct device *dev) +static void ipr_shutdown(struct pci_dev *pdev) { - struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(to_pci_dev(dev)); + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); unsigned long lock_flags = 0; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -6068,9 +6068,7 @@ static struct pci_driver ipr_driver = { .id_table = ipr_pci_table, .probe = ipr_probe, .remove = ipr_remove, - .driver = { - .shutdown = ipr_shutdown, - }, + .shutdown = ipr_shutdown, }; /** diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index ec81532eb84..a70cdf31311 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -5036,9 +5036,9 @@ megaraid_remove_one(struct pci_dev *pdev) } static void -megaraid_shutdown(struct device *dev) +megaraid_shutdown(struct pci_dev *pdev) { - struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); + struct Scsi_Host *host = pci_get_drvdata(pdev); adapter_t *adapter = (adapter_t *)host->hostdata; __megaraid_shutdown(adapter); @@ -5070,9 +5070,7 @@ static struct pci_driver megaraid_pci_driver = { .id_table = megaraid_pci_tbl, .probe = megaraid_probe_one, .remove = __devexit_p(megaraid_remove_one), - .driver = { - .shutdown = megaraid_shutdown, - }, + .shutdown = megaraid_shutdown, }; static int __init megaraid_init(void) -- cgit v1.2.3 From 66b7f8a30437b8639e798f7db8e9be1da5711efa Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Mon, 25 Apr 2005 13:51:00 -0700 Subject: [IA64-SGI] pcdp: add PCDP pci interface support Resend 2 with changes per Bjorn Helgaas comments. Changes from original: + Change globals to vga_console_iobase/vga_console_membase and make them unconditional. + Address style-related comments. Patch to extend the PCDP vga setup code to support PCI io/mem translations for the legacy vga ioport and ram spaces on architectures (e.g. altix) which need them. Summary of the changes: drivers/firmware/pcdp.c drivers/firmware/pcdp.h ----------------------- + add declaration for the spec-defined PCI interface struct (pcdp_if_pci) as well as support macros. + extend setup_vga_console() to know about pcdp_if_pci and add a couple of globals to hold the io and mem translation offsets if present. arch/ia64/kernel/setup.c ------------------------ + tweek early_console_setup() to allow multiple early console setup routines to be called. include/asm-ia64/vga.h ---------------------- + make VGA_MAP_MEM vga_console_membase aware Signed-off-by: Mark Maule Signed-off-by: Tony Luck --- drivers/firmware/pcdp.c | 24 +++++++++++++++++++++--- drivers/firmware/pcdp.h | 33 +++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c index 839b44a7e08..53c95c0bbf4 100644 --- a/drivers/firmware/pcdp.c +++ b/drivers/firmware/pcdp.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "pcdp.h" static int __init @@ -40,10 +41,27 @@ setup_serial_console(struct pcdp_uart *uart) } static int __init -setup_vga_console(struct pcdp_vga *vga) +setup_vga_console(struct pcdp_device *dev) { #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) - if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) { + u8 *if_ptr; + + if_ptr = ((u8 *)dev + sizeof(struct pcdp_device)); + if (if_ptr[0] == PCDP_IF_PCI) { + struct pcdp_if_pci if_pci; + + /* struct copy since ifptr might not be correctly aligned */ + + memcpy(&if_pci, if_ptr, sizeof(if_pci)); + + if (if_pci.trans & PCDP_PCI_TRANS_IOPORT) + vga_console_iobase = if_pci.ioport_tra; + + if (if_pci.trans & PCDP_PCI_TRANS_MMIO) + vga_console_membase = if_pci.mmio_tra; + } + + if (efi_mem_type(vga_console_membase + 0xA0000) == EFI_CONVENTIONAL_MEMORY) { printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n"); return -ENODEV; } @@ -95,7 +113,7 @@ efi_setup_pcdp_console(char *cmdline) dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) { if (dev->flags & PCDP_PRIMARY_CONSOLE) { if (dev->type == PCDP_CONSOLE_VGA) { - return setup_vga_console((struct pcdp_vga *) dev); + return setup_vga_console(dev); } } } diff --git a/drivers/firmware/pcdp.h b/drivers/firmware/pcdp.h index 1dc7c88b7b4..e72cc47de33 100644 --- a/drivers/firmware/pcdp.h +++ b/drivers/firmware/pcdp.h @@ -52,11 +52,34 @@ struct pcdp_uart { u32 clock_rate; u8 pci_prog_intfc; u8 flags; -}; +} __attribute__((packed)); + +#define PCDP_IF_PCI 1 + +/* pcdp_if_pci.trans */ +#define PCDP_PCI_TRANS_IOPORT 0x02 +#define PCDP_PCI_TRANS_MMIO 0x01 + +struct pcdp_if_pci { + u8 interconnect; + u8 reserved; + u16 length; + u8 segment; + u8 bus; + u8 dev; + u8 fun; + u16 dev_id; + u16 vendor_id; + u32 acpi_interrupt; + u64 mmio_tra; + u64 ioport_tra; + u8 flags; + u8 trans; +} __attribute__((packed)); struct pcdp_vga { u8 count; /* address space descriptors */ -}; +} __attribute__((packed)); /* pcdp_device.flags */ #define PCDP_PRIMARY_CONSOLE 1 @@ -66,7 +89,9 @@ struct pcdp_device { u8 flags; u16 length; u16 efi_index; -}; + /* next data is pcdp_if_pci or pcdp_if_acpi (not yet supported) */ + /* next data is device specific type (currently only pcdp_vga) */ +} __attribute__((packed)); struct pcdp { u8 signature[4]; @@ -81,4 +106,4 @@ struct pcdp { u32 num_uarts; struct pcdp_uart uart[0]; /* actual size is num_uarts */ /* remainder of table is pcdp_device structures */ -}; +} __attribute__((packed)); -- cgit v1.2.3 From 97afa0a25afb43a82954662773a9d48d61b2996a Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 27 Jun 2005 22:29:31 -0700 Subject: [PATCH] cciss_ioctl() warning fix Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/cciss.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 653512b7757..3e9fb6e4a52 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -786,7 +786,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, case CCISS_GETLUNINFO: { LogvolInfo_struct luninfo; - int i; luninfo.LunID = drv->LunID; luninfo.num_opens = drv->usage_count; -- cgit v1.2.3 From f8b58edf3acf0dcc186b8330939000ecf709368a Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Mon, 27 Jun 2005 22:29:34 -0700 Subject: [PATCH] md: bio leak fix insert a missing bio_put when writting the md superblock. Without this we have a steady growth in the "bio" slab. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/md.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 3802f7a17f1..4a0c57db2b6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -338,6 +338,7 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error) if (atomic_dec_and_test(&rdev->mddev->pending_writes)) wake_up(&rdev->mddev->sb_wait); + bio_put(bio); return 0; } -- cgit v1.2.3 From 082cf69eb82681f4eacb3a5653834c7970714bef Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 28 Jun 2005 16:35:11 +0200 Subject: [PATCH] ll_rw_blk: prevent huge request allocations Currently we cap request allocations at q->nr_requests, but we allow a batching io context to allocate up to 32 more (default setting). This can flood the queue with request allocations, with only a few batching processes. The real fix would be to limit the number of batchers, but as that isn't currently tracked, I suggest we just cap the maximum number of allocated requests to eg 50% over the limit. This was observed in real life, users typically see this as vmstat bo numbers going off the wall with seconds of no queueing afterwards. Behaviour this bursty is not beneficial. Signed-off-by: Jens Axboe Signed-off-by: Linus Torvalds --- drivers/block/ll_rw_blk.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 234fdcfbdf0..6c98cf04271 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1912,6 +1912,15 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, } get_rq: + /* + * Only allow batching queuers to allocate up to 50% over the defined + * limit of requests, otherwise we could have thousands of requests + * allocated with any setting of ->nr_requests + */ + if (rl->count[rw] >= (3 * q->nr_requests / 2)) { + spin_unlock_irq(q->queue_lock); + goto out; + } rl->count[rw]++; rl->starved[rw] = 0; if (rl->count[rw] >= queue_congestion_on_threshold(q)) -- cgit v1.2.3 From 689be43945e9ca7dd704522e55af1b8a73a994d3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 28 Jun 2005 15:25:31 -0700 Subject: [NET]: Remove gratuitous use of skb->tail in network drivers. Many drivers use skb->tail unnecessarily. In these situations, the code roughly looks like: dev = dev_alloc_skb(...); [optional] skb_reserve(skb, ...); ... skb->tail ... But even if the skb_reserve() happens, skb->data equals skb->tail. So it doesn't make any sense to use anything other than skb->data in these cases. Another case was the s2io.c driver directly mucking with the skb->data and skb->tail pointers. It really just wanted to do an skb_reserve(), so that's what the code was changed to do instead. Another reason I'm making this change as it allows some SKB cleanups I have planned simpler to merge. In those cleanups, skb->head, skb->tail, and skb->end pointers are removed, and replaced with skb->head_room and skb->tail_room integers. Signed-off-by: David S. Miller Acked-by: Jeff Garzik --- drivers/net/3c515.c | 4 ++-- drivers/net/3c59x.c | 6 +++--- drivers/net/8139cp.c | 4 ++-- drivers/net/82596.c | 14 +++++++------- drivers/net/dl2k.c | 8 ++++---- drivers/net/eepro100.c | 8 ++++---- drivers/net/epic100.c | 6 +++--- drivers/net/fealnx.c | 8 ++++---- drivers/net/hamachi.c | 12 ++++++------ drivers/net/lance.c | 2 +- drivers/net/lasi_82596.c | 8 ++++---- drivers/net/natsemi.c | 4 ++-- drivers/net/ns83820.c | 4 ++-- drivers/net/pcnet32.c | 6 +++--- drivers/net/r8169.c | 4 ++-- drivers/net/s2io.c | 8 +++----- drivers/net/sb1250-mac.c | 4 ++-- drivers/net/sis900.c | 6 +++--- drivers/net/starfire.c | 6 +++--- drivers/net/sundance.c | 6 +++--- drivers/net/tulip/de2104x.c | 6 +++--- drivers/net/tulip/dmfe.c | 10 +++++----- drivers/net/tulip/interrupt.c | 10 +++++----- drivers/net/tulip/tulip_core.c | 2 +- drivers/net/tulip/winbond-840.c | 6 +++--- drivers/net/tulip/xircom_tulip_cb.c | 4 ++-- drivers/net/typhoon.c | 4 ++-- drivers/net/via-rhine.c | 6 +++--- drivers/net/via-velocity.c | 6 +++--- drivers/net/wan/hdlc_cisco.c | 2 +- drivers/net/yellowfin.c | 8 ++++---- 31 files changed, 95 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index d272ea36a57..91d1c4c24d9 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -822,7 +822,7 @@ static int corkscrew_open(struct net_device *dev) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = isa_virt_to_bus(skb->tail); + vp->rx_ring[i].addr = isa_virt_to_bus(skb->data); } vp->rx_ring[i - 1].next = isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */ outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); @@ -1406,7 +1406,7 @@ static int boomerang_rx(struct net_device *dev) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr = isa_virt_to_bus(skb->tail); + vp->rx_ring[entry].addr = isa_virt_to_bus(skb->data); vp->rx_skbuff[entry] = skb; } vp->rx_ring[entry].status = 0; /* Clear complete bit. */ diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 80ec9aa575b..07746b95fd8 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1802,7 +1802,7 @@ vortex_open(struct net_device *dev) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); + vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); } if (i != RX_RING_SIZE) { int j; @@ -2632,7 +2632,7 @@ boomerang_rx(struct net_device *dev) pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), - vp->rx_skbuff[entry]->tail, + vp->rx_skbuff[entry]->data, pkt_len); pci_dma_sync_single_for_device(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); vp->rx_copy++; @@ -2678,7 +2678,7 @@ boomerang_rx(struct net_device *dev) } skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); + vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); vp->rx_skbuff[entry] = skb; } vp->rx_ring[entry].status = 0; /* Clear complete bit. */ diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index e4b3c5c8854..7b293f01c9e 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -596,7 +596,7 @@ rx_status_loop: mapping = cp->rx_skb[rx_tail].mapping = - pci_map_single(cp->pdev, new_skb->tail, + pci_map_single(cp->pdev, new_skb->data, buflen, PCI_DMA_FROMDEVICE); cp->rx_skb[rx_tail].skb = new_skb; @@ -1101,7 +1101,7 @@ static int cp_refill_rx (struct cp_private *cp) skb_reserve(skb, RX_OFFSET); cp->rx_skb[i].mapping = pci_map_single(cp->pdev, - skb->tail, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); cp->rx_skb[i].skb = skb; cp->rx_ring[i].opts2 = 0; diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 65f97b1dc58..13b745b3966 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -546,11 +546,11 @@ static inline void init_rx_bufs(struct net_device *dev) rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1)); rbd->b_addr = WSWAPrbd(virt_to_bus(rbd)); rbd->skb = skb; - rbd->v_data = skb->tail; - rbd->b_data = WSWAPchar(virt_to_bus(skb->tail)); + rbd->v_data = skb->data; + rbd->b_data = WSWAPchar(virt_to_bus(skb->data)); rbd->size = PKT_BUF_SZ; #ifdef __mc68000__ - cache_clear(virt_to_phys(skb->tail), PKT_BUF_SZ); + cache_clear(virt_to_phys(skb->data), PKT_BUF_SZ); #endif } lp->rbd_head = lp->rbds; @@ -816,10 +816,10 @@ static inline int i596_rx(struct net_device *dev) rx_in_place = 1; rbd->skb = newskb; newskb->dev = dev; - rbd->v_data = newskb->tail; - rbd->b_data = WSWAPchar(virt_to_bus(newskb->tail)); + rbd->v_data = newskb->data; + rbd->b_data = WSWAPchar(virt_to_bus(newskb->data)); #ifdef __mc68000__ - cache_clear(virt_to_phys(newskb->tail), PKT_BUF_SZ); + cache_clear(virt_to_phys(newskb->data), PKT_BUF_SZ); #endif } else @@ -840,7 +840,7 @@ memory_squeeze: skb->protocol=eth_type_trans(skb,dev); skb->len = pkt_len; #ifdef __mc68000__ - cache_clear(virt_to_phys(rbd->skb->tail), + cache_clear(virt_to_phys(rbd->skb->data), pkt_len); #endif netif_rx(skb); diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index aa42b7a2773..430c628279b 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -547,7 +547,7 @@ rio_timer (unsigned long data) skb_reserve (skb, 2); np->rx_ring[entry].fraginfo = cpu_to_le64 (pci_map_single - (np->pdev, skb->tail, np->rx_buf_sz, + (np->pdev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); } np->rx_ring[entry].fraginfo |= @@ -618,7 +618,7 @@ alloc_list (struct net_device *dev) /* Rubicon now supports 40 bits of addressing space. */ np->rx_ring[i].fraginfo = cpu_to_le64 ( pci_map_single ( - np->pdev, skb->tail, np->rx_buf_sz, + np->pdev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48; } @@ -906,7 +906,7 @@ receive_packet (struct net_device *dev) /* 16 byte align the IP header */ skb_reserve (skb, 2); eth_copy_and_sum (skb, - np->rx_skbuff[entry]->tail, + np->rx_skbuff[entry]->data, pkt_len, 0); skb_put (skb, pkt_len); pci_dma_sync_single_for_device(np->pdev, @@ -950,7 +950,7 @@ receive_packet (struct net_device *dev) skb_reserve (skb, 2); np->rx_ring[entry].fraginfo = cpu_to_le64 (pci_map_single - (np->pdev, skb->tail, np->rx_buf_sz, + (np->pdev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); } np->rx_ring[entry].fraginfo |= diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 98b3a2fdce9..1795425f512 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -1269,7 +1269,7 @@ speedo_init_rx_ring(struct net_device *dev) if (skb == NULL) break; /* OK. Just initially short of Rx bufs. */ skb->dev = dev; /* Mark as being used by this device. */ - rxf = (struct RxFD *)skb->tail; + rxf = (struct RxFD *)skb->data; sp->rx_ringp[i] = rxf; sp->rx_ring_dma[i] = pci_map_single(sp->pdev, rxf, @@ -1661,7 +1661,7 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) sp->rx_ringp[entry] = NULL; return NULL; } - rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail; + rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->data; sp->rx_ring_dma[entry] = pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); @@ -1808,10 +1808,10 @@ speedo_rx(struct net_device *dev) #if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ - eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0); + eth_copy_and_sum(skb, sp->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail, + memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->data, pkt_len); #endif pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 81ebaedaa24..87f522738bf 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1003,7 +1003,7 @@ static void epic_init_ring(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev, - skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn); } ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -1274,7 +1274,7 @@ static int epic_rx(struct net_device *dev, int budget) ep->rx_ring[entry].bufaddr, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0); + eth_copy_and_sum(skb, ep->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(ep->pci_dev, ep->rx_ring[entry].bufaddr, @@ -1308,7 +1308,7 @@ static int epic_rx(struct net_device *dev, int budget) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, - skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); work_done++; } ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn); diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 9e0303f6d73..55dbe9a3fd5 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1107,7 +1107,7 @@ static void allocate_rx_buffers(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ np->lack_rxbuf->skbuff = skb; - np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->tail, + np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); np->lack_rxbuf->status = RXOWN; ++np->really_rx_count; @@ -1300,7 +1300,7 @@ static void init_ring(struct net_device *dev) ++np->really_rx_count; np->rx_ring[i].skbuff = skb; skb->dev = dev; /* Mark as being used by this device. */ - np->rx_ring[i].buffer = pci_map_single(np->pci_dev, skb->tail, + np->rx_ring[i].buffer = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); np->rx_ring[i].status = RXOWN; np->rx_ring[i].control |= RXIC; @@ -1737,11 +1737,11 @@ static int netdev_rx(struct net_device *dev) #if ! defined(__alpha__) eth_copy_and_sum(skb, - np->cur_rx->skbuff->tail, pkt_len, 0); + np->cur_rx->skbuff->data, pkt_len, 0); skb_put(skb, pkt_len); #else memcpy(skb_put(skb, pkt_len), - np->cur_rx->skbuff->tail, pkt_len); + np->cur_rx->skbuff->data, pkt_len); #endif pci_dma_sync_single_for_device(np->pci_dev, np->cur_rx->buffer, diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 3d96714ed3c..d9df1d9a573 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1149,7 +1149,7 @@ static void hamachi_tx_timeout(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, - skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2)); } @@ -1210,7 +1210,7 @@ static void hamachi_init_ring(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, - skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); /* -2 because it doesn't REALLY have that first 2 bytes -KDU */ hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | DescEndPacket | DescIntr | (hmp->rx_buf_sz -2)); @@ -1509,7 +1509,7 @@ static int hamachi_rx(struct net_device *dev) desc->addr, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); - buf_addr = (u8 *) hmp->rx_skbuff[entry]->tail; + buf_addr = (u8 *) hmp->rx_skbuff[entry]->data; frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12]))); if (hamachi_debug > 4) printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", @@ -1678,7 +1678,7 @@ static int hamachi_rx(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ desc->addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, - skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); } desc->status_n_length = cpu_to_le32(hmp->rx_buf_sz); if (entry >= RX_RING_SIZE-1) @@ -1772,9 +1772,9 @@ static int hamachi_close(struct net_device *dev) readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ', i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr); if (hamachi_debug > 6) { - if (*(u8*)hmp->rx_skbuff[i]->tail != 0x69) { + if (*(u8*)hmp->rx_skbuff[i]->data != 0x69) { u16 *addr = (u16 *) - hmp->rx_skbuff[i]->tail; + hmp->rx_skbuff[i]->data; int j; for (j = 0; j < 0x50; j++) diff --git a/drivers/net/lance.c b/drivers/net/lance.c index ca90f0d1e4b..b4929beb33b 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -862,7 +862,7 @@ lance_init_ring(struct net_device *dev, int gfp) lp->rx_skbuff[i] = skb; if (skb) { skb->dev = dev; - rx_buff = skb->tail; + rx_buff = skb->data; } else rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | gfp); if (rx_buff == NULL) diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index 5e263fcba66..41bad07ac1a 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -553,14 +553,14 @@ static inline void init_rx_bufs(struct net_device *dev) if (skb == NULL) panic("%s: alloc_skb() failed", __FILE__); skb_reserve(skb, 2); - dma_addr = dma_map_single(lp->dev, skb->tail,PKT_BUF_SZ, + dma_addr = dma_map_single(lp->dev, skb->data,PKT_BUF_SZ, DMA_FROM_DEVICE); skb->dev = dev; rbd->v_next = rbd+1; rbd->b_next = WSWAPrbd(virt_to_dma(lp,rbd+1)); rbd->b_addr = WSWAPrbd(virt_to_dma(lp,rbd)); rbd->skb = skb; - rbd->v_data = skb->tail; + rbd->v_data = skb->data; rbd->b_data = WSWAPchar(dma_addr); rbd->size = PKT_BUF_SZ; } @@ -783,8 +783,8 @@ static inline int i596_rx(struct net_device *dev) rx_in_place = 1; rbd->skb = newskb; newskb->dev = dev; - dma_addr = dma_map_single(lp->dev, newskb->tail, PKT_BUF_SZ, DMA_FROM_DEVICE); - rbd->v_data = newskb->tail; + dma_addr = dma_map_single(lp->dev, newskb->data, PKT_BUF_SZ, DMA_FROM_DEVICE); + rbd->v_data = newskb->data; rbd->b_data = WSWAPchar(dma_addr); CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd)); } diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index babb59e146e..9d6d2548c2d 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -1926,7 +1926,7 @@ static void refill_rx(struct net_device *dev) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ np->rx_dma[entry] = pci_map_single(np->pci_dev, - skb->tail, buflen, PCI_DMA_FROMDEVICE); + skb->data, buflen, PCI_DMA_FROMDEVICE); np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); } np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz); @@ -2280,7 +2280,7 @@ static void netdev_rx(struct net_device *dev) buflen, PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, - np->rx_skbuff[entry]->tail, pkt_len, 0); + np->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(np->pci_dev, np->rx_dma[entry], diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index cc796527177..e64df4d0800 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -574,7 +574,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb) dev->rx_info.next_empty = (next_empty + 1) % NR_RX_DESC; cmdsts = REAL_RX_BUF_SIZE | CMDSTS_INTR; - buf = pci_map_single(dev->pci_dev, skb->tail, + buf = pci_map_single(dev->pci_dev, skb->data, REAL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); build_rx_desc(dev, sg, 0, buf, cmdsts, 0); /* update link of previous rx */ @@ -604,7 +604,7 @@ static inline int rx_refill(struct net_device *ndev, int gfp) if (unlikely(!skb)) break; - res = (long)skb->tail & 0xf; + res = (long)skb->data & 0xf; res = 0x10 - res; res &= 0xf; skb_reserve(skb, res); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 3213f3e5048..113b6809921 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1602,7 +1602,7 @@ pcnet32_init_ring(struct net_device *dev) rmb(); if (lp->rx_dma_addr[i] == 0) - lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, + lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]); lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ); @@ -1983,7 +1983,7 @@ pcnet32_rx(struct net_device *dev) lp->rx_skbuff[entry] = newskb; newskb->dev = dev; lp->rx_dma_addr[entry] = - pci_map_single(lp->pci_dev, newskb->tail, + pci_map_single(lp->pci_dev, newskb->data, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]); rx_in_place = 1; @@ -2020,7 +2020,7 @@ pcnet32_rx(struct net_device *dev) PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, - (unsigned char *)(lp->rx_skbuff[entry]->tail), + (unsigned char *)(lp->rx_skbuff[entry]->data), pkt_len,0); pci_dma_sync_single_for_device(lp->pci_dev, lp->rx_dma_addr[entry], diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index ce449fe90e6..d5afe05cd82 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1876,7 +1876,7 @@ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, skb_reserve(skb, NET_IP_ALIGN); *sk_buff = skb; - mapping = pci_map_single(pdev, skb->tail, rx_buf_sz, + mapping = pci_map_single(pdev, skb->data, rx_buf_sz, PCI_DMA_FROMDEVICE); rtl8169_map_to_asic(desc, mapping, rx_buf_sz); @@ -2336,7 +2336,7 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN); if (skb) { skb_reserve(skb, NET_IP_ALIGN); - eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0); + eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0); *sk_buff = skb; rtl8169_mark_to_asic(desc, rx_buf_sz); ret = 0; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index bb639a8794d..ea638b162d3 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1699,11 +1699,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) #else ba = &nic->ba[ring_no][block_no][off]; skb_reserve(skb, BUF0_LEN); - tmp = (unsigned long) skb->data; - tmp += ALIGN_SIZE; - tmp &= ~ALIGN_SIZE; - skb->data = (void *) tmp; - skb->tail = (void *) tmp; + tmp = ((unsigned long) skb->data & ALIGN_SIZE); + if (tmp) + skb_reserve(skb, (ALIGN_SIZE + 1) - tmp); memset(rxdp, 0, sizeof(RxD_t)); rxdp->Buffer2_ptr = pci_map_single diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index fd2e7c37490..7abd55a4fb2 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -963,11 +963,11 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) /* * Do not interrupt per DMA transfer. */ - dsc->dscr_a = virt_to_phys(sb_new->tail) | + dsc->dscr_a = virt_to_phys(sb_new->data) | V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | 0; #else - dsc->dscr_a = virt_to_phys(sb_new->tail) | + dsc->dscr_a = virt_to_phys(sb_new->data) | V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | M_DMA_DSCRA_INTERRUPT; #endif diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 127324f014d..23b713c700b 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1154,7 +1154,7 @@ sis900_init_rx_ring(struct net_device *net_dev) sis_priv->rx_skbuff[i] = skb; sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE; sis_priv->rx_ring[i].bufptr = pci_map_single(sis_priv->pci_dev, - skb->tail, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); } sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC); @@ -1776,7 +1776,7 @@ static int sis900_rx(struct net_device *net_dev) sis_priv->rx_skbuff[entry] = skb; sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; sis_priv->rx_ring[entry].bufptr = - pci_map_single(sis_priv->pci_dev, skb->tail, + pci_map_single(sis_priv->pci_dev, skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); sis_priv->dirty_rx++; } @@ -1809,7 +1809,7 @@ static int sis900_rx(struct net_device *net_dev) sis_priv->rx_skbuff[entry] = skb; sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; sis_priv->rx_ring[entry].bufptr = - pci_map_single(sis_priv->pci_dev, skb->tail, + pci_map_single(sis_priv->pci_dev, skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); } } diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 12e2b6826fa..88b89dc95c7 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1286,7 +1286,7 @@ static void init_ring(struct net_device *dev) np->rx_info[i].skb = skb; if (skb == NULL) break; - np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb->dev = dev; /* Mark as being used by this device. */ /* Grrr, we cannot offset to correctly align the IP header. */ np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid); @@ -1572,7 +1572,7 @@ static int __netdev_rx(struct net_device *dev, int *quota) pci_dma_sync_single_for_cpu(np->pci_dev, np->rx_info[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0); + eth_copy_and_sum(skb, np->rx_info[entry].skb->data, pkt_len, 0); pci_dma_sync_single_for_device(np->pci_dev, np->rx_info[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); @@ -1696,7 +1696,7 @@ static void refill_rx_ring(struct net_device *dev) if (skb == NULL) break; /* Better luck next round. */ np->rx_info[entry].mapping = - pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb->dev = dev; /* Mark as being used by this device. */ np->rx_ring[entry].rxaddr = cpu_to_dma(np->rx_info[entry].mapping | RxDescValid); diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 08cb7177a17..d500a5771db 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1028,7 +1028,7 @@ static void init_ring(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ np->rx_ring[i].frag[0].addr = cpu_to_le32( - pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, + pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag); } @@ -1341,7 +1341,7 @@ static void rx_poll(unsigned long data) np->rx_buf_sz, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0); pci_dma_sync_single_for_device(np->pci_dev, desc->frag[0].addr, np->rx_buf_sz, @@ -1400,7 +1400,7 @@ static void refill_rx (struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ np->rx_ring[entry].frag[0].addr = cpu_to_le32( - pci_map_single(np->pci_dev, skb->tail, + pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); } /* Perhaps we need not reset this field. */ diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index dd357dd8c37..fc353e348f9 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -446,13 +446,13 @@ static void de_rx (struct de_private *de) mapping = de->rx_skb[rx_tail].mapping = - pci_map_single(de->pdev, copy_skb->tail, + pci_map_single(de->pdev, copy_skb->data, buflen, PCI_DMA_FROMDEVICE); de->rx_skb[rx_tail].skb = copy_skb; } else { pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); skb_reserve(copy_skb, RX_OFFSET); - memcpy(skb_put(copy_skb, len), skb->tail, len); + memcpy(skb_put(copy_skb, len), skb->data, len); pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); @@ -1269,7 +1269,7 @@ static int de_refill_rx (struct de_private *de) skb->dev = de->dev; de->rx_skb[i].mapping = pci_map_single(de->pdev, - skb->tail, de->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->data, de->rx_buf_sz, PCI_DMA_FROMDEVICE); de->rx_skb[i].skb = skb; de->rx_ring[i].opts1 = cpu_to_le32(DescOwn); diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 7b899702ceb..74e9075d9c4 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -945,8 +945,8 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) /* Received Packet CRC check need or not */ if ( (db->dm910x_chk_mode & 1) && - (cal_CRC(skb->tail, rxlen, 1) != - (*(u32 *) (skb->tail+rxlen) ))) { /* FIXME (?) */ + (cal_CRC(skb->data, rxlen, 1) != + (*(u32 *) (skb->data+rxlen) ))) { /* FIXME (?) */ /* Found a error received packet */ dmfe_reuse_skb(db, rxptr->rx_skb_ptr); db->dm910x_chk_mode = 3; @@ -959,7 +959,7 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) /* size less than COPY_SIZE, allocate a rxlen SKB */ skb->dev = dev; skb_reserve(skb, 2); /* 16byte align */ - memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen); + memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->data, rxlen); dmfe_reuse_skb(db, rxptr->rx_skb_ptr); } else { skb->dev = dev; @@ -1252,7 +1252,7 @@ static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb) if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) { rxptr->rx_skb_ptr = skb; - rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); db->rx_avail_cnt++; @@ -1463,7 +1463,7 @@ static void allocate_rx_buffer(struct dmfe_board_info *db) if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL ) break; rxptr->rx_skb_ptr = skb; /* FIXME (?) */ - rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); rxptr = rxptr->next_rx_desc; diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index afb5cda9d8e..bb3558164a5 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -78,7 +78,7 @@ int tulip_refill_rx(struct net_device *dev) if (skb == NULL) break; - mapping = pci_map_single(tp->pdev, skb->tail, PKT_BUF_SZ, + mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); tp->rx_buffers[entry].mapping = mapping; @@ -199,12 +199,12 @@ int tulip_poll(struct net_device *dev, int *budget) tp->rx_buffers[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) - eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, + eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data, pkt_len, 0); skb_put(skb, pkt_len); #else memcpy(skb_put(skb, pkt_len), - tp->rx_buffers[entry].skb->tail, + tp->rx_buffers[entry].skb->data, pkt_len); #endif pci_dma_sync_single_for_device(tp->pdev, @@ -423,12 +423,12 @@ static int tulip_rx(struct net_device *dev) tp->rx_buffers[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) - eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, + eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data, pkt_len, 0); skb_put(skb, pkt_len); #else memcpy(skb_put(skb, pkt_len), - tp->rx_buffers[entry].skb->tail, + tp->rx_buffers[entry].skb->data, pkt_len); #endif pci_dma_sync_single_for_device(tp->pdev, diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 08e0f80f89d..d45d8f56e5b 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -625,7 +625,7 @@ static void tulip_init_ring(struct net_device *dev) tp->rx_buffers[i].skb = skb; if (skb == NULL) break; - mapping = pci_map_single(tp->pdev, skb->tail, + mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); tp->rx_buffers[i].mapping = mapping; skb->dev = dev; /* Mark as being used by this device. */ diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index db4b32c2369..5b1af3986ab 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -849,7 +849,7 @@ static void init_rxtx_rings(struct net_device *dev) if (skb == NULL) break; skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail, + np->rx_addr[i] = pci_map_single(np->pci_dev,skb->data, skb->len,PCI_DMA_FROMDEVICE); np->rx_ring[i].buffer1 = np->rx_addr[i]; @@ -1269,7 +1269,7 @@ static int netdev_rx(struct net_device *dev) pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, @@ -1315,7 +1315,7 @@ static int netdev_rx(struct net_device *dev) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ np->rx_addr[entry] = pci_map_single(np->pci_dev, - skb->tail, + skb->data, skb->len, PCI_DMA_FROMDEVICE); np->rx_ring[entry].buffer1 = np->rx_addr[entry]; } diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c index b8a9b395c5e..887d7245fe7 100644 --- a/drivers/net/tulip/xircom_tulip_cb.c +++ b/drivers/net/tulip/xircom_tulip_cb.c @@ -899,7 +899,7 @@ static void xircom_init_ring(struct net_device *dev) break; skb->dev = dev; /* Mark as being used by this device. */ tp->rx_ring[i].status = Rx0DescOwned; /* Owned by Xircom chip */ - tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail); + tp->rx_ring[i].buffer1 = virt_to_bus(skb->data); } tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -1291,7 +1291,7 @@ xircom_rx(struct net_device *dev) if (skb == NULL) break; skb->dev = dev; /* Mark as being used by this device. */ - tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail); + tp->rx_ring[entry].buffer1 = virt_to_bus(skb->data); work_done++; } tp->rx_ring[entry].status = Rx0DescOwned; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 8f3392989a0..0b5ca253796 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1661,7 +1661,7 @@ typhoon_alloc_rx_skb(struct typhoon *tp, u32 idx) #endif skb->dev = tp->dev; - dma_addr = pci_map_single(tp->pdev, skb->tail, + dma_addr = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* Since no card does 64 bit DAC, the high bits will never @@ -1721,7 +1721,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready, pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(new_skb, skb->tail, pkt_len, 0); + eth_copy_and_sum(new_skb, skb->data, pkt_len, 0); pci_dma_sync_single_for_device(tp->pdev, dma_addr, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index be1c1047b9b..a56ef0df203 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -990,7 +990,7 @@ static void alloc_rbufs(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ rp->rx_skbuff_dma[i] = - pci_map_single(rp->pdev, skb->tail, rp->rx_buf_sz, + pci_map_single(rp->pdev, skb->data, rp->rx_buf_sz, PCI_DMA_FROMDEVICE); rp->rx_ring[i].addr = cpu_to_le32(rp->rx_skbuff_dma[i]); @@ -1518,7 +1518,7 @@ static void rhine_rx(struct net_device *dev) PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, - rp->rx_skbuff[entry]->tail, + rp->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(rp->pdev, @@ -1561,7 +1561,7 @@ static void rhine_rx(struct net_device *dev) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ rp->rx_skbuff_dma[entry] = - pci_map_single(rp->pdev, skb->tail, + pci_map_single(rp->pdev, skb->data, rp->rx_buf_sz, PCI_DMA_FROMDEVICE); rp->rx_ring[entry].addr = cpu_to_le32(rp->rx_skbuff_dma[entry]); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 15e71028349..abc5cee6eed 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1335,7 +1335,7 @@ static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) skb_reserve(new_skb, 2); - memcpy(new_skb->data, rx_skb[0]->tail, pkt_size); + memcpy(new_skb->data, rx_skb[0]->data, pkt_size); *rx_skb = new_skb; ret = 0; } @@ -1456,9 +1456,9 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) * Do the gymnastics to get the buffer head for data at * 64byte alignment. */ - skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->tail & 63); + skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63); rd_info->skb->dev = vptr->dev; - rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->tail, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); + rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); /* * Fill in the descriptor to match diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index c1b6896d700..87496843681 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -72,7 +72,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, } skb_reserve(skb, 4); cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); - data = (cisco_packet*)skb->tail; + data = (cisco_packet*)skb->data; data->type = htonl(type); data->par1 = htonl(par1); diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 9da92543010..1c2506535f7 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -786,7 +786,7 @@ static void yellowfin_init_ring(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ yp->rx_ring[i].addr = cpu_to_le32(pci_map_single(yp->pci_dev, - skb->tail, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); } yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP); yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -1111,7 +1111,7 @@ static int yellowfin_rx(struct net_device *dev) pci_dma_sync_single_for_cpu(yp->pci_dev, desc->addr, yp->rx_buf_sz, PCI_DMA_FROMDEVICE); desc_status = le32_to_cpu(desc->result_status) >> 16; - buf_addr = rx_skb->tail; + buf_addr = rx_skb->data; data_size = (le32_to_cpu(desc->dbdma_cmd) - le32_to_cpu(desc->result_status)) & 0xffff; frame_status = le16_to_cpu(get_unaligned((s16*)&(buf_addr[data_size - 2]))); @@ -1185,7 +1185,7 @@ static int yellowfin_rx(struct net_device *dev) break; skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - eth_copy_and_sum(skb, rx_skb->tail, pkt_len, 0); + eth_copy_and_sum(skb, rx_skb->data, pkt_len, 0); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(yp->pci_dev, desc->addr, yp->rx_buf_sz, @@ -1211,7 +1211,7 @@ static int yellowfin_rx(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ yp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev, - skb->tail, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); } yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP); yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */ -- cgit v1.2.3 From 12dc2fdd3e6067f5137e4a6d8af0b1a994952f52 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 28 Jun 2005 16:27:32 -0700 Subject: [NET]: drivers/net/slip.c needs linux/delay.h For msleep_interruptible(). Signed-off-by: David S. Miller --- drivers/net/slip.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 16363b5c6f5..404ea4297e3 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -74,6 +74,7 @@ #include #include #include +#include #include #include "slip.h" #ifdef CONFIG_INET -- cgit v1.2.3 From 47f176fdaf8924bc83fddcf9658f2fd3ef60d573 Mon Sep 17 00:00:00 2001 From: Luca Falavigna Date: Tue, 28 Jun 2005 20:44:42 -0700 Subject: [PATCH] Using msleep() instead of HZ Use msleep() in a few places. Signed-off-by: Luca Falavigna Acked-by: Ingo Molnar Acked-by: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/rtc.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index ff4f0980486..d8f9e94ae47 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -78,6 +78,7 @@ #include #include #include +#include #include #include @@ -894,7 +895,6 @@ static int __init rtc_init(void) struct proc_dir_entry *ent; #if defined(__alpha__) || defined(__mips__) unsigned int year, ctrl; - unsigned long uip_watchdog; char *guess = NULL; #endif #ifdef __sparc__ @@ -1000,12 +1000,8 @@ no_irq: /* Each operating system on an Alpha uses its own epoch. Let's try to guess which one we are using now. */ - uip_watchdog = jiffies; if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) { - barrier(); - cpu_relax(); - } + msleep(20); spin_lock_irq(&rtc_lock); year = CMOS_READ(RTC_YEAR); @@ -1213,7 +1209,6 @@ static int rtc_proc_open(struct inode *inode, struct file *file) void rtc_get_rtc_time(struct rtc_time *rtc_tm) { - unsigned long uip_watchdog = jiffies; unsigned char ctrl; #ifdef CONFIG_MACH_DECSTATION unsigned int real_year; @@ -1221,7 +1216,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) /* * 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 @@ -1230,10 +1225,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) */ if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) { - barrier(); - cpu_relax(); - } + msleep(20); /* * Only the values that we read from the RTC are set. We leave -- cgit v1.2.3 From 45ae36cbce9c7f55615e2b5f8faf23c7a06d0bd2 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Tue, 28 Jun 2005 20:44:44 -0700 Subject: [PATCH] drivers/char/tipar.c: off by one array access In the setup function, the delay variable is initialized with ints[2], but ints is declared as: int ints[2]; Since the module parameter should correspond to: tipar=timeout,delay I suppose that the following patch fix the problem. Signed-off-by: Luc Van Oostenryck Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tipar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 659335d80ee..ec78d2f161f 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -396,7 +396,7 @@ static struct file_operations tipar_fops = { static int __init tipar_setup(char *str) { - int ints[2]; + int ints[3]; str = get_options(str, ARRAY_SIZE(ints), ints); -- cgit v1.2.3 From b36bbb6c3d5244eaf52241ec69f79494137f2db0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 28 Jun 2005 20:44:46 -0700 Subject: [PATCH] ixp4xx/ixp2000 watchdog driver typo Fix the same typo in the ixp4xx and ixp2000 watchdog drivers. Signed-off-by: Lennert Buytenhek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/watchdog/ixp2000_wdt.c | 2 +- drivers/char/watchdog/ixp4xx_wdt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c index 4e98c215e5b..4b039516cc8 100644 --- a/drivers/char/watchdog/ixp2000_wdt.c +++ b/drivers/char/watchdog/ixp2000_wdt.c @@ -162,7 +162,7 @@ ixp2000_wdt_release(struct inode *inode, struct file *file) if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { wdt_disable(); } else { - printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - " + printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " "timer will not stop\n"); } diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c index 82396e06c8a..83df369113a 100644 --- a/drivers/char/watchdog/ixp4xx_wdt.c +++ b/drivers/char/watchdog/ixp4xx_wdt.c @@ -156,7 +156,7 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file) if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { wdt_disable(); } else { - printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - " + printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " "timer will not stop\n"); } -- cgit v1.2.3 From bcc8ca09920755520ba8a1e2d9f72fe8ff892643 Mon Sep 17 00:00:00 2001 From: Emmanuel Colbus Date: Tue, 28 Jun 2005 20:44:49 -0700 Subject: [PATCH] Adapt drivers/char/vt_ioctl.c to non-x86 This code uses the x86 (non-AMD-ELAN) value of CLOCK_TICK_RATE instead of CLOCK_TICK_RATE itself, which is wrong for other archs. Signed-off-by: Emmanuel Colbus Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/vt_ioctl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 8971484b956..1d44f69e1fd 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -386,7 +387,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (!perm) return -EPERM; if (arg) - arg = 1193182 / arg; + arg = CLOCK_TICK_RATE / arg; kd_mksound(arg, 0); return 0; @@ -403,7 +404,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ticks = HZ * ((arg >> 16) & 0xffff) / 1000; count = ticks ? (arg & 0xffff) : 0; if (count) - count = 1193182 / count; + count = CLOCK_TICK_RATE / count; kd_mksound(count, ticks); return 0; } -- cgit v1.2.3 From b92eac01c3c6ad5dab5c74d3bc32ac8e9bf4dae7 Mon Sep 17 00:00:00 2001 From: "Stanislaw W. Gruszka" Date: Tue, 28 Jun 2005 20:44:51 -0700 Subject: [PATCH] request_firmware(): avoid race conditions Avoid race occurs when some process have open file descriptor for class device attributes and already firmware allocated memory are freed. Don't allow negative loading timeout. Signed-off-by: Stanislaw W. Gruszka Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/firmware_class.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 97fe13f7f07..652281402c9 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -74,6 +74,8 @@ static ssize_t firmware_timeout_store(struct class *class, const char *buf, size_t count) { loading_timeout = simple_strtol(buf, NULL, 10); + if (loading_timeout < 0) + loading_timeout = 0; return count; } @@ -138,6 +140,10 @@ firmware_loading_store(struct class_device *class_dev, switch (loading) { case 1: down(&fw_lock); + if (!fw_priv->fw) { + up(&fw_lock); + break; + } vfree(fw_priv->fw->data); fw_priv->fw->data = NULL; fw_priv->fw->size = 0; @@ -178,7 +184,7 @@ firmware_data_read(struct kobject *kobj, down(&fw_lock); fw = fw_priv->fw; - if (test_bit(FW_STATUS_DONE, &fw_priv->status)) { + if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { ret_count = -ENODEV; goto out; } @@ -238,9 +244,10 @@ firmware_data_write(struct kobject *kobj, if (!capable(CAP_SYS_RAWIO)) return -EPERM; + down(&fw_lock); fw = fw_priv->fw; - if (test_bit(FW_STATUS_DONE, &fw_priv->status)) { + if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { retval = -ENODEV; goto out; } @@ -418,7 +425,7 @@ request_firmware(const struct firmware **firmware_p, const char *name, fw_priv = class_get_devdata(class_dev); - if (loading_timeout) { + if (loading_timeout > 0) { fw_priv->timeout.expires = jiffies + loading_timeout * HZ; add_timer(&fw_priv->timeout); } -- cgit v1.2.3 From b79646e3dd51b389b2a570b454f8e2fb7a613e37 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 28 Jun 2005 20:44:53 -0700 Subject: [PATCH] hisax warning fixes drivers/isdn/hisax/hfc4s8s_l1.c:317: warning: type qualifiers ignored on function return type drivers/isdn/hisax/hfc4s8s_l1.c:329: warning: type qualifiers ignored on function return type Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/hisax/hfc4s8s_l1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index 6e7e060716b..5cbcfa99fc6 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -312,7 +312,7 @@ wait_busy(hfc4s8s_hw * a) /* function to read critical counter registers that */ /* may be udpated by the chip during read */ /******************************************************/ -static volatile u_char +static u_char Read_hfc8_stable(hfc4s8s_hw * hw, int reg) { u_char ref8; @@ -324,7 +324,7 @@ Read_hfc8_stable(hfc4s8s_hw * hw, int reg) return in8; } -static volatile int +static int Read_hfc16_stable(hfc4s8s_hw * hw, int reg) { int ref16; -- cgit v1.2.3 From aade0e82739f4b24c5b952de68c8d794459ad531 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 28 Jun 2005 20:44:56 -0700 Subject: [PATCH] drivers/isdn/: make some code static This patch makes some needlessly global code static. Signed-off-by: Adrian Bunk Signed-off-by: Armin Schindler Signed-off-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/hardware/eicon/dadapter.c | 2 +- drivers/isdn/hisax/hfc4s8s_l1.c | 4 ++-- drivers/isdn/hysdn/hycapi.c | 20 +++++++++++--------- drivers/isdn/hysdn/hysdn_boot.c | 4 ++-- drivers/isdn/hysdn/hysdn_defs.h | 12 ------------ drivers/isdn/hysdn/hysdn_init.c | 2 +- drivers/isdn/hysdn/hysdn_proclog.c | 4 +++- 7 files changed, 20 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/eicon/dadapter.c b/drivers/isdn/hardware/eicon/dadapter.c index 6e548a222ef..89497890158 100644 --- a/drivers/isdn/hardware/eicon/dadapter.c +++ b/drivers/isdn/hardware/eicon/dadapter.c @@ -44,7 +44,7 @@ static didd_adapter_change_notification_t\ Array to held adapter information -------------------------------------------------------------------------- */ static DESCRIPTOR HandleTable[NEW_MAX_DESCRIPTORS]; -dword Adapters = 0; /* Number of adapters */ +static dword Adapters = 0; /* Number of adapters */ /* -------------------------------------------------------------------------- Shadow IDI_DIMAINT and 'shadow' debug stuff diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index 5cbcfa99fc6..7333377ab31 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -1465,7 +1465,7 @@ hfc_hardware_enable(hfc4s8s_hw * hw, int enable, int nt_mode) /******************************************/ /* disable memory mapped ports / io ports */ /******************************************/ -void +static void release_pci_ports(hfc4s8s_hw * hw) { pci_write_config_word(hw->pdev, PCI_COMMAND, 0); @@ -1481,7 +1481,7 @@ release_pci_ports(hfc4s8s_hw * hw) /*****************************************/ /* enable memory mapped ports / io ports */ /*****************************************/ -void +static void enable_pci_ports(hfc4s8s_hw * hw) { #ifdef CONFIG_HISAX_HFC4S8S_PCIMEM diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index 8ee25b2ccce..1fd3d4e5f28 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -42,6 +42,8 @@ typedef struct _hycapi_appl { static hycapi_appl hycapi_applications[CAPI_MAXAPPL]; +static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); + static inline int _hycapi_appCheck(int app_id, int ctrl_no) { if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) || @@ -57,7 +59,7 @@ static inline int _hycapi_appCheck(int app_id, int ctrl_no) Kernel-Capi callback reset_ctr ******************************/ -void +static void hycapi_reset_ctr(struct capi_ctr *ctrl) { hycapictrl_info *cinfo = ctrl->driverdata; @@ -73,7 +75,7 @@ hycapi_reset_ctr(struct capi_ctr *ctrl) Kernel-Capi callback remove_ctr ******************************/ -void +static void hycapi_remove_ctr(struct capi_ctr *ctrl) { int i; @@ -215,7 +217,7 @@ Error-checking is done for CAPI-compliance. The application is recorded in the internal list. *************************************************************/ -void +static void hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) { @@ -291,7 +293,7 @@ Release the application from the internal list an remove it's registration at controller-level ******************************************************************/ -void +static void hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl) { int chk; @@ -364,7 +366,7 @@ firmware-releases that do not check the MsgLen-Indication! ***************************************************************/ -u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) { __u16 appl_id; int _len, _len2; @@ -437,8 +439,8 @@ Informations provided in the /proc/capi-entries. *********************************************************************/ -int hycapi_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctrl) +static int hycapi_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl) { hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); hysdn_card *card = cinfo->card; @@ -485,7 +487,7 @@ on capi-interface registration. **************************************************************/ -int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +static int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) { #ifdef HYCAPI_PRINTFNAMES printk(KERN_NOTICE "hycapi_load_firmware\n"); @@ -494,7 +496,7 @@ int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) } -char *hycapi_procinfo(struct capi_ctr *ctrl) +static char *hycapi_procinfo(struct capi_ctr *ctrl) { hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); #ifdef HYCAPI_PRINTFNAMES diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c index 6c04281e57b..7bfba196f31 100644 --- a/drivers/isdn/hysdn/hysdn_boot.c +++ b/drivers/isdn/hysdn/hysdn_boot.c @@ -53,7 +53,7 @@ struct boot_data { /* to be called at start of POF file reading, */ /* before starting any decryption on any POF record. */ /*****************************************************/ -void +static void StartDecryption(struct boot_data *boot) { boot->Cryptor = CRYPT_STARTTERM; @@ -66,7 +66,7 @@ StartDecryption(struct boot_data *boot) /* to HI and LO boot loader and (all) seq tags, because */ /* global Cryptor is started for whole POF. */ /***************************************************************/ -void +static void DecryptBuf(struct boot_data *boot, int cnt) { uchar *bufp = boot->buf.BootBuf; diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h index 4cee26e558e..432f6f99089 100644 --- a/drivers/isdn/hysdn/hysdn_defs.h +++ b/drivers/isdn/hysdn/hysdn_defs.h @@ -227,7 +227,6 @@ typedef struct hycapictrl_info hycapictrl_info; /*****************/ /* exported vars */ /*****************/ -extern int cardmax; /* number of found cards */ extern hysdn_card *card_root; /* pointer to first card */ @@ -244,7 +243,6 @@ extern void hysdn_procconf_release(void); /* deinit proc config filesys */ /* hysdn_proclog.c */ extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */ extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */ -extern void put_log_buffer(hysdn_card *, char *); /* output log data */ extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */ extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */ @@ -278,16 +276,6 @@ extern unsigned int hycapi_enable; extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */ extern int hycapi_capi_release(hysdn_card *); /* delete the device */ extern int hycapi_capi_stop(hysdn_card *card); /* suspend */ -extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *); -extern void hycapi_reset_ctr(struct capi_ctr *); -extern void hycapi_remove_ctr(struct capi_ctr *); -extern void hycapi_register_appl(struct capi_ctr *, __u16 appl, - capi_register_params *); -extern void hycapi_release_appl(struct capi_ctr *, __u16 appl); -extern u16 hycapi_send_message(struct capi_ctr *, struct sk_buff *skb); -extern char *hycapi_procinfo(struct capi_ctr *); -extern int hycapi_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *card); extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len); extern void hycapi_tx_capiack(hysdn_card * card); extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card); diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c index 5cac2bf5f4b..12c8137b516 100644 --- a/drivers/isdn/hysdn/hysdn_init.c +++ b/drivers/isdn/hysdn/hysdn_init.c @@ -34,7 +34,7 @@ MODULE_AUTHOR("Werner Cornelius"); MODULE_LICENSE("GPL"); static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; -int cardmax; /* number of found cards */ +static int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ /**********************************************/ diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 8ef2b7c952a..4d57011c573 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -22,6 +22,8 @@ /* the proc subdir for the interface is defined in the procconf module */ extern struct proc_dir_entry *hysdn_proc_entry; +static void put_log_buffer(hysdn_card * card, char *cp); + /*************************************************/ /* structure keeping ascii log for device output */ /*************************************************/ @@ -93,7 +95,7 @@ hysdn_addlog(hysdn_card * card, char *fmt,...) /* opened for read got the contents. */ /* Flushes buffers not longer in use. */ /********************************************/ -void +static void put_log_buffer(hysdn_card * card, char *cp) { struct log_data *ib; -- cgit v1.2.3 From a77e3362a224212d9d3b9e6fdec44df2eef6cf92 Mon Sep 17 00:00:00 2001 From: "KAMBAROV, ZAUR" Date: Tue, 28 Jun 2005 20:45:06 -0700 Subject: [PATCH] coverity: i386: scsi_lib buffer overrun fix The check in 627 BUG_ON(index > SG_MEMPOOL_NR); with SG_MEMPOOL_NR defined in 32 #define SG_MEMPOOL_NR (sizeof(scsi_sg_pools)/sizeof(struct scsi_host_sg_pool)) was not sufficient. sgp, set in 629 sgp = scsi_sg_pools + index; is dereferenced in 630 mempool_free(sgl, sgp->pool); Signed-off-by: Zaur Kambarov Cc: Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/scsi_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 621dee8b8cb..10506f9cd0c 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -632,7 +632,7 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index) { struct scsi_host_sg_pool *sgp; - BUG_ON(index > SG_MEMPOOL_NR); + BUG_ON(index >= SG_MEMPOOL_NR); sgp = scsi_sg_pools + index; mempool_free(sgl, sgp->pool); -- cgit v1.2.3 From 9c101fd439dab60d6eba76afb35fd2696f42c63d Mon Sep 17 00:00:00 2001 From: "KAMBAROV, ZAUR" Date: Tue, 28 Jun 2005 20:45:08 -0700 Subject: [PATCH] coverity: ipmi_msghandler() channels array overrun fix We fix the check in 1084, which was 1084 if (addr->channel > IPMI_NUM_CHANNELS) { 1085 spin_lock_irqsave(&intf->counter_lock, flags); 1086 intf->sent_invalid_commands++; 1087 spin_unlock_irqrestore(&intf->counter_lock, flags); 1088 rv = -EINVAL; 1089 goto out_err; 1090 } addr->channel is used in 1092 if (intf->channels[addr->channel].medium Definitions involved: 221 struct ipmi_channel channels[IPMI_MAX_CHANNELS]; 134 #define IPMI_MAX_CHANNELS 8 In /linux-2.6.12-rc6/include/linux/ipmi.h 148 #define IPMI_NUM_CHANNELS 0x10 Signed-off-by: Zaur Kambarov Cc: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_msghandler.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 1813d0d198f..e16c13fe698 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -1088,8 +1088,8 @@ static inline int i_ipmi_request(ipmi_user_t user, long seqid; int broadcast = 0; - if (addr->channel > IPMI_NUM_CHANNELS) { - spin_lock_irqsave(&intf->counter_lock, flags); + if (addr->channel >= IPMI_MAX_CHANNELS) { + spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); rv = -EINVAL; -- cgit v1.2.3 From 69f63c5c34d0b34ee2cbf10c5ff7fcff0404879e Mon Sep 17 00:00:00 2001 From: "KAMBAROV, ZAUR" Date: Tue, 28 Jun 2005 20:45:12 -0700 Subject: [PATCH] coverity: tty_ldisc_ref return null check We add a check of the return value of tty_ldisc_ref(), which is checked 7 out of 8 times, e.g.: 149 ld = tty_ldisc_ref(tty); 150 if (ld != NULL) { 151 if (ld->set_termios) 152 (ld->set_termios)(tty, &old_termios); 153 tty_ldisc_deref(ld); 154 } This defect was found automatically by Coverity Prevent, a static analysis tool. (akpm: presumably `ld' is never NULL. Oh well) Signed-off-by: Zaur Kambarov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_ioctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 58597993954..f19cf9d7792 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -476,11 +476,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, ld = tty_ldisc_ref(tty); switch (arg) { case TCIFLUSH: - if (ld->flush_buffer) + if (ld && ld->flush_buffer) ld->flush_buffer(tty); break; case TCIOFLUSH: - if (ld->flush_buffer) + if (ld && ld->flush_buffer) ld->flush_buffer(tty); /* fall through */ case TCOFLUSH: -- cgit v1.2.3 From 450991bc1026135ee30482a4a806d069915ab2f6 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Tue, 28 Jun 2005 20:45:13 -0700 Subject: [PATCH] blk: __make_request efficiency In the case where the request is not able to be merged by the elevator, don't retake the lock and retry the merge mechanism after allocating a new request. Instead assume that the chance of a merge remains slim, and now that we've done most of the work allocating a request we may as well just go with it. Also be rid of the GFP_ATOMIC allocation: we've got working mempools for the block layer now, so let's save atomic memory for things like networking. Lastly, in get_request_wait, do an initial get_request call before going into the waitqueue. This is reported to help efficiency. Signed-off-by: Nick Piggin Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/ll_rw_blk.c | 62 ++++++++++++++++------------------------------- 1 file changed, 21 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 6c98cf04271..67431f28015 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1971,10 +1971,11 @@ out: static struct request *get_request_wait(request_queue_t *q, int rw, struct bio *bio) { - DEFINE_WAIT(wait); struct request *rq; - do { + rq = get_request(q, rw, bio, GFP_NOIO); + while (!rq) { + DEFINE_WAIT(wait); struct request_list *rl = &q->rq; prepare_to_wait_exclusive(&rl->wait[rw], &wait, @@ -1999,7 +2000,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw, put_io_context(ioc); } finish_wait(&rl->wait[rw], &wait); - } while (!rq); + } return rq; } @@ -2521,7 +2522,7 @@ EXPORT_SYMBOL(blk_attempt_remerge); static int __make_request(request_queue_t *q, struct bio *bio) { - struct request *req, *freereq = NULL; + struct request *req; int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync; unsigned short prio; sector_t sector; @@ -2549,14 +2550,9 @@ static int __make_request(request_queue_t *q, struct bio *bio) goto end_io; } -again: spin_lock_irq(q->queue_lock); - if (elv_queue_empty(q)) { - blk_plug_device(q); - goto get_rq; - } - if (barrier) + if (unlikely(barrier) || elv_queue_empty(q)) goto get_rq; el_ret = elv_merge(q, &req, bio); @@ -2601,40 +2597,23 @@ again: elv_merged_request(q, req); goto out; - /* - * elevator says don't/can't merge. get new request - */ - case ELEVATOR_NO_MERGE: - break; - + /* ELV_NO_MERGE: elevator says don't/can't merge. */ default: - printk("elevator returned crap (%d)\n", el_ret); - BUG(); + ; } +get_rq: /* - * Grab a free request from the freelist - if that is empty, check - * if we are doing read ahead and abort instead of blocking for - * a free slot. + * Grab a free request. This is might sleep but can not fail. + */ + spin_unlock_irq(q->queue_lock); + req = get_request_wait(q, rw, bio); + /* + * After dropping the lock and possibly sleeping here, our request + * may now be mergeable after it had proven unmergeable (above). + * We don't worry about that case for efficiency. It won't happen + * often, and the elevators are able to handle it. */ -get_rq: - if (freereq) { - req = freereq; - freereq = NULL; - } else { - spin_unlock_irq(q->queue_lock); - if ((freereq = get_request(q, rw, bio, GFP_ATOMIC)) == NULL) { - /* - * READA bit set - */ - err = -EWOULDBLOCK; - if (bio_rw_ahead(bio)) - goto end_io; - - freereq = get_request_wait(q, rw, bio); - } - goto again; - } req->flags |= REQ_CMD; @@ -2663,10 +2642,11 @@ get_rq: req->rq_disk = bio->bi_bdev->bd_disk; req->start_time = jiffies; + spin_lock_irq(q->queue_lock); + if (elv_queue_empty(q)) + blk_plug_device(q); add_request(q, req); out: - if (freereq) - __blk_put_request(q, freereq); if (sync) __generic_unplug_device(q); -- cgit v1.2.3 From d6344532a26a318c128102507f6328aaafe02d4d Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Tue, 28 Jun 2005 20:45:14 -0700 Subject: [PATCH] blk: reduce locking Change around locking a bit for a result of 1-2 less spin lock unlock pairs in request submission paths. Signed-off-by: Nick Piggin Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/ll_rw_blk.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 67431f28015..5caebe2cf0a 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1867,19 +1867,20 @@ static void freed_request(request_queue_t *q, int rw) #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist) /* - * Get a free request, queue_lock must not be held + * Get a free request, queue_lock must be held. + * Returns NULL on failure, with queue_lock held. + * Returns !NULL on success, with queue_lock *not held*. */ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask) { struct request *rq = NULL; struct request_list *rl = &q->rq; - struct io_context *ioc = get_io_context(gfp_mask); + struct io_context *ioc = get_io_context(GFP_ATOMIC); if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) goto out; - spin_lock_irq(q->queue_lock); if (rl->count[rw]+1 >= q->nr_requests) { /* * The queue will fill after this allocation, so set it as @@ -1907,7 +1908,6 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, * The queue is full and the allocating process is not a * "batcher", and not exempted by the IO scheduler */ - spin_unlock_irq(q->queue_lock); goto out; } @@ -1950,7 +1950,6 @@ rq_starved: if (unlikely(rl->count[rw] == 0)) rl->starved[rw] = 1; - spin_unlock_irq(q->queue_lock); goto out; } @@ -1967,6 +1966,8 @@ out: /* * No available requests for this queue, unplug the device and wait for some * requests to become available. + * + * Called with q->queue_lock held, and returns with it unlocked. */ static struct request *get_request_wait(request_queue_t *q, int rw, struct bio *bio) @@ -1986,7 +1987,8 @@ static struct request *get_request_wait(request_queue_t *q, int rw, if (!rq) { struct io_context *ioc; - generic_unplug_device(q); + __generic_unplug_device(q); + spin_unlock_irq(q->queue_lock); io_schedule(); /* @@ -1998,6 +2000,8 @@ static struct request *get_request_wait(request_queue_t *q, int rw, ioc = get_io_context(GFP_NOIO); ioc_set_batching(q, ioc); put_io_context(ioc); + + spin_lock_irq(q->queue_lock); } finish_wait(&rl->wait[rw], &wait); } @@ -2011,14 +2015,18 @@ struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask) BUG_ON(rw != READ && rw != WRITE); - if (gfp_mask & __GFP_WAIT) + spin_lock_irq(q->queue_lock); + if (gfp_mask & __GFP_WAIT) { rq = get_request_wait(q, rw, NULL); - else + } else { rq = get_request(q, rw, NULL, gfp_mask); + if (!rq) + spin_unlock_irq(q->queue_lock); + } + /* q->queue_lock is unlocked at this point */ return rq; } - EXPORT_SYMBOL(blk_get_request); /** @@ -2605,9 +2613,10 @@ static int __make_request(request_queue_t *q, struct bio *bio) get_rq: /* * Grab a free request. This is might sleep but can not fail. + * Returns with the queue unlocked. */ - spin_unlock_irq(q->queue_lock); req = get_request_wait(q, rw, bio); + /* * After dropping the lock and possibly sleeping here, our request * may now be mergeable after it had proven unmergeable (above). -- cgit v1.2.3 From fb3cc4320e1fd87143683b540e459a2e20fdc9bb Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Tue, 28 Jun 2005 20:45:15 -0700 Subject: [PATCH] blk: light iocontext ops get_io_context needlessly turned off interrupts and checked for racing io context creations. Both of which aren't needed, because the io context can only be created while in process context of the current process. Also, split the function in 2. A light version, current_io_context does not elevate the reference count specifically, but can be used when in process context, because the process holds a reference itself. Signed-off-by: Nick Piggin Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/ll_rw_blk.c | 56 +++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 5caebe2cf0a..1197462bb6b 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1876,7 +1876,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, { struct request *rq = NULL; struct request_list *rl = &q->rq; - struct io_context *ioc = get_io_context(GFP_ATOMIC); + struct io_context *ioc = current_io_context(GFP_ATOMIC); if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) goto out; @@ -1959,7 +1959,6 @@ rq_starved: rq_init(q, rq); rq->rl = rl; out: - put_io_context(ioc); return rq; } @@ -1997,9 +1996,8 @@ static struct request *get_request_wait(request_queue_t *q, int rw, * up to a big batch of them for a small period time. * See ioc_batching, ioc_set_batching */ - ioc = get_io_context(GFP_NOIO); + ioc = current_io_context(GFP_NOIO); ioc_set_batching(q, ioc); - put_io_context(ioc); spin_lock_irq(q->queue_lock); } @@ -3282,24 +3280,20 @@ void exit_io_context(void) /* * If the current task has no IO context then create one and initialise it. - * If it does have a context, take a ref on it. + * Otherwise, return its existing IO context. * - * This is always called in the context of the task which submitted the I/O. - * But weird things happen, so we disable local interrupts to ensure exclusive - * access to *current. + * This returned IO context doesn't have a specifically elevated refcount, + * but since the current task itself holds a reference, the context can be + * used in general code, so long as it stays within `current` context. */ -struct io_context *get_io_context(int gfp_flags) +struct io_context *current_io_context(int gfp_flags) { struct task_struct *tsk = current; - unsigned long flags; struct io_context *ret; - local_irq_save(flags); ret = tsk->io_context; - if (ret) - goto out; - - local_irq_restore(flags); + if (likely(ret)) + return ret; ret = kmem_cache_alloc(iocontext_cachep, gfp_flags); if (ret) { @@ -3310,25 +3304,25 @@ struct io_context *get_io_context(int gfp_flags) ret->nr_batch_requests = 0; /* because this is 0 */ ret->aic = NULL; ret->cic = NULL; + tsk->io_context = ret; + } - local_irq_save(flags); - - /* - * very unlikely, someone raced with us in setting up the task - * io context. free new context and just grab a reference. - */ - if (!tsk->io_context) - tsk->io_context = ret; - else { - kmem_cache_free(iocontext_cachep, ret); - ret = tsk->io_context; - } + return ret; +} +EXPORT_SYMBOL(current_io_context); -out: +/* + * If the current task has no IO context then create one and initialise it. + * If it does have a context, take a ref on it. + * + * This is always called in the context of the task which submitted the I/O. + */ +struct io_context *get_io_context(int gfp_flags) +{ + struct io_context *ret; + ret = current_io_context(gfp_flags); + if (likely(ret)) atomic_inc(&ret->refcount); - local_irq_restore(flags); - } - return ret; } EXPORT_SYMBOL(get_io_context); -- cgit v1.2.3 From 586b0cab2516640fec4dffc3049c4d8bca188f89 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 28 Jun 2005 20:45:21 -0700 Subject: [PATCH] v4l: tuner improvements *tuner-core.c: - some tuner_info msgs will be generated only if insmod opt tuner_debug enabled. - Implemented tuner-core support for VIDIO_S_TUNER to allow changing mono/stereo mode - Remove unneeded config options. - I2C_CLIENT_MULTI option removed. - support for Philips FMD12ME hybrid tuner - allow to initialize with another tuner - Move PHILIPS_FMD initialization code to set_type function, * tda8290: - Fix dumb error in tda8290 tunning. - Radio tuner uses high-precision step instead of 62.5 KHz. *tea5767.c: - tuner_info msgs will be generated only if insmod tuner option tuner_debug enabled. - some cleanups for better reading. - Radio tuner uses high-precision step instead of 62.5 KHz. - Changing radio mode stereo/mono for tea5767 working. *tuner-simple.c: - TNF9533-D/IF UHF fixup. - Radio tuners now uses high-precision step instead of 62.5 KHz. *mt20xx.c: - Radio tuner uses high-precision step instead of 62.5 KHz. *tda9887.c: - tab and blank spaces corrections. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Gerd Knorr Signed-off-by: Nickolay V Shmyrev Signed-off-by: Hartmut Hackmann Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/Makefile | 3 +- drivers/media/video/mt20xx.c | 6 +- drivers/media/video/tda8290.c | 20 ++- drivers/media/video/tda9887.c | 7 +- drivers/media/video/tea5767.c | 334 +++++++++++++++++++++++++++++++++++++ drivers/media/video/tuner-core.c | 163 +++++++++--------- drivers/media/video/tuner-simple.c | 34 ++-- 7 files changed, 457 insertions(+), 110 deletions(-) create mode 100644 drivers/media/video/tea5767.c (limited to 'drivers') diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 2dc906fdfa5..810e7aac0a5 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -7,8 +7,7 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o -tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o - +tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 95ad17b7f38..9c005cb128d 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -1,5 +1,5 @@ /* - * $Id: mt20xx.c,v 1.4 2005/03/04 09:24:56 kraxel Exp $ + * $Id: mt20xx.c,v 1.5 2005/06/16 08:29:49 nsh Exp $ * * i2c tv tuner chip device driver * controls microtune tuners, mt2032 + mt2050 at the moment. @@ -295,8 +295,8 @@ static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) int if2 = t->radio_if2; // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, - 1085*1000*1000,if2,if2,if2); + mt2032_set_if_freq(c, freq * 1000 / 16, + 1085*1000*1000,if2,if2,if2); } // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index b27cc348d95..f59d4601cc6 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -1,5 +1,5 @@ /* - * $Id: tda8290.c,v 1.7 2005/03/07 12:01:51 kraxel Exp $ + * $Id: tda8290.c,v 1.11 2005/06/18 06:09:06 nsh Exp $ * * i2c tv tuner chip device driver * controls the philips tda8290+75 tuner chip combo. @@ -69,7 +69,7 @@ static __u8 get_freq_entry( struct freq_entry* table, __u16 freq) static unsigned char i2c_enable_bridge[2] = { 0x21, 0xC0 }; static unsigned char i2c_disable_bridge[2] = { 0x21, 0x80 }; static unsigned char i2c_init_tda8275[14] = { 0x00, 0x00, 0x00, 0x00, - 0x7C, 0x04, 0xA3, 0x3F, + 0xfC, 0x04, 0xA3, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; static unsigned char i2c_set_VS[2] = { 0x30, 0x6F }; @@ -138,16 +138,24 @@ static int tda8290_tune(struct i2c_client *c) static void set_frequency(struct tuner *t, u16 ifc) { - u32 N = (((t->freq<<3)+ifc)&0x3fffc); + u32 freq; + u32 N; - N = N >> get_freq_entry(div_table, t->freq); + if (t->mode == V4L2_TUNER_RADIO) + freq = t->freq / 1000; + else + freq = t->freq; + + N = (((freq<<3)+ifc)&0x3fffc); + + N = N >> get_freq_entry(div_table, freq); t->i2c_set_freq[0] = 0; t->i2c_set_freq[1] = (unsigned char)(N>>8); t->i2c_set_freq[2] = (unsigned char) N; t->i2c_set_freq[3] = 0x40; t->i2c_set_freq[4] = 0x52; - t->i2c_set_freq[5] = get_freq_entry(band_table, t->freq); - t->i2c_set_freq[6] = get_freq_entry(agc_table, t->freq); + t->i2c_set_freq[5] = get_freq_entry(band_table, freq); + t->i2c_set_freq[6] = get_freq_entry(agc_table, freq); t->i2c_set_freq[7] = 0x8f; } diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 39773633cc3..ee35562f4d1 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -368,7 +368,7 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) if (t->radio_mode == V4L2_TUNER_MODE_MONO) norm = &radio_mono; else - norm = &radio_stereo; + norm = &radio_stereo; } else { for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { if (tvnorms[i].std & t->std) { @@ -566,7 +566,6 @@ static int tda9887_configure(struct tda9887 *t) if (UNSET != t->pinnacle_id) { tda9887_set_pinnacle(t,buf); } - tda9887_set_config(t,buf); tda9887_set_insmod(t,buf); @@ -615,8 +614,8 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind) t->pinnacle_id = UNSET; t->radio_mode = V4L2_TUNER_MODE_STEREO; - i2c_set_clientdata(&t->client, t); - i2c_attach_client(&t->client); + i2c_set_clientdata(&t->client, t); + i2c_attach_client(&t->client); return 0; } diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c new file mode 100644 index 00000000000..a29f08f81f6 --- /dev/null +++ b/drivers/media/video/tea5767.c @@ -0,0 +1,334 @@ +/* + * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview + * I2C address is allways 0xC0. + * + * $Id: tea5767.c,v 1.11 2005/06/21 15:40:33 mchehab Exp $ + * + * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br) + * This code is placed under the terms of the GNU General Public License + * + * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa + * from their contributions on DScaler. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Declared at tuner-core.c */ +extern unsigned int tuner_debug; + +#define PREFIX "TEA5767 " + +/*****************************************************************************/ + +/****************************** + * Write mode register values * + ******************************/ + +/* First register */ +#define TEA5767_MUTE 0x80 /* Mutes output */ +#define TEA5767_SEARCH 0x40 /* Activates station search */ +/* Bits 0-5 for divider MSB */ + +/* Second register */ +/* Bits 0-7 for divider LSB */ + +/* Third register */ + +/* Station search from botton to up */ +#define TEA5767_SEARCH_UP 0x80 + +/* Searches with ADC output = 10 */ +#define TEA5767_SRCH_HIGH_LVL 0x60 + +/* Searches with ADC output = 10 */ +#define TEA5767_SRCH_MID_LVL 0x40 + +/* Searches with ADC output = 5 */ +#define TEA5767_SRCH_LOW_LVL 0x20 + +/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */ +#define TEA5767_HIGH_LO_INJECT 0x10 + +/* Disable stereo */ +#define TEA5767_MONO 0x08 + +/* Disable right channel and turns to mono */ +#define TEA5767_MUTE_RIGHT 0x04 + +/* Disable left channel and turns to mono */ +#define TEA5767_MUTE_LEFT 0x02 + +#define TEA5767_PORT1_HIGH 0x01 + +/* Forth register */ +#define TEA5767_PORT2_HIGH 0x80 +/* Chips stops working. Only I2C bus remains on */ +#define TEA5767_STDBY 0x40 + +/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */ +#define TEA5767_JAPAN_BAND 0x20 + +/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */ +#define TEA5767_XTAL_32768 0x10 + +/* Cuts weak signals */ +#define TEA5767_SOFT_MUTE 0x08 + +/* Activates high cut control */ +#define TEA5767_HIGH_CUT_CTRL 0x04 + +/* Activates stereo noise control */ +#define TEA5767_ST_NOISE_CTL 0x02 + +/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ +#define TEA5767_SRCH_IND 0x01 + +/* Fiveth register */ + +/* By activating, it will use Xtal at 13 MHz as reference for divider */ +#define TEA5767_PLLREF_ENABLE 0x80 + +/* By activating, deemphasis=50, or else, deemphasis of 50us */ +#define TEA5767_DEEMPH_75 0X40 + +/***************************** + * Read mode register values * + *****************************/ + +/* First register */ +#define TEA5767_READY_FLAG_MASK 0x80 +#define TEA5767_BAND_LIMIT_MASK 0X40 +/* Bits 0-5 for divider MSB after search or preset */ + +/* Second register */ +/* Bits 0-7 for divider LSB after search or preset */ + +/* Third register */ +#define TEA5767_STEREO_MASK 0x80 +#define TEA5767_IF_CNTR_MASK 0x7f + +/* Four register */ +#define TEA5767_ADC_LEVEL_MASK 0xf0 + +/* should be 0 */ +#define TEA5767_CHIP_ID_MASK 0x0f + +/* Fiveth register */ +/* Reserved for future extensions */ +#define TEA5767_RESERVED_MASK 0xff + +/*****************************************************************************/ + +static void set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + + tuner_warn("This tuner doesn't support TV freq.\n"); +} + +static void tea5767_status_dump(unsigned char *buffer) +{ + unsigned int div, frq; + + if (TEA5767_READY_FLAG_MASK & buffer[0]) + printk(PREFIX "Ready Flag ON\n"); + else + printk(PREFIX "Ready Flag OFF\n"); + + if (TEA5767_BAND_LIMIT_MASK & buffer[0]) + printk(PREFIX "Tuner at band limit\n"); + else + printk(PREFIX "Tuner not at band limit\n"); + + div=((buffer[0]&0x3f)<<8) | buffer[1]; + + switch (TEA5767_HIGH_LO_32768) { + case TEA5767_HIGH_LO_13MHz: + frq = 1000*(div*50-700-225)/4; /* Freq in KHz */ + break; + case TEA5767_LOW_LO_13MHz: + frq = 1000*(div*50+700+225)/4; /* Freq in KHz */ + break; + case TEA5767_LOW_LO_32768: + frq = 1000*(div*32768/1000+700+225)/4; /* Freq in KHz */ + break; + case TEA5767_HIGH_LO_32768: + default: + frq = 1000*(div*32768/1000-700-225)/4; /* Freq in KHz */ + break; + } + buffer[0] = (div>>8) & 0x3f; + buffer[1] = div & 0xff; + + printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n", + frq/1000,frq%1000,div); + + if (TEA5767_STEREO_MASK & buffer[2]) + printk(PREFIX "Stereo\n"); + else + printk(PREFIX "Mono\n"); + + printk(PREFIX "IF Counter = %d\n",buffer[2] & TEA5767_IF_CNTR_MASK); + + printk(PREFIX "ADC Level = %d\n",(buffer[3] & TEA5767_ADC_LEVEL_MASK)>>4); + + printk(PREFIX "Chip ID = %d\n",(buffer[3] & TEA5767_CHIP_ID_MASK)); + + printk(PREFIX "Reserved = 0x%02x\n",(buffer[4] & TEA5767_RESERVED_MASK)); +} + +/* Freq should be specifyed at 62.5 Hz */ +static void set_radio_freq(struct i2c_client *c, unsigned int frq) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buffer[5]; + unsigned div; + int rc; + + if ( tuner_debug ) + printk(PREFIX "radio freq counter %d\n",frq); + + /* Rounds freq to next decimal value - for 62.5 KHz step */ + /* frq = 20*(frq/16)+radio_frq[frq%16]; */ + + buffer[2] = TEA5767_PORT1_HIGH; + buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; + buffer[4]=0; + + if (t->audmode == V4L2_TUNER_MODE_MONO) { + tuner_dbg("TEA5767 set to mono\n"); + buffer[2] |= TEA5767_MONO; + } else + tuner_dbg("TEA5767 set to stereo\n"); + + switch (t->type) { + case TEA5767_HIGH_LO_13MHz: + tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); + buffer[2] |= TEA5767_HIGH_LO_INJECT; + buffer[4] |= TEA5767_PLLREF_ENABLE; + div = (frq*4/16+700+225+25)/50; + break; + case TEA5767_LOW_LO_13MHz: + tuner_dbg("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); + + buffer[4] |= TEA5767_PLLREF_ENABLE; + div = (frq*4/16-700-225+25)/50; + break; + case TEA5767_LOW_LO_32768: + tuner_dbg("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); + buffer[3] |= TEA5767_XTAL_32768; + /* const 700=4000*175 Khz - to adjust freq to right value */ + div = (1000*(frq*4/16-700-225)+16384)>>15; + break; + case TEA5767_HIGH_LO_32768: + default: + tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); + + buffer[2] |= TEA5767_HIGH_LO_INJECT; + buffer[3] |= TEA5767_XTAL_32768; + div = (1000*(frq*4/16+700+225)+16384)>>15; + break; + } + buffer[0] = (div>>8) & 0x3f; + buffer[1] = div & 0xff; + + if ( tuner_debug ) + tea5767_status_dump(buffer); + + if (5 != (rc = i2c_master_send(c,buffer,5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n",rc); +} + +static int tea5767_signal(struct i2c_client *c) +{ + unsigned char buffer[5]; + int rc; + struct tuner *t = i2c_get_clientdata(c); + + memset(buffer,0,sizeof(buffer)); + if (5 != (rc = i2c_master_recv(c,buffer,5))) + tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc); + + return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) <<(13-4)); +} + +static int tea5767_stereo(struct i2c_client *c) +{ + unsigned char buffer[5]; + int rc; + struct tuner *t = i2c_get_clientdata(c); + + memset(buffer,0,sizeof(buffer)); + if (5 != (rc = i2c_master_recv(c,buffer,5))) + tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc); + + rc = buffer[2] & TEA5767_STEREO_MASK; + + if ( tuner_debug ) + tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); + + return ( (buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO: 0); +} + +int tea_detection(struct i2c_client *c) +{ + unsigned char buffer[5]= { 0xff, 0xff, 0xff, 0xff, 0xff }; + int rc; + struct tuner *t = i2c_get_clientdata(c); + + if (5 != (rc = i2c_master_recv(c,buffer,5))) { + tuner_warn ( "it is not a TEA5767. Received %i chars.\n",rc ); + return EINVAL; + } + + /* If all bytes are the same then it's a TV tuner and not a tea5767 chip. */ + if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && + buffer[0] == buffer[3] && buffer[0] == buffer[4]) { + tuner_warn ( "All bytes are equal. It is not a TEA5767\n" ); + return EINVAL; + } + + /* Status bytes: + * Byte 4: bit 3:1 : CI (Chip Identification) == 0 + * bit 0 : internally set to 0 + * Byte 5: bit 7:0 : == 0 + */ + + if (!((buffer[3] & 0x0f) == 0x00) && (buffer[4] == 0x00)) { + tuner_warn ( "Chip ID is not zero. It is not a TEA5767\n" ); + return EINVAL; + } + tuner_warn ( "TEA5767 detected.\n" ); + return 0; +} + +int tea5767_tuner_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (tea_detection(c)==EINVAL) return EINVAL; + + tuner_info("type set to %d (%s)\n", + t->type, TEA5767_TUNER_NAME); + strlcpy(c->name, TEA5767_TUNER_NAME, sizeof(c->name)); + + t->tv_freq = set_tv_freq; + t->radio_freq = set_radio_freq; + t->has_signal = tea5767_signal; + t->is_stereo = tea5767_stereo; + + return (0); +} diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index eaabfc85870..6f6bf4a633f 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1,5 +1,5 @@ /* - * $Id: tuner-core.c,v 1.15 2005/06/12 01:36:14 mchehab Exp $ + * $Id: tuner-core.c,v 1.29 2005/06/21 15:40:33 mchehab Exp $ * * i2c tv tuner chip device driver * core core, i.e. kernel interfaces, registering and so on @@ -26,7 +26,6 @@ /* * comment line bellow to return to old behavor, where only one I2C device is supported */ -#define CONFIG_TUNER_MULTI_I2C /**/ #define UNSET (-1U) @@ -58,9 +57,7 @@ MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); static int this_adap; -#ifdef CONFIG_TUNER_MULTI_I2C static unsigned short first_tuner, tv_tuner, radio_tuner; -#endif static struct i2c_driver driver; static struct i2c_client client_template; @@ -81,26 +78,9 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) return; } if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { - - if (freq >= tv_range[0]*16364 && freq <= tv_range[1]*16384) { - /* V4L2_TUNER_CAP_LOW frequency */ - - tuner_dbg("V4L2_TUNER_CAP_LOW freq selected for TV. Tuners yet doesn't support converting it to valid freq.\n"); - - t->tv_freq(c,freq>>10); - - return; - } else { - /* FIXME: better do that chip-specific, but - right now we don't have that in the config - struct and this way is still better than no - check at all */ tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n", freq/16,freq%16*100/16,tv_range[0],tv_range[1]); - return; - } } - tuner_dbg("62.5 Khz freq step selected for TV.\n"); t->tv_freq(c,freq); } @@ -116,31 +96,18 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_info("no radio tuning for this one, sorry.\n"); return; } - if (freq < radio_range[0]*16 || freq > radio_range[1]*16) { - if (freq >= tv_range[0]*16364 && freq <= tv_range[1]*16384) { - /* V4L2_TUNER_CAP_LOW frequency */ - if (t->type == TUNER_TEA5767) { - tuner_info("radio freq step 62.5Hz (%d.%06d)\n",(freq>>14),freq%(1<<14)*10000); - t->radio_freq(c,freq>>10); - return; - } - - tuner_dbg("V4L2_TUNER_CAP_LOW freq selected for Radio. Tuners yet doesn't support converting it to valid freq.\n"); - - tuner_info("radio freq (%d.%06d)\n",(freq>>14),freq%(1<<14)*10000); - - t->radio_freq(c,freq>>10); - return; - - } else { - tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n", - freq/16,freq%16*100/16, - radio_range[0],radio_range[1]); - return; - } + if (freq >= radio_range[0]*16000 && freq <= radio_range[1]*16000) { + if (tuner_debug) + tuner_info("radio freq step 62.5Hz (%d.%06d)\n", + freq/16000,freq%16000*1000/16); + t->radio_freq(c,freq); + } else { + tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n", + freq/16,freq%16*100/16, + radio_range[0],radio_range[1]); } - tuner_dbg("62.5 Khz freq step selected for Radio.\n"); - t->radio_freq(c,freq); + + return; } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -166,8 +133,8 @@ static void set_freq(struct i2c_client *c, unsigned long freq) static void set_type(struct i2c_client *c, unsigned int type) { struct tuner *t = i2c_get_clientdata(c); + unsigned char buffer[4]; - tuner_dbg ("I2C addr 0x%02x with type %d\n",c->addr<<1,type); /* sanity check */ if (type == UNSET || type == TUNER_ABSENT) return; @@ -179,8 +146,8 @@ static void set_type(struct i2c_client *c, unsigned int type) t->type = type; return; } - if (t->initialized) - /* run only once */ + if ((t->initialized) && (t->type == type)) + /* run only once except type change Hac 04/05*/ return; t->initialized = 1; @@ -193,25 +160,42 @@ static void set_type(struct i2c_client *c, unsigned int type) case TUNER_PHILIPS_TDA8290: tda8290_init(c); break; + case TUNER_TEA5767: + if (tea5767_tuner_init(c)==EINVAL) t->type=TUNER_ABSENT; + break; + case TUNER_PHILIPS_FMD1216ME_MK3: + buffer[0] = 0x0b; + buffer[1] = 0xdc; + buffer[2] = 0x9c; + buffer[3] = 0x60; + i2c_master_send(c,buffer,4); + mdelay(1); + buffer[2] = 0x86; + buffer[3] = 0x54; + i2c_master_send(c,buffer,4); + default_tuner_init(c); + break; default: + /* TEA5767 autodetection code */ + if (tea5767_tuner_init(c)!=EINVAL) { + t->type = TUNER_TEA5767; + if (first_tuner == 0x60) + first_tuner++; + break; + } + default_tuner_init(c); break; } + tuner_dbg ("I2C addr 0x%02x with type %d\n",c->addr<<1,type); } -#ifdef CONFIG_TUNER_MULTI_I2C #define CHECK_ADDR(tp,cmd,tun) if (client->addr!=tp) { \ - return 0; } else \ + return 0; } else if (tuner_debug) \ tuner_info ("Cmd %s accepted to "tun"\n",cmd); #define CHECK_MODE(cmd) if (t->mode == V4L2_TUNER_RADIO) { \ CHECK_ADDR(radio_tuner,cmd,"radio") } else \ { CHECK_ADDR(tv_tuner,cmd,"TV"); } -#else -#define CHECK_ADDR(tp,cmd,tun) tuner_info ("Cmd %s accepted to "tun"\n",cmd); -#define CHECK_MODE(cmd) tuner_info ("Cmd %s accepted\n",cmd); -#endif - -#ifdef CONFIG_TUNER_MULTI_I2C static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr) { @@ -242,9 +226,6 @@ static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr) } set_type(c,tun_addr->type); } -#else -#define set_addr(c,tun_addr) set_type(c,(tun_addr)->type) -#endif static char pal[] = "-"; module_param_string(pal, pal, sizeof(pal), 0644); @@ -284,17 +265,12 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) { struct tuner *t; -#ifndef CONFIG_TUNER_MULTI_I2C - if (this_adap > 0) - return -1; -#else /* by default, first I2C card is both tv and radio tuner */ if (this_adap == 0) { first_tuner = addr; tv_tuner = addr; radio_tuner = addr; } -#endif this_adap++; client_template.adapter = adap; @@ -308,6 +284,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) i2c_set_clientdata(&t->i2c, t); t->type = UNSET; t->radio_if2 = 10700*1000; /* 10.7MHz - FM radio */ + t->audmode = V4L2_TUNER_MODE_STEREO; i2c_attach_client(&t->i2c); tuner_info("chip found @ 0x%x (%s)\n", @@ -325,11 +302,9 @@ static int tuner_probe(struct i2c_adapter *adap) } this_adap = 0; -#ifdef CONFIG_TUNER_MULTI_I2C first_tuner = 0; tv_tuner = 0; radio_tuner = 0; -#endif if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tuner_attach); @@ -392,8 +367,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) t->radio_if2 = 41300 * 1000; break; } - break; - + break; /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ @@ -440,11 +414,18 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) vt->signal = t->has_signal(client); if (t->is_stereo) { if (t->is_stereo(client)) - vt-> flags |= VIDEO_TUNER_STEREO_ON; + vt->flags |= VIDEO_TUNER_STEREO_ON; else - vt-> flags &= 0xffff ^ VIDEO_TUNER_STEREO_ON; + vt->flags &= ~VIDEO_TUNER_STEREO_ON; } vt->flags |= V4L2_TUNER_CAP_LOW; /* Allow freqs at 62.5 Hz */ + + vt->rangelow = radio_range[0] * 16000; + vt->rangehigh = radio_range[1] * 16000; + + } else { + vt->rangelow = tv_range[0] * 16; + vt->rangehigh = tv_range[1] * 16; } return 0; @@ -510,20 +491,46 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) tuner -> signal = t->has_signal(client); if (t->is_stereo) { if (t->is_stereo(client)) { - tuner -> capability |= V4L2_TUNER_CAP_STEREO; - tuner -> rxsubchans |= V4L2_TUNER_SUB_STEREO; + tuner -> rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; } else { - tuner -> rxsubchans &= 0xffff ^ V4L2_TUNER_SUB_STEREO; + tuner -> rxsubchans = V4L2_TUNER_SUB_MONO; } } + tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + tuner->audmode = t->audmode; + + tuner->rangelow = radio_range[0] * 16000; + tuner->rangehigh = radio_range[1] * 16000; + } else { + tuner->rangelow = tv_range[0] * 16; + tuner->rangehigh = tv_range[1] * 16; } - /* Wow to deal with V4L2_TUNER_CAP_LOW ? For now, it accepts from low at 62.5KHz step to high at 62.5 Hz */ - tuner->rangelow = tv_range[0] * 16; -// tuner->rangehigh = tv_range[1] * 16; -// tuner->rangelow = tv_range[0] * 16384; - tuner->rangehigh = tv_range[1] * 16384; break; } + case VIDIOC_S_TUNER: /* Allow changing radio range and audio mode */ + { + struct v4l2_tuner *tuner = arg; + + CHECK_ADDR(radio_tuner,"VIDIOC_S_TUNER","radio"); + SWITCH_V4L2; + + /* To switch the audio mode, applications initialize the + index and audmode fields and the reserved array and + call the VIDIOC_S_TUNER ioctl. */ + /* rxsubchannels: V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO, + V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2, + V4L2_TUNER_MODE_SAP */ + + if (tuner->audmode == V4L2_TUNER_MODE_MONO) + t->audmode = V4L2_TUNER_MODE_MONO; + else + t->audmode = V4L2_TUNER_MODE_STEREO; + + set_radio_freq(client, t->freq); + break; + } + case TDA9887_SET_CONFIG: /* Nothing to do on tuner-core */ + break; default: tuner_dbg ("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd); /* nothing */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 539f3055731..c39ed6226ee 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -1,5 +1,5 @@ /* - * $Id: tuner-simple.c,v 1.21 2005/06/10 19:53:26 nsh Exp $ + * $Id: tuner-simple.c,v 1.31 2005/06/21 16:02:25 mkrufky Exp $ * * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. @@ -207,28 +207,27 @@ static struct tunertype tuners[] = { { "LG PAL (TAPE series)", LGINNOTEK, PAL, 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623}, - { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL, - 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 }, - { "Philips FQ1236A MK4", Philips, NTSC, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, + { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL, + 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 }, + { "Philips FQ1236A MK4", Philips, NTSC, + 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, /* Should work for TVF8531MF, TVF8831MF, TVF8731MF */ { "Ymec TVision TVF-8531MF", Philips, NTSC, 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, { "Ymec TVision TVF-5533MF", Philips, NTSC, 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732}, - { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC, 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, - { "Tena TNF9533-D/IF", LGINNOTEK, PAL, - 16*160.25, 16*464.25, 0x01,0x02,0x08,0x8e,623}, + /* Should work for TNF9533-D/IF, TNF9533-B/DF */ + { "Tena TNF9533-D/IF", Philips, PAL, + 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623}, - /* - * This entry is for TEA5767 FM radio only chip used on several boards - * w/TV tuner - */ + /* This entry is for TEA5767 FM radio only chip used on several boards w/TV tuner */ { TEA5767_TUNER_NAME, Philips, RADIO, - -1, -1, 0, 0, 0, TEA5767_LOW_LO_32768,0}, + -1, -1, 0, 0, 0, TEA5767_LOW_LO_32768,0}, + { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL, + 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); @@ -455,24 +454,24 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) int rc; tun=&tuners[t->type]; - div = freq + (int)(16*10.7); + div = (freq / 1000) + (int)(16*10.7); buffer[2] = tun->config; switch (t->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - /*These values are empirically determinated */ - div = (freq*122)/16 - 20; + div = (freq * 122) / 16000 - 20; buffer[2] = 0x88; /* could be also 0x80 */ buffer[3] = 0x19; /* could be also 0x10, 0x18, 0x99 */ break; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: + case TUNER_PHILIPS_FMD1216ME_MK3: buffer[3] = 0x19; break; case TUNER_PHILIPS_FM1256_IH3: - div = (20 * freq)/16 + 333 * 2; + div = (20 * freq) / 16000 + 333 * 2; buffer[2] = 0x80; buffer[3] = 0x19; break; @@ -505,6 +504,7 @@ int default_tuner_init(struct i2c_client *c) t->radio_freq = default_set_radio_freq; t->has_signal = tuner_signal; t->is_stereo = tuner_stereo; + return 0; } -- cgit v1.2.3 From 060d3027f26aab9adeac8ff6d1184bca67c7d174 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 28 Jun 2005 20:45:25 -0700 Subject: [PATCH] v4l: bttv new insmod parameters * bttv-driver.c, bttvp.h: - New bttv module params: - uv_ratio : allow a ratio of saturation between u and v. If you have a ratio of 40 and a saturation of 100, usat will be 80 and vstat 120. Useful to correct a bad color balance. - full_luma_range : provide a better contrast in using the full range 0-253 of values instead of 16-253. - coring : to have a better black level. - radio range is now defined on tuner-core.c. Cleaning up. * bttvp.h: - Fix gcc 4.0 compilation Signed-off-by: Jorik Jonker Signed-off-by: Sylvain Meyer Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Nickolay V Shmyrev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/bttv-driver.c | 73 ++++++++++++++++++++++++++++++++++----- drivers/media/video/bttvp.h | 5 ++- 2 files changed, 68 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 290289a9975..7d62b394c50 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -1,5 +1,5 @@ /* - $Id: bttv-driver.c,v 1.38 2005/06/10 17:20:24 mchehab Exp $ + $Id: bttv-driver.c,v 1.40 2005/06/16 21:38:45 nsh Exp $ bttv - Bt848 frame grabber driver @@ -76,6 +76,9 @@ static unsigned int whitecrush_upper = 0xCF; static unsigned int whitecrush_lower = 0x7F; static unsigned int vcr_hack = 0; static unsigned int irq_iswitch = 0; +static unsigned int uv_ratio = 50; +static unsigned int full_luma_range = 0; +static unsigned int coring = 0; /* API features (turn on/off stuff for testing) */ static unsigned int v4l2 = 1; @@ -106,6 +109,9 @@ module_param(adc_crush, int, 0444); module_param(whitecrush_upper, int, 0444); module_param(whitecrush_lower, int, 0444); module_param(vcr_hack, int, 0444); +module_param(uv_ratio, int, 0444); +module_param(full_luma_range, int, 0444); +module_param(coring, int, 0444); module_param_array(radio, int, NULL, 0444); @@ -124,6 +130,9 @@ MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127"); MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler"); +MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50"); +MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)"); +MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)"); MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards"); MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); @@ -484,7 +493,10 @@ static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats); #define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5) #define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6) #define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 8) +#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8) +#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9) +#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10) +#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11) static const struct v4l2_queryctrl no_ctl = { .name = "42", @@ -618,8 +630,32 @@ static const struct v4l2_queryctrl bttv_ctls[] = { .step = 1, .default_value = 0x7F, .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_UV_RATIO, + .name = "uv ratio", + .minimum = 0, + .maximum = 100, + .step = 1, + .default_value = 50, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE, + .name = "full luma range", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_CORING, + .name = "coring", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + .type = V4L2_CTRL_TYPE_INTEGER, } + + }; static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls); @@ -833,8 +869,8 @@ static void bt848_sat(struct bttv *btv, int color) btv->saturation = color; /* 0-511 for the color */ - val_u = color >> 7; - val_v = ((color>>7)*180L)/254; + val_u = ((color * btv->opt_uv_ratio) / 50) >> 7; + val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254; hibits = (val_u >> 7) & 2; hibits |= (val_v >> 8) & 1; btwrite(val_u & 0xff, BT848_SAT_U_LO); @@ -1151,6 +1187,15 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: c->value = btv->opt_whitecrush_lower; break; + case V4L2_CID_PRIVATE_UV_RATIO: + c->value = btv->opt_uv_ratio; + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + c->value = btv->opt_full_luma_range; + break; + case V4L2_CID_PRIVATE_CORING: + c->value = btv->opt_coring; + break; default: return -EINVAL; } @@ -1247,6 +1292,18 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) btv->opt_whitecrush_lower = c->value; btwrite(c->value, BT848_WC_DOWN); break; + case V4L2_CID_PRIVATE_UV_RATIO: + btv->opt_uv_ratio = c->value; + bt848_sat(btv, btv->saturation); + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + btv->opt_full_luma_range = c->value; + btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); + break; + case V4L2_CID_PRIVATE_CORING: + btv->opt_coring = c->value; + btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); + break; default: return -EINVAL; } @@ -3117,11 +3174,6 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; memset(v,0,sizeof(*v)); strcpy(v->name, "Radio"); - /* japan: 76.0 MHz - 89.9 MHz - western europe: 87.5 MHz - 108.0 MHz - russia: 65.0 MHz - 108.0 MHz */ - v->rangelow=(int)(65*16); - v->rangehigh=(int)(108*16); bttv_call_i2c_clients(btv,cmd,v); return 0; } @@ -3876,6 +3928,9 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->opt_vcr_hack = vcr_hack; btv->opt_whitecrush_upper = whitecrush_upper; btv->opt_whitecrush_lower = whitecrush_lower; + btv->opt_uv_ratio = uv_ratio; + btv->opt_full_luma_range = full_luma_range; + btv->opt_coring = coring; /* fill struct bttv with some useful defaults */ btv->init.btv = btv; diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index 7b6f1e85602..f3293e4a15a 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -1,5 +1,5 @@ /* - $Id: bttvp.h,v 1.17 2005/02/16 12:14:10 kraxel Exp $ + $Id: bttvp.h,v 1.19 2005/06/16 21:38:45 nsh Exp $ bttv - Bt848 frame grabber driver @@ -326,6 +326,9 @@ struct bttv { int opt_vcr_hack; int opt_whitecrush_upper; int opt_whitecrush_lower; + int opt_uv_ratio; + int opt_full_luma_range; + int opt_coring; /* radio data/state */ int has_radio; -- cgit v1.2.3 From 2fa938b8a3964c21b23d9d095091e7abc88249c5 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 28 Jun 2005 20:08:29 -0400 Subject: [PATCH] sis 760 support. This patch adds the SiS 760 ID to the amd64-agp driver, so that agpgart can be used on Athlon64 boards based on this chip. Signed-off-by: Daniel Drake Signed-off-by: Dave Jones Signed-off-by: Linus Torvalds --- drivers/char/agp/amd64-agp.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 1407945a589..59f589d733f 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -686,6 +686,15 @@ static struct pci_device_id agp_amd64_pci_table[] = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + /* SIS 760 */ + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_760, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { } }; -- cgit v1.2.3 From c5f4644e6c8ba21666128603e4e92544d3cd740d Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 29 Jun 2005 09:42:38 +0100 Subject: [PATCH] Serial: Adjust serial locking This patch changes the way serial ports are locked when getting modem status. This change is necessary because we will need to atomically read the modem status and take action depending on the CTS status. Signed-off-by: Russell King --- drivers/serial/8250.c | 3 --- drivers/serial/au1x00_uart.c | 3 --- drivers/serial/ip22zilog.c | 13 +++++++------ drivers/serial/mpsc.c | 3 --- drivers/serial/pmac_zilog.c | 4 ++-- drivers/serial/pxa.c | 3 --- drivers/serial/serial_core.c | 11 ++++++++++- drivers/serial/serial_txx9.c | 3 --- drivers/serial/sunsab.c | 7 +------ drivers/serial/sunsu.c | 3 --- drivers/serial/sunzilog.c | 13 +++++++------ 11 files changed, 27 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 34e75bc8f4c..b53b53bb147 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1376,13 +1376,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) static unsigned int serial8250_get_mctrl(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; - unsigned long flags; unsigned char status; unsigned int ret; - spin_lock_irqsave(&up->port.lock, flags); status = serial_in(up, UART_MSR); - spin_unlock_irqrestore(&up->port.lock, flags); ret = 0; if (status & UART_MSR_DCD) diff --git a/drivers/serial/au1x00_uart.c b/drivers/serial/au1x00_uart.c index 5400dc2c087..6104aeef124 100644 --- a/drivers/serial/au1x00_uart.c +++ b/drivers/serial/au1x00_uart.c @@ -556,13 +556,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) static unsigned int serial8250_get_mctrl(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; - unsigned long flags; unsigned char status; unsigned int ret; - spin_lock_irqsave(&up->port.lock, flags); status = serial_in(up, UART_MSR); - spin_unlock_irqrestore(&up->port.lock, flags); ret = 0; if (status & UART_MSR_DCD) diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index 3ea46c069f6..ea5bf4d4daa 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c @@ -518,27 +518,28 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *re static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port) { struct zilog_channel *channel; - unsigned long flags; unsigned char status; - spin_lock_irqsave(&port->lock, flags); - channel = ZILOG_CHANNEL_FROM_PORT(port); status = readb(&channel->control); ZSDELAY(); - spin_unlock_irqrestore(&port->lock, flags); - return status; } /* The port lock is not held. */ static unsigned int ip22zilog_tx_empty(struct uart_port *port) { + unsigned long flags; unsigned char status; unsigned int ret; + spin_lock_irqsave(&port->lock, flags); + status = ip22zilog_read_channel_status(port); + + spin_unlock_irqrestore(&port->lock, flags); + if (status & Tx_BUF_EMP) ret = TIOCSER_TEMT; else @@ -547,7 +548,7 @@ static unsigned int ip22zilog_tx_empty(struct uart_port *port) return ret; } -/* The port lock is not held. */ +/* The port lock is held and interrupts are disabled. */ static unsigned int ip22zilog_get_mctrl(struct uart_port *port) { unsigned char status; diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index a2a64331800..e43276c6a95 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -1058,12 +1058,9 @@ mpsc_get_mctrl(struct uart_port *port) { struct mpsc_port_info *pi = (struct mpsc_port_info *)port; u32 mflags, status; - ulong iflags; - spin_lock_irqsave(&pi->port.lock, iflags); status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m : readl(pi->mpsc_base + MPSC_CHR_10); - spin_unlock_irqrestore(&pi->port.lock, iflags); mflags = 0; if (status & 0x1) diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 85abd8a045e..1c9f7161712 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -604,7 +604,7 @@ static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl) /* * Get Modem Control bits (only the input ones, the core will * or that with a cached value of the control ones) - * The port lock is not held. + * The port lock is held and interrupts are disabled. */ static unsigned int pmz_get_mctrl(struct uart_port *port) { @@ -615,7 +615,7 @@ static unsigned int pmz_get_mctrl(struct uart_port *port) if (ZS_IS_ASLEEP(uap) || uap->node == NULL) return 0; - status = pmz_peek_status(to_pmz(port)); + status = read_zsreg(uap, R0); ret = 0; if (status & DCD) diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 08b08d6ae90..461c81c9320 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -274,14 +274,11 @@ static unsigned int serial_pxa_tx_empty(struct uart_port *port) static unsigned int serial_pxa_get_mctrl(struct uart_port *port) { struct uart_pxa_port *up = (struct uart_pxa_port *)port; - unsigned long flags; unsigned char status; unsigned int ret; return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - spin_lock_irqsave(&up->port.lock, flags); status = serial_in(up, UART_MSR); - spin_unlock_irqrestore(&up->port.lock, flags); ret = 0; if (status & UART_MSR_DCD) diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 36b1ae083fb..f5ce58d0514 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -828,7 +828,10 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file) if ((!file || !tty_hung_up_p(file)) && !(tty->flags & (1 << TTY_IO_ERROR))) { result = port->mctrl; + + spin_lock_irq(&port->lock); result |= port->ops->get_mctrl(port); + spin_unlock_irq(&port->lock); } up(&state->sem); @@ -1369,6 +1372,7 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) DECLARE_WAITQUEUE(wait, current); struct uart_info *info = state->info; struct uart_port *port = state->port; + unsigned int mctrl; info->blocked_open++; state->count--; @@ -1416,7 +1420,10 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) * and wait for the carrier to indicate that the * modem is ready for us. */ - if (port->ops->get_mctrl(port) & TIOCM_CAR) + spin_lock_irq(&port->lock); + mctrl = port->ops->get_mctrl(port); + spin_unlock_irq(&port->lock); + if (mctrl & TIOCM_CAR) break; up(&state->sem); @@ -1618,7 +1625,9 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) if(capable(CAP_SYS_ADMIN)) { + spin_lock_irq(&port->lock); status = port->ops->get_mctrl(port); + spin_unlock_irq(&port->lock); ret += sprintf(buf + ret, " tx:%d rx:%d", port->icount.tx, port->icount.rx); diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 3f1051a4a13..d085030df70 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -442,13 +442,10 @@ static unsigned int serial_txx9_tx_empty(struct uart_port *port) static unsigned int serial_txx9_get_mctrl(struct uart_port *port) { struct uart_txx9_port *up = (struct uart_txx9_port *)port; - unsigned long flags; unsigned int ret; - spin_lock_irqsave(&up->port.lock, flags); ret = ((sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS) | ((sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS); - spin_unlock_irqrestore(&up->port.lock, flags); return ret; } diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 10e2990a40d..8d198880756 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -426,18 +426,15 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl) sunsab_tx_idle(up); } -/* port->lock is not held. */ +/* port->lock is held by caller and interrupts are disabled. */ static unsigned int sunsab_get_mctrl(struct uart_port *port) { struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - unsigned long flags; unsigned char val; unsigned int result; result = 0; - spin_lock_irqsave(&up->port.lock, flags); - val = readb(&up->regs->r.pvr); result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR; @@ -447,8 +444,6 @@ static unsigned int sunsab_get_mctrl(struct uart_port *port) val = readb(&up->regs->r.star); result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0; - spin_unlock_irqrestore(&up->port.lock, flags); - return result; } diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index ddc97c905e1..d57a3553aea 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -572,13 +572,10 @@ static unsigned int sunsu_tx_empty(struct uart_port *port) static unsigned int sunsu_get_mctrl(struct uart_port *port) { struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - unsigned long flags; unsigned char status; unsigned int ret; - spin_lock_irqsave(&up->port.lock, flags); status = serial_in(up, UART_MSR); - spin_unlock_irqrestore(&up->port.lock, flags); ret = 0; if (status & UART_MSR_DCD) diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 8e65206d3d7..bff42a7b89d 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -610,27 +610,28 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port) { struct zilog_channel __iomem *channel; - unsigned long flags; unsigned char status; - spin_lock_irqsave(&port->lock, flags); - channel = ZILOG_CHANNEL_FROM_PORT(port); status = sbus_readb(&channel->control); ZSDELAY(); - spin_unlock_irqrestore(&port->lock, flags); - return status; } /* The port lock is not held. */ static unsigned int sunzilog_tx_empty(struct uart_port *port) { + unsigned long flags; unsigned char status; unsigned int ret; + spin_lock_irqsave(&port->lock, flags); + status = sunzilog_read_channel_status(port); + + spin_unlock_irqrestore(&port->lock, flags); + if (status & Tx_BUF_EMP) ret = TIOCSER_TEMT; else @@ -639,7 +640,7 @@ static unsigned int sunzilog_tx_empty(struct uart_port *port) return ret; } -/* The port lock is not held. */ +/* The port lock is held and interrupts are disabled. */ static unsigned int sunzilog_get_mctrl(struct uart_port *port) { unsigned char status; -- cgit v1.2.3 From fd782a4a99d2d3e818b9465c427b10f7f027d7da Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Wed, 29 Jun 2005 15:15:40 +0100 Subject: [PATCH] Fix get_request nastiness get_request is now expected to be holding on to queue_lock, with interrupts disabled, when it returns NULL; but one path forgot that, causing all kinds of nastiness under swap load - badness backtraces, strange failures, BUGs. Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds --- drivers/block/ll_rw_blk.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 1197462bb6b..692a5fced76 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1917,10 +1917,9 @@ get_rq: * limit of requests, otherwise we could have thousands of requests * allocated with any setting of ->nr_requests */ - if (rl->count[rw] >= (3 * q->nr_requests / 2)) { - spin_unlock_irq(q->queue_lock); + if (rl->count[rw] >= (3 * q->nr_requests / 2)) goto out; - } + rl->count[rw]++; rl->starved[rw] = 0; if (rl->count[rw] >= queue_congestion_on_threshold(q)) -- cgit v1.2.3 From 164cad9bacc2cf190493d2ee4918dc2869ba6f53 Mon Sep 17 00:00:00 2001 From: Prakash Punnoor Date: Wed, 29 Jun 2005 14:13:54 +0200 Subject: [PATCH] Don't fill up log with atxp1 vcore messages change message I am using the atxp1 module to change vcore on my NForce2 via userspace daemon (see punnoor.de). Currently the atxp1 module will write to the log on every vcore change, thus filling up my log - which I don't want. I am no kernel coder, but I guess, this one-liner will change this behaviour in a wanted way, ie output will be made for debug purposes only. Signed-off-by: Prakash Punnoor Signed-off-by: Linus Torvalds --- drivers/i2c/chips/atxp1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/atxp1.c b/drivers/i2c/chips/atxp1.c index 5c6597aa2c7..0bcf82b4c07 100644 --- a/drivers/i2c/chips/atxp1.c +++ b/drivers/i2c/chips/atxp1.c @@ -144,7 +144,7 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att if (vid == cvid) return count; - dev_info(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid); + dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid); /* Write every 25 mV step to increase stability */ if (cvid > vid) { -- cgit v1.2.3 From c7e788766610bdc764d7150e69ace2e0c4196cf0 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 29 Jun 2005 18:10:54 +0100 Subject: [PATCH] ARM: 2723/2: remove __udivdi3 and __umoddi3 from the kernel Patch from Nicolas Pitre Those are big, slow and generally not recommended for kernel code. They are even not present on i386. So it should be concluded that one could as well get away with do_div() alone. Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- drivers/net/arm/etherh.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 2e28c201dcc..942a2819576 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -68,7 +68,6 @@ struct etherh_priv { void __iomem *dma_base; unsigned int id; void __iomem *ctrl_port; - void __iomem *base; unsigned char ctrl; u32 supported; }; @@ -178,7 +177,7 @@ etherh_setif(struct net_device *dev) switch (etherh_priv(dev)->id) { case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600A: - addr = etherh_priv(dev)->base + EN0_RCNTHI; + addr = (void *)dev->base_addr + EN0_RCNTHI; switch (dev->if_port) { case IF_PORT_10BASE2: @@ -219,7 +218,7 @@ etherh_getifstat(struct net_device *dev) switch (etherh_priv(dev)->id) { case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600A: - addr = etherh_priv(dev)->base + EN0_RCNTHI; + addr = (void *)dev->base_addr + EN0_RCNTHI; switch (dev->if_port) { case IF_PORT_10BASE2: stat = 1; @@ -282,7 +281,7 @@ static void etherh_reset(struct net_device *dev) { struct ei_device *ei_local = netdev_priv(dev); - void __iomem *addr = etherh_priv(dev)->base; + void __iomem *addr = (void *)dev->base_addr; writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr); @@ -328,7 +327,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf ei_local->dmaing = 1; - addr = etherh_priv(dev)->base; + addr = (void *)dev->base_addr; dma_base = etherh_priv(dev)->dma_base; count = (count + 1) & ~1; @@ -388,7 +387,7 @@ etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ei_local->dmaing = 1; - addr = etherh_priv(dev)->base; + addr = (void *)dev->base_addr; dma_base = etherh_priv(dev)->dma_base; buf = skb->data; @@ -428,7 +427,7 @@ etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_p ei_local->dmaing = 1; - addr = etherh_priv(dev)->base; + addr = (void *)dev->base_addr; dma_base = etherh_priv(dev)->dma_base; writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); @@ -697,8 +696,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) eh->ctrl_port = eh->ioc_fast; } - eh->base = eh->memc + data->ns8390_offset; - dev->base_addr = (unsigned long)eh->base; + dev->base_addr = (unsigned long)eh->memc + data->ns8390_offset; eh->dma_base = eh->memc + data->dataport_offset; eh->ctrl_port += data->ctrlport_offset; -- cgit v1.2.3 From 0dd7a1aed7c34a39917c4faf75b4230c169e809b Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 29 Jun 2005 18:40:53 +0100 Subject: [PATCH] Serial: Check status of CTS when using flow control Fix bugme #4712: read the CTS status and set hw_stopped if CTS is not active when opening the port and/or enabling CRTSCTS Thanks to Stefan Wolff for spotting this problem. Signed-off-by: Russell King --- drivers/serial/serial_core.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index f5ce58d0514..139863a787f 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -182,6 +182,13 @@ static int uart_startup(struct uart_state *state, int init_hw) uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); } + if (info->flags & UIF_CTS_FLOW) { + spin_lock_irq(&port->lock); + if (!(port->ops->get_mctrl(port) & TIOCM_CTS)) + info->tty->hw_stopped = 1; + spin_unlock_irq(&port->lock); + } + info->flags |= UIF_INITIALIZED; clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1134,6 +1141,16 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios spin_unlock_irqrestore(&state->port->lock, flags); } + /* Handle turning on CRTSCTS */ + if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { + spin_lock_irqsave(&state->port->lock, flags); + if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) { + tty->hw_stopped = 1; + state->port->ops->stop_tx(state->port, 0); + } + spin_unlock_irqrestore(&state->port->lock, flags); + } + #if 0 /* * No need to wake up processes in open wait, since they -- cgit v1.2.3 From e763b90c41563a0f8258d379fe71a9a1f1fa5445 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 29 Jun 2005 18:41:51 +0100 Subject: [PATCH] Serial: Disable OX950 transmitter for flow control Disable the transmitter whenever we want to prevent characters being transmitted by flow control. However, if we run out of characters to send and want to only disable the TX interrupt, allow that scenario. Signed-off-by: Russell King --- drivers/serial/8250.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index b53b53bb147..429994d5bc8 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -993,21 +993,24 @@ static void autoconfig_irq(struct uart_8250_port *up) up->port.irq = (irq > 0) ? irq : 0; } +static inline void __stop_tx(struct uart_8250_port *p) +{ + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + } +} + static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop) { struct uart_8250_port *up = (struct uart_8250_port *)port; - if (up->ier & UART_IER_THRI) { - up->ier &= ~UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } + __stop_tx(up); /* - * We only do this from uart_stop - if we run out of - * characters to send, we don't want to prevent the - * FIFO from emptying. + * We really want to stop the transmitter from sending. */ - if (up->port.type == PORT_16C950 && tty_stop) { + if (up->port.type == PORT_16C950) { up->acr |= UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); } @@ -1031,10 +1034,11 @@ static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start) transmit_chars(up); } } + /* - * We only do this from uart_start + * Re-enable the transmitter if we disabled it. */ - if (tty_start && up->port.type == PORT_16C950) { + if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { up->acr &= ~UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); } @@ -1155,7 +1159,7 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up) return; } if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial8250_stop_tx(&up->port, 0); + __stop_tx(up); return; } @@ -1174,7 +1178,7 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up) DEBUG_INTR("THRE..."); if (uart_circ_empty(xmit)) - serial8250_stop_tx(&up->port, 0); + __stop_tx(up); } static _INLINE_ void check_modem_status(struct uart_8250_port *up) -- cgit v1.2.3 From 026d02a236f429eb61a1277166bd425f8514c431 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 29 Jun 2005 18:45:19 +0100 Subject: [PATCH] Serial: Split 8250 port table (part 2) Remove legacy ISA serial ports for Accent, Boca, Fourport, Hub6 and MCA from the architecture specific serial.h include. The only ports which remain in asm-*/serial.h are the platform specific entries. These should really be converted by platform maintainers to use a platform device, such as can be found in arch/arm/mach-footbridge/isa.c Signed-off-by: Russell King --- drivers/serial/8250.c | 2 +- drivers/serial/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 429994d5bc8..9224fc3184e 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -105,7 +105,7 @@ static struct old_serial_port old_serial_port[] = { SERIAL_PORT_DFNS /* defined in asm/serial.h */ }; -#define UART_NR (ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS) +#define UART_NR CONFIG_SERIAL_8250_NR_UARTS #ifdef CONFIG_SERIAL_8250_RSA diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e879bce160d..e0d0a470ddf 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -86,7 +86,7 @@ config SERIAL_8250_ACPI namespace, say Y here. If unsure, say N. config SERIAL_8250_NR_UARTS - int "Maximum number of non-legacy 8250/16550 serial ports" + int "Maximum number of 8250/16550 serial ports" depends on SERIAL_8250 default "4" help -- cgit v1.2.3