diff options
Diffstat (limited to 'drivers')
70 files changed, 2770 insertions, 536 deletions
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 81e14bea54b..4bada0e8b81 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -148,6 +148,9 @@ struct agp_bridge_data { char minor_version; struct list_head list; u32 apbase_config; + /* list of agp_memory mapped to the aperture */ + struct list_head mapped_list; + spinlock_t mapped_lock; }; #define KB(x) ((x) * 1024) diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 1ffb381130c..31dcd9142d5 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -110,7 +110,8 @@ static int ali_configure(void) nlvm_addr+= agp_bridge->gart_bus_addr; nlvm_addr|=(agp_bridge->gart_bus_addr>>12); - printk(KERN_INFO PFX "nlvm top &base = %8x\n",nlvm_addr); + dev_info(&agp_bridge->dev->dev, "nlvm top &base = %8x\n", + nlvm_addr); } #endif @@ -315,8 +316,8 @@ static int __devinit agp_ali_probe(struct pci_dev *pdev, goto found; } - printk(KERN_ERR PFX "Unsupported ALi chipset (device id: %04x)\n", - pdev->device); + dev_err(&pdev->dev, "unsupported ALi chipset [%04x/%04x])\n", + pdev->vendor, pdev->device); return -ENODEV; @@ -361,8 +362,7 @@ found: bridge->driver = &ali_generic_bridge; } - printk(KERN_INFO PFX "Detected ALi %s chipset\n", - devs[j].chipset_name); + dev_info(&pdev->dev, "ALi %s chipset\n", devs[j].chipset_name); /* Fill in the mode register */ pci_read_config_dword(pdev, diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 39a0718bc61..e280531843b 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -419,8 +419,8 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, return -ENODEV; j = ent - agp_amdk7_pci_table; - printk(KERN_INFO PFX "Detected AMD %s chipset\n", - amd_agp_device_ids[j].chipset_name); + dev_info(&pdev->dev, "AMD %s chipset\n", + amd_agp_device_ids[j].chipset_name); bridge = agp_alloc_bridge(); if (!bridge) @@ -442,7 +442,7 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, while (!cap_ptr) { gfxcard = pci_get_class(PCI_CLASS_DISPLAY_VGA<<8, gfxcard); if (!gfxcard) { - printk (KERN_INFO PFX "Couldn't find an AGP VGA controller.\n"); + dev_info(&pdev->dev, "no AGP VGA controller\n"); return -ENODEV; } cap_ptr = pci_find_capability(gfxcard, PCI_CAP_ID_AGP); @@ -453,7 +453,7 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, (if necessary at all). */ if (gfxcard->vendor == PCI_VENDOR_ID_NVIDIA) { agp_bridge->flags |= AGP_ERRATA_1X; - printk (KERN_INFO PFX "AMD 751 chipset with NVidia GeForce detected. Forcing to 1X due to errata.\n"); + dev_info(&pdev->dev, "AMD 751 chipset with NVidia GeForce; forcing 1X due to errata\n"); } pci_dev_put(gfxcard); } @@ -469,7 +469,7 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, agp_bridge->flags = AGP_ERRATA_FASTWRITES; agp_bridge->flags |= AGP_ERRATA_SBA; agp_bridge->flags |= AGP_ERRATA_1X; - printk (KERN_INFO PFX "AMD 761 chipset with errata detected - disabling AGP fast writes & SBA and forcing to 1X.\n"); + dev_info(&pdev->dev, "AMD 761 chipset with errata; disabling AGP fast writes & SBA and forcing to 1X\n"); } } diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 481ffe87c71..7495c522d8e 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -34,6 +34,7 @@ static struct resource *aperture_resource; static int __initdata agp_try_unsupported = 1; +static int agp_bridges_found; static void amd64_tlbflush(struct agp_memory *temp) { @@ -293,12 +294,13 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, * so let double check that order, and lets trust the AMD NB settings */ if (order >=0 && aper + (32ULL<<(20 + order)) > 0x100000000ULL) { - printk(KERN_INFO "Aperture size %u MB is not right, using settings from NB\n", - 32 << order); + dev_info(&agp->dev, "aperture size %u MB is not right, using settings from NB\n", + 32 << order); order = nb_order; } - printk(KERN_INFO PFX "Aperture from AGP @ %Lx size %u MB\n", aper, 32 << order); + dev_info(&agp->dev, "aperture from AGP @ %Lx size %u MB\n", + aper, 32 << order); if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order)) return -1; @@ -319,10 +321,10 @@ static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr) for (i = 0; i < num_k8_northbridges; i++) { struct pci_dev *dev = k8_northbridges[i]; if (fix_northbridge(dev, pdev, cap_ptr) < 0) { - printk(KERN_ERR PFX "No usable aperture found.\n"); + dev_err(&dev->dev, "no usable aperture found\n"); #ifdef __x86_64__ /* should port this to i386 */ - printk(KERN_ERR PFX "Consider rebooting with iommu=memaper=2 to get a good aperture.\n"); + dev_err(&dev->dev, "consider rebooting with iommu=memaper=2 to get a good aperture\n"); #endif return -1; } @@ -345,14 +347,14 @@ static void __devinit amd8151_init(struct pci_dev *pdev, struct agp_bridge_data default: revstring="??"; break; } - printk (KERN_INFO PFX "Detected AMD 8151 AGP Bridge rev %s\n", revstring); + dev_info(&pdev->dev, "AMD 8151 AGP Bridge rev %s\n", revstring); /* * Work around errata. * Chips before B2 stepping incorrectly reporting v3.5 */ if (pdev->revision < 0x13) { - printk (KERN_INFO PFX "Correcting AGP revision (reports 3.5, is really 3.0)\n"); + dev_info(&pdev->dev, "correcting AGP revision (reports 3.5, is really 3.0)\n"); bridge->major_version = 3; bridge->minor_version = 0; } @@ -375,11 +377,11 @@ static int __devinit uli_agp_init(struct pci_dev *pdev) struct pci_dev *dev1; int i; unsigned size = amd64_fetch_size(); - printk(KERN_INFO "Setting up ULi AGP.\n"); + + dev_info(&pdev->dev, "setting up ULi AGP\n"); dev1 = pci_get_slot (pdev->bus,PCI_DEVFN(0,0)); if (dev1 == NULL) { - printk(KERN_INFO PFX "Detected a ULi chipset, " - "but could not fine the secondary device.\n"); + dev_info(&pdev->dev, "can't find ULi secondary device\n"); return -ENODEV; } @@ -388,7 +390,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev) break; if (i == ARRAY_SIZE(uli_sizes)) { - printk(KERN_INFO PFX "No ULi size found for %d\n", size); + dev_info(&pdev->dev, "no ULi size found for %d\n", size); return -ENODEV; } @@ -433,13 +435,11 @@ static int nforce3_agp_init(struct pci_dev *pdev) int i; unsigned size = amd64_fetch_size(); - printk(KERN_INFO PFX "Setting up Nforce3 AGP.\n"); + dev_info(&pdev->dev, "setting up Nforce3 AGP\n"); dev1 = pci_get_slot(pdev->bus, PCI_DEVFN(11, 0)); if (dev1 == NULL) { - printk(KERN_INFO PFX "agpgart: Detected an NVIDIA " - "nForce3 chipset, but could not find " - "the secondary device.\n"); + dev_info(&pdev->dev, "can't find Nforce3 secondary device\n"); return -ENODEV; } @@ -448,7 +448,7 @@ static int nforce3_agp_init(struct pci_dev *pdev) break; if (i == ARRAY_SIZE(nforce3_sizes)) { - printk(KERN_INFO PFX "No NForce3 size found for %d\n", size); + dev_info(&pdev->dev, "no NForce3 size found for %d\n", size); return -ENODEV; } @@ -462,7 +462,7 @@ static int nforce3_agp_init(struct pci_dev *pdev) /* if x86-64 aperture base is beyond 4G, exit here */ if ( (apbase & 0x7fff) >> (32 - 25) ) { - printk(KERN_INFO PFX "aperture base > 4G\n"); + dev_info(&pdev->dev, "aperture base > 4G\n"); return -ENODEV; } @@ -489,6 +489,7 @@ static int __devinit agp_amd64_probe(struct pci_dev *pdev, { struct agp_bridge_data *bridge; u8 cap_ptr; + int err; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) @@ -504,7 +505,8 @@ static int __devinit agp_amd64_probe(struct pci_dev *pdev, pdev->device == PCI_DEVICE_ID_AMD_8151_0) { amd8151_init(pdev, bridge); } else { - printk(KERN_INFO PFX "Detected AGP bridge %x\n", pdev->devfn); + dev_info(&pdev->dev, "AGP bridge [%04x/%04x]\n", + pdev->vendor, pdev->device); } bridge->driver = &amd_8151_driver; @@ -536,7 +538,12 @@ static int __devinit agp_amd64_probe(struct pci_dev *pdev, } pci_set_drvdata(pdev, bridge); - return agp_add_bridge(bridge); + err = agp_add_bridge(bridge); + if (err < 0) + return err; + + agp_bridges_found++; + return 0; } static void __devexit agp_amd64_remove(struct pci_dev *pdev) @@ -713,7 +720,11 @@ int __init agp_amd64_init(void) if (agp_off) return -EINVAL; - if (pci_register_driver(&agp_amd64_pci_driver) < 0) { + err = pci_register_driver(&agp_amd64_pci_driver); + if (err < 0) + return err; + + if (agp_bridges_found == 0) { struct pci_dev *dev; if (!agp_try_unsupported && !agp_try_unsupported_boot) { printk(KERN_INFO PFX "No supported AGP bridge found.\n"); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 3a4566c0d84..6ecbcafb34b 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -486,8 +486,8 @@ static int __devinit agp_ati_probe(struct pci_dev *pdev, goto found; } - printk(KERN_ERR PFX - "Unsupported Ati chipset (device id: %04x)\n", pdev->device); + dev_err(&pdev->dev, "unsupported Ati chipset [%04x/%04x])\n", + pdev->vendor, pdev->device); return -ENODEV; found: @@ -500,8 +500,7 @@ found: bridge->driver = &ati_generic_bridge; - printk(KERN_INFO PFX "Detected Ati %s chipset\n", - devs[j].chipset_name); + dev_info(&pdev->dev, "Ati %s chipset\n", devs[j].chipset_name); /* Fill in the mode register */ pci_read_config_dword(pdev, diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 1ec87104e68..3a3cc03d401 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -144,7 +144,8 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) void *addr = bridge->driver->agp_alloc_page(bridge); if (!addr) { - printk(KERN_ERR PFX "unable to get memory for scratch page.\n"); + dev_err(&bridge->dev->dev, + "can't get memory for scratch page\n"); return -ENOMEM; } @@ -155,13 +156,13 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) size_value = bridge->driver->fetch_size(); if (size_value == 0) { - printk(KERN_ERR PFX "unable to determine aperture size.\n"); + dev_err(&bridge->dev->dev, "can't determine aperture size\n"); rc = -EINVAL; goto err_out; } if (bridge->driver->create_gatt_table(bridge)) { - printk(KERN_ERR PFX - "unable to get memory for graphics translation table.\n"); + dev_err(&bridge->dev->dev, + "can't get memory for graphics translation table\n"); rc = -ENOMEM; goto err_out; } @@ -169,7 +170,8 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) bridge->key_list = vmalloc(PAGE_SIZE * 4); if (bridge->key_list == NULL) { - printk(KERN_ERR PFX "error allocating memory for key lists.\n"); + dev_err(&bridge->dev->dev, + "can't allocate memory for key lists\n"); rc = -ENOMEM; goto err_out; } @@ -179,10 +181,12 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) memset(bridge->key_list, 0, PAGE_SIZE * 4); if (bridge->driver->configure()) { - printk(KERN_ERR PFX "error configuring host chipset.\n"); + dev_err(&bridge->dev->dev, "error configuring host chipset\n"); rc = -EINVAL; goto err_out; } + INIT_LIST_HEAD(&bridge->mapped_list); + spin_lock_init(&bridge->mapped_lock); return 0; @@ -269,25 +273,27 @@ int agp_add_bridge(struct agp_bridge_data *bridge) /* Grab reference on the chipset driver. */ if (!try_module_get(bridge->driver->owner)) { - printk (KERN_INFO PFX "Couldn't lock chipset driver.\n"); + dev_info(&bridge->dev->dev, "can't lock chipset driver\n"); return -EINVAL; } error = agp_backend_initialize(bridge); if (error) { - printk (KERN_INFO PFX "agp_backend_initialize() failed.\n"); + dev_info(&bridge->dev->dev, + "agp_backend_initialize() failed\n"); goto err_out; } if (list_empty(&agp_bridges)) { error = agp_frontend_initialize(); if (error) { - printk (KERN_INFO PFX "agp_frontend_initialize() failed.\n"); + dev_info(&bridge->dev->dev, + "agp_frontend_initialize() failed\n"); goto frontend_err; } - printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n", - bridge->driver->fetch_size(), bridge->gart_bus_addr); + dev_info(&bridge->dev->dev, "AGP aperture is %dM @ 0x%lx\n", + bridge->driver->fetch_size(), bridge->gart_bus_addr); } diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index eaa1a355bb3..118dbde25dc 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -429,6 +429,10 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start) curr->is_bound = true; curr->pg_start = pg_start; + spin_lock(&agp_bridge->mapped_lock); + list_add(&curr->mapped_list, &agp_bridge->mapped_list); + spin_unlock(&agp_bridge->mapped_lock); + return 0; } EXPORT_SYMBOL(agp_bind_memory); @@ -461,10 +465,34 @@ int agp_unbind_memory(struct agp_memory *curr) curr->is_bound = false; curr->pg_start = 0; + spin_lock(&curr->bridge->mapped_lock); + list_del(&curr->mapped_list); + spin_unlock(&curr->bridge->mapped_lock); return 0; } EXPORT_SYMBOL(agp_unbind_memory); +/** + * agp_rebind_emmory - Rewrite the entire GATT, useful on resume + */ +int agp_rebind_memory(void) +{ + struct agp_memory *curr; + int ret_val = 0; + + spin_lock(&agp_bridge->mapped_lock); + list_for_each_entry(curr, &agp_bridge->mapped_list, mapped_list) { + ret_val = curr->bridge->driver->insert_memory(curr, + curr->pg_start, + curr->type); + if (ret_val != 0) + break; + } + spin_unlock(&agp_bridge->mapped_lock); + return ret_val; +} +EXPORT_SYMBOL(agp_rebind_memory); + /* End - Routines for handling swapping of agp_memory into the GATT */ @@ -771,8 +799,8 @@ void agp_device_command(u32 bridge_agpstat, bool agp_v3) if (!agp) continue; - printk(KERN_INFO PFX "Putting AGP V%d device at %s into %dx mode\n", - agp_v3 ? 3 : 2, pci_name(device), mode); + dev_info(&device->dev, "putting AGP V%d device into %dx mode\n", + agp_v3 ? 3 : 2, mode); pci_write_config_dword(device, agp + PCI_AGP_COMMAND, bridge_agpstat); } } @@ -800,10 +828,8 @@ void agp_generic_enable(struct agp_bridge_data *bridge, u32 requested_mode) get_agp_version(agp_bridge); - printk(KERN_INFO PFX "Found an AGP %d.%d compliant device at %s.\n", - agp_bridge->major_version, - agp_bridge->minor_version, - pci_name(agp_bridge->dev)); + dev_info(&agp_bridge->dev->dev, "AGP %d.%d bridge\n", + agp_bridge->major_version, agp_bridge->minor_version); pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + PCI_AGP_STATUS, &bridge_agpstat); @@ -832,8 +858,7 @@ void agp_generic_enable(struct agp_bridge_data *bridge, u32 requested_mode) pci_write_config_dword(bridge->dev, bridge->capndx+AGPCTRL, temp); - printk(KERN_INFO PFX "Device is in legacy mode," - " falling back to 2.x\n"); + dev_info(&bridge->dev->dev, "bridge is in legacy mode, falling back to 2.x\n"); } } diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index df702642ab8..016fdf0623a 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -32,8 +32,8 @@ #define PCI_DEVICE_ID_INTEL_Q35_IG 0x29B2 #define PCI_DEVICE_ID_INTEL_Q33_HB 0x29D0 #define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2 -#define PCI_DEVICE_ID_INTEL_IGD_HB 0x2A40 -#define PCI_DEVICE_ID_INTEL_IGD_IG 0x2A42 +#define PCI_DEVICE_ID_INTEL_GM45_HB 0x2A40 +#define PCI_DEVICE_ID_INTEL_GM45_IG 0x2A42 #define PCI_DEVICE_ID_INTEL_IGD_E_HB 0x2E00 #define PCI_DEVICE_ID_INTEL_IGD_E_IG 0x2E02 #define PCI_DEVICE_ID_INTEL_Q45_HB 0x2E10 @@ -55,7 +55,7 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_HB) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB) #define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \ @@ -161,7 +161,7 @@ static int intel_i810_fetch_size(void) values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { - printk(KERN_WARNING PFX "i810 is disabled\n"); + dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n"); return 0; } if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { @@ -193,7 +193,8 @@ static int intel_i810_configure(void) intel_private.registers = ioremap(temp, 128 * 4096); if (!intel_private.registers) { - printk(KERN_ERR PFX "Unable to remap memory.\n"); + dev_err(&intel_private.pcidev->dev, + "can't remap memory\n"); return -ENOMEM; } } @@ -201,7 +202,8 @@ static int intel_i810_configure(void) if ((readl(intel_private.registers+I810_DRAM_CTL) & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { /* This will need to be dynamically assigned */ - printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n"); + dev_info(&intel_private.pcidev->dev, + "detected 4MB dedicated video ram\n"); intel_private.num_dcache_entries = 1024; } pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); @@ -500,8 +502,8 @@ static void intel_i830_init_gtt_entries(void) size = 1024 + 512; break; default: - printk(KERN_INFO PFX "Unknown page table size, " - "assuming 512KB\n"); + dev_info(&intel_private.pcidev->dev, + "unknown page table size, assuming 512KB\n"); size = 512; } size += 4; /* add in BIOS popup space */ @@ -515,8 +517,8 @@ static void intel_i830_init_gtt_entries(void) size = 2048; break; default: - printk(KERN_INFO PFX "Unknown page table size 0x%x, " - "assuming 512KB\n", + dev_info(&agp_bridge->dev->dev, + "unknown page table size 0x%x, assuming 512KB\n", (gmch_ctrl & G33_PGETBL_SIZE_MASK)); size = 512; } @@ -627,11 +629,11 @@ static void intel_i830_init_gtt_entries(void) } } if (gtt_entries > 0) - printk(KERN_INFO PFX "Detected %dK %s memory.\n", + dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n", gtt_entries / KB(1), local ? "local" : "stolen"); else - printk(KERN_INFO PFX - "No pre-allocated video memory detected.\n"); + dev_info(&agp_bridge->dev->dev, + "no pre-allocated video memory detected\n"); gtt_entries /= KB(4); intel_private.gtt_entries = gtt_entries; @@ -801,10 +803,12 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, num_entries = A_SIZE_FIX(temp)->num_entries; if (pg_start < intel_private.gtt_entries) { - printk(KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", - pg_start, intel_private.gtt_entries); + dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, + "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n", + pg_start, intel_private.gtt_entries); - printk(KERN_INFO PFX "Trying to insert into local/stolen memory\n"); + dev_info(&intel_private.pcidev->dev, + "trying to insert into local/stolen memory\n"); goto out_err; } @@ -851,7 +855,8 @@ static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start, return 0; if (pg_start < intel_private.gtt_entries) { - printk(KERN_INFO PFX "Trying to disable local/stolen memory\n"); + dev_info(&intel_private.pcidev->dev, + "trying to disable local/stolen memory\n"); return -EINVAL; } @@ -957,7 +962,7 @@ static void intel_i9xx_setup_flush(void) if (intel_private.ifp_resource.start) { intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); if (!intel_private.i9xx_flush_page) - printk(KERN_INFO "unable to ioremap flush page - no chipset flushing"); + dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing"); } } @@ -1028,10 +1033,12 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, num_entries = A_SIZE_FIX(temp)->num_entries; if (pg_start < intel_private.gtt_entries) { - printk(KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", - pg_start, intel_private.gtt_entries); + dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, + "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n", + pg_start, intel_private.gtt_entries); - printk(KERN_INFO PFX "Trying to insert into local/stolen memory\n"); + dev_info(&intel_private.pcidev->dev, + "trying to insert into local/stolen memory\n"); goto out_err; } @@ -1078,7 +1085,8 @@ static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start, return 0; if (pg_start < intel_private.gtt_entries) { - printk(KERN_INFO PFX "Trying to disable local/stolen memory\n"); + dev_info(&intel_private.pcidev->dev, + "trying to disable local/stolen memory\n"); return -EINVAL; } @@ -1182,7 +1190,7 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) { switch (agp_bridge->dev->device) { - case PCI_DEVICE_ID_INTEL_IGD_HB: + case PCI_DEVICE_ID_INTEL_GM45_HB: case PCI_DEVICE_ID_INTEL_IGD_E_HB: case PCI_DEVICE_ID_INTEL_Q45_HB: case PCI_DEVICE_ID_INTEL_G45_HB: @@ -1379,7 +1387,7 @@ static int intel_815_configure(void) /* the Intel 815 chipset spec. says that bits 29-31 in the * ATTBASE register are reserved -> try not to write them */ if (agp_bridge->gatt_bus_addr & INTEL_815_ATTBASE_MASK) { - printk(KERN_EMERG PFX "gatt bus addr too high"); + dev_emerg(&agp_bridge->dev->dev, "gatt bus addr too high"); return -EINVAL; } @@ -2117,8 +2125,8 @@ static const struct intel_driver_description { NULL, &intel_g33_driver }, { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33", NULL, &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_IGD_HB, PCI_DEVICE_ID_INTEL_IGD_IG, 0, - "Intel Integrated Graphics Device", NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0, + "Mobile Intel? GM45 Express", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_IGD_E_HB, PCI_DEVICE_ID_INTEL_IGD_E_IG, 0, "Intel Integrated Graphics Device", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG, 0, @@ -2163,8 +2171,8 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, if (intel_agp_chipsets[i].name == NULL) { if (cap_ptr) - printk(KERN_WARNING PFX "Unsupported Intel chipset" - "(device id: %04x)\n", pdev->device); + dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n", + pdev->vendor, pdev->device); agp_put_bridge(bridge); return -ENODEV; } @@ -2172,9 +2180,8 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, if (bridge->driver == NULL) { /* bridge has no AGP and no IGD detected */ if (cap_ptr) - printk(KERN_WARNING PFX "Failed to find bridge device " - "(chip_id: %04x)\n", - intel_agp_chipsets[i].gmch_chip_id); + dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n", + intel_agp_chipsets[i].gmch_chip_id); agp_put_bridge(bridge); return -ENODEV; } @@ -2183,8 +2190,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, bridge->capndx = cap_ptr; bridge->dev_private_data = &intel_private; - printk(KERN_INFO PFX "Detected an Intel %s Chipset.\n", - intel_agp_chipsets[i].name); + dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); /* * The following fixes the case where the BIOS has "forgotten" to @@ -2194,7 +2200,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, r = &pdev->resource[0]; if (!r->start && r->end) { if (pci_assign_resource(pdev, 0)) { - printk(KERN_ERR PFX "could not assign resource 0\n"); + dev_err(&pdev->dev, "can't assign resource 0\n"); agp_put_bridge(bridge); return -ENODEV; } @@ -2206,7 +2212,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, * 20030610 - hamish@zot.org */ if (pci_enable_device(pdev)) { - printk(KERN_ERR PFX "Unable to Enable PCI device\n"); + dev_err(&pdev->dev, "can't enable PCI device\n"); agp_put_bridge(bridge); return -ENODEV; } @@ -2238,6 +2244,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) static int agp_intel_resume(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + int ret_val; pci_restore_state(pdev); @@ -2265,6 +2272,10 @@ static int agp_intel_resume(struct pci_dev *pdev) else if (bridge->driver == &intel_i965_driver) intel_i915_configure(); + ret_val = agp_rebind_memory(); + if (ret_val != 0) + return ret_val; + return 0; } #endif @@ -2315,7 +2326,7 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_G33_HB), ID(PCI_DEVICE_ID_INTEL_Q35_HB), ID(PCI_DEVICE_ID_INTEL_Q33_HB), - ID(PCI_DEVICE_ID_INTEL_IGD_HB), + ID(PCI_DEVICE_ID_INTEL_GM45_HB), ID(PCI_DEVICE_ID_INTEL_IGD_E_HB), ID(PCI_DEVICE_ID_INTEL_Q45_HB), ID(PCI_DEVICE_ID_INTEL_G45_HB), diff --git a/drivers/char/agp/isoch.c b/drivers/char/agp/isoch.c index 3f9ccde6237..c73385cc4b8 100644 --- a/drivers/char/agp/isoch.c +++ b/drivers/char/agp/isoch.c @@ -153,7 +153,7 @@ static int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge, /* Check if this configuration has any chance of working */ if (tot_bw > target.maxbw) { - printk(KERN_ERR PFX "isochronous bandwidth required " + dev_err(&td->dev, "isochronous bandwidth required " "by AGP 3.0 devices exceeds that which is supported by " "the AGP 3.0 bridge!\n"); ret = -ENODEV; @@ -188,7 +188,7 @@ static int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge, /* Exit if the minimal ISOCH_N allocation among the masters is more * than the target can handle. */ if (tot_n > target.n) { - printk(KERN_ERR PFX "number of isochronous " + dev_err(&td->dev, "number of isochronous " "transactions per period required by AGP 3.0 devices " "exceeds that which is supported by the AGP 3.0 " "bridge!\n"); @@ -229,7 +229,7 @@ static int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge, /* Exit if the minimal RQ needs of the masters exceeds what the target * can provide. */ if (tot_rq > rq_isoch) { - printk(KERN_ERR PFX "number of request queue slots " + dev_err(&td->dev, "number of request queue slots " "required by the isochronous bandwidth requested by " "AGP 3.0 devices exceeds the number provided by the " "AGP 3.0 bridge!\n"); @@ -359,8 +359,9 @@ int agp_3_5_enable(struct agp_bridge_data *bridge) case 0x0001: /* Unclassified device */ /* Don't know what this is, but log it for investigation. */ if (mcapndx != 0) { - printk (KERN_INFO PFX "Wacky, found unclassified AGP device. %x:%x\n", - dev->vendor, dev->device); + dev_info(&td->dev, "wacky, found unclassified AGP device %s [%04x/%04x]\n", + pci_name(dev), + dev->vendor, dev->device); } continue; @@ -407,17 +408,18 @@ int agp_3_5_enable(struct agp_bridge_data *bridge) } if (mcapndx == 0) { - printk(KERN_ERR PFX "woah! Non-AGP device " - "found on the secondary bus of an AGP 3.5 bridge!\n"); + dev_err(&td->dev, "woah! Non-AGP device %s on " + "secondary bus of AGP 3.5 bridge!\n", + pci_name(dev)); ret = -ENODEV; goto free_and_exit; } mmajor = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf; if (mmajor < 3) { - printk(KERN_ERR PFX "woah! AGP 2.0 device " - "found on the secondary bus of an AGP 3.5 " - "bridge operating with AGP 3.0 electricals!\n"); + dev_err(&td->dev, "woah! AGP 2.0 device %s on " + "secondary bus of AGP 3.5 bridge operating " + "with AGP 3.0 electricals!\n", pci_name(dev)); ret = -ENODEV; goto free_and_exit; } @@ -427,10 +429,10 @@ int agp_3_5_enable(struct agp_bridge_data *bridge) pci_read_config_dword(dev, cur->capndx+AGPSTAT, &mstatus); if (((mstatus >> 3) & 0x1) == 0) { - printk(KERN_ERR PFX "woah! AGP 3.x device " - "not operating in AGP 3.x mode found on the " - "secondary bus of an AGP 3.5 bridge operating " - "with AGP 3.0 electricals!\n"); + dev_err(&td->dev, "woah! AGP 3.x device %s not " + "operating in AGP 3.x mode on secondary bus " + "of AGP 3.5 bridge operating with AGP 3.0 " + "electricals!\n", pci_name(dev)); ret = -ENODEV; goto free_and_exit; } @@ -444,9 +446,9 @@ int agp_3_5_enable(struct agp_bridge_data *bridge) if (isoch) { ret = agp_3_5_isochronous_node_enable(bridge, dev_list, ndevs); if (ret) { - printk(KERN_INFO PFX "Something bad happened setting " - "up isochronous xfers. Falling back to " - "non-isochronous xfer mode.\n"); + dev_info(&td->dev, "something bad happened setting " + "up isochronous xfers; falling back to " + "non-isochronous xfer mode\n"); } else { goto free_and_exit; } @@ -466,4 +468,3 @@ free_and_exit: get_out: return ret; } - diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index b6791846809..2587ef96a96 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -79,10 +79,8 @@ static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode) u32 command; int rate; - printk(KERN_INFO PFX "Found an AGP %d.%d compliant device at %s.\n", - agp_bridge->major_version, - agp_bridge->minor_version, - pci_name(agp_bridge->dev)); + dev_info(&agp_bridge->dev->dev, "AGP %d.%d bridge\n", + agp_bridge->major_version, agp_bridge->minor_version); pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + PCI_AGP_STATUS, &command); command = agp_collect_device_status(bridge, mode, command); @@ -94,8 +92,8 @@ static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode) if (!agp) continue; - printk(KERN_INFO PFX "Putting AGP V3 device at %s into %dx mode\n", - pci_name(device), rate); + dev_info(&agp_bridge->dev->dev, "putting AGP V3 device at %s into %dx mode\n", + pci_name(device), rate); pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command); @@ -105,7 +103,7 @@ static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode) * cannot be configured */ if (device->device == bridge->dev->device) { - printk(KERN_INFO PFX "SiS delay workaround: giving bridge time to recover.\n"); + dev_info(&agp_bridge->dev->dev, "SiS delay workaround: giving bridge time to recover\n"); msleep(10); } } @@ -190,7 +188,8 @@ static int __devinit agp_sis_probe(struct pci_dev *pdev, return -ENODEV; - printk(KERN_INFO PFX "Detected SiS chipset - id:%i\n", pdev->device); + dev_info(&pdev->dev, "SiS chipset [%04x/%04x]\n", + pdev->vendor, pdev->device); bridge = agp_alloc_bridge(); if (!bridge) return -ENOMEM; @@ -242,7 +241,7 @@ static struct pci_device_id agp_sis_pci_table[] = { .class = (PCI_CLASS_BRIDGE_HOST << 8), .class_mask = ~0, .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_5591_AGP, + .device = PCI_DEVICE_ID_SI_5591, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 0e054c13449..2fb27fe4c10 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -241,7 +241,8 @@ static void serverworks_tlbflush(struct agp_memory *temp) while (readb(serverworks_private.registers+SVWRKS_POSTFLUSH) == 1) { cpu_relax(); if (time_after(jiffies, timeout)) { - printk(KERN_ERR PFX "TLB post flush took more than 3 seconds\n"); + dev_err(&serverworks_private.svrwrks_dev->dev, + "TLB post flush took more than 3 seconds\n"); break; } } @@ -251,7 +252,8 @@ static void serverworks_tlbflush(struct agp_memory *temp) while (readl(serverworks_private.registers+SVWRKS_DIRFLUSH) == 1) { cpu_relax(); if (time_after(jiffies, timeout)) { - printk(KERN_ERR PFX "TLB Dir flush took more than 3 seconds\n"); + dev_err(&serverworks_private.svrwrks_dev->dev, + "TLB Dir flush took more than 3 seconds\n"); break; } } @@ -271,7 +273,7 @@ static int serverworks_configure(void) temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); serverworks_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); if (!serverworks_private.registers) { - printk (KERN_ERR PFX "Unable to ioremap() memory.\n"); + dev_err(&agp_bridge->dev->dev, "can't ioremap(%#x)\n", temp); return -ENOMEM; } @@ -451,7 +453,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, switch (pdev->device) { case 0x0006: - printk (KERN_ERR PFX "ServerWorks CNB20HE is unsupported due to lack of documentation.\n"); + dev_err(&pdev->dev, "ServerWorks CNB20HE is unsupported due to lack of documentation\n"); return -ENODEV; case PCI_DEVICE_ID_SERVERWORKS_HE: @@ -461,8 +463,8 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, default: if (cap_ptr) - printk(KERN_ERR PFX "Unsupported Serverworks chipset " - "(device id: %04x)\n", pdev->device); + dev_err(&pdev->dev, "unsupported Serverworks chipset " + "[%04x/%04x]\n", pdev->vendor, pdev->device); return -ENODEV; } @@ -470,8 +472,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, bridge_dev = pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); if (!bridge_dev) { - printk(KERN_INFO PFX "Detected a Serverworks chipset " - "but could not find the secondary device.\n"); + dev_info(&pdev->dev, "can't find secondary device\n"); return -ENODEV; } @@ -482,8 +483,8 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, if (temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { pci_read_config_dword(pdev, SVWRKS_APSIZE + 4, &temp2); if (temp2 != 0) { - printk(KERN_INFO PFX "Detected 64 bit aperture address, " - "but top bits are not zero. Disabling agp\n"); + dev_info(&pdev->dev, "64 bit aperture address, " + "but top bits are not zero; disabling AGP\n"); return -ENODEV; } serverworks_private.mm_addr_ofs = 0x18; @@ -495,8 +496,8 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, pci_read_config_dword(pdev, serverworks_private.mm_addr_ofs + 4, &temp2); if (temp2 != 0) { - printk(KERN_INFO PFX "Detected 64 bit MMIO address, " - "but top bits are not zero. Disabling agp\n"); + dev_info(&pdev->dev, "64 bit MMIO address, but top " + "bits are not zero; disabling AGP\n"); return -ENODEV; } } diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index d2fa3cfca02..eef72709ec5 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -46,8 +46,8 @@ static int uninorth_fetch_size(void) break; if (i == agp_bridge->driver->num_aperture_sizes) { - printk(KERN_ERR PFX "Invalid aperture size, using" - " default\n"); + dev_err(&agp_bridge->dev->dev, "invalid aperture size, " + "using default\n"); size = 0; aperture = NULL; } @@ -108,8 +108,8 @@ static int uninorth_configure(void) current_size = A_SIZE_32(agp_bridge->current_size); - printk(KERN_INFO PFX "configuring for size idx: %d\n", - current_size->size_value); + dev_info(&agp_bridge->dev->dev, "configuring for size idx: %d\n", + current_size->size_value); /* aperture size and gatt addr */ pci_write_config_dword(agp_bridge->dev, @@ -197,8 +197,9 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type) gp = (u32 *) &agp_bridge->gatt_table[pg_start]; for (i = 0; i < mem->page_count; ++i) { if (gp[i]) { - printk("u3_insert_memory: entry 0x%x occupied (%x)\n", - i, gp[i]); + dev_info(&agp_bridge->dev->dev, + "u3_insert_memory: entry 0x%x occupied (%x)\n", + i, gp[i]); return -EBUSY; } } @@ -276,8 +277,8 @@ static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode) &scratch); } while ((scratch & PCI_AGP_COMMAND_AGP) == 0 && ++timeout < 1000); if ((scratch & PCI_AGP_COMMAND_AGP) == 0) - printk(KERN_ERR PFX "failed to write UniNorth AGP" - " command register\n"); + dev_err(&bridge->dev->dev, "can't write UniNorth AGP " + "command register\n"); if (uninorth_rev >= 0x30) { /* This is an AGP V3 */ @@ -330,8 +331,8 @@ static int agp_uninorth_suspend(struct pci_dev *pdev) pci_read_config_dword(device, agp + PCI_AGP_COMMAND, &cmd); if (!(cmd & PCI_AGP_COMMAND_AGP)) continue; - printk("uninorth-agp: disabling AGP on device %s\n", - pci_name(device)); + dev_info(&pdev->dev, "disabling AGP on device %s\n", + pci_name(device)); cmd &= ~PCI_AGP_COMMAND_AGP; pci_write_config_dword(device, agp + PCI_AGP_COMMAND, cmd); } @@ -341,8 +342,7 @@ static int agp_uninorth_suspend(struct pci_dev *pdev) pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd); bridge->dev_private_data = (void *)(long)cmd; if (cmd & PCI_AGP_COMMAND_AGP) { - printk("uninorth-agp: disabling AGP on bridge %s\n", - pci_name(pdev)); + dev_info(&pdev->dev, "disabling AGP on bridge\n"); cmd &= ~PCI_AGP_COMMAND_AGP; pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND, cmd); } @@ -591,14 +591,14 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev, /* probe for known chipsets */ for (j = 0; devs[j].chipset_name != NULL; ++j) { if (pdev->device == devs[j].device_id) { - printk(KERN_INFO PFX "Detected Apple %s chipset\n", - devs[j].chipset_name); + dev_info(&pdev->dev, "Apple %s chipset\n", + devs[j].chipset_name); goto found; } } - printk(KERN_ERR PFX "Unsupported Apple chipset (device id: %04x).\n", - pdev->device); + dev_err(&pdev->dev, "unsupported Apple chipset [%04x/%04x]\n", + pdev->vendor, pdev->device); return -ENODEV; found: diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 02aac104842..fd64137b1ab 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -322,11 +322,10 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) hp->tty = tty; - if (hp->ops->notifier_add) - rc = hp->ops->notifier_add(hp, hp->data); - spin_unlock_irqrestore(&hp->lock, flags); + if (hp->ops->notifier_add) + rc = hp->ops->notifier_add(hp, hp->data); /* * If the notifier fails we return an error. The tty layer diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index d9799e2bcfb..f53d4d00faf 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -78,7 +78,6 @@ #include <linux/wait.h> #include <linux/bcd.h> #include <linux/delay.h> -#include <linux/smp_lock.h> #include <linux/uaccess.h> #include <asm/current.h> diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e1b46bc7e43..0e6866fe0f9 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1161,8 +1161,8 @@ void disassociate_ctty(int on_exit) tty = get_current_tty(); if (tty) { tty_pgrp = get_pid(tty->pgrp); - mutex_unlock(&tty_mutex); lock_kernel(); + mutex_unlock(&tty_mutex); /* XXX: here we race, there is nothing protecting tty */ if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 31a0e0b455b..97b003839fb 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -21,8 +21,8 @@ static int __init cpuidle_sysfs_setup(char *unused) } __setup("cpuidle_sysfs_switch", cpuidle_sysfs_setup); -static ssize_t show_available_governors(struct sys_device *dev, - struct sysdev_attribute *attr, char *buf) +static ssize_t show_available_governors(struct sysdev_class *class, + char *buf) { ssize_t i = 0; struct cpuidle_governor *tmp; @@ -40,8 +40,8 @@ out: return i; } -static ssize_t show_current_driver(struct sys_device *dev, - struct sysdev_attribute *attr, char *buf) +static ssize_t show_current_driver(struct sysdev_class *class, + char *buf) { ssize_t ret; @@ -55,8 +55,8 @@ static ssize_t show_current_driver(struct sys_device *dev, return ret; } -static ssize_t show_current_governor(struct sys_device *dev, - struct sysdev_attribute *attr, char *buf) +static ssize_t show_current_governor(struct sysdev_class *class, + char *buf) { ssize_t ret; @@ -70,9 +70,8 @@ static ssize_t show_current_governor(struct sys_device *dev, return ret; } -static ssize_t store_current_governor(struct sys_device *dev, - struct sysdev_attribute *attr, - const char *buf, size_t count) +static ssize_t store_current_governor(struct sysdev_class *class, + const char *buf, size_t count) { char gov_name[CPUIDLE_NAME_LEN]; int ret = -EINVAL; @@ -104,8 +103,9 @@ static ssize_t store_current_governor(struct sys_device *dev, return count; } -static SYSDEV_ATTR(current_driver, 0444, show_current_driver, NULL); -static SYSDEV_ATTR(current_governor_ro, 0444, show_current_governor, NULL); +static SYSDEV_CLASS_ATTR(current_driver, 0444, show_current_driver, NULL); +static SYSDEV_CLASS_ATTR(current_governor_ro, 0444, show_current_governor, + NULL); static struct attribute *cpuclass_default_attrs[] = { &attr_current_driver.attr, @@ -113,9 +113,10 @@ static struct attribute *cpuclass_default_attrs[] = { NULL }; -static SYSDEV_ATTR(available_governors, 0444, show_available_governors, NULL); -static SYSDEV_ATTR(current_governor, 0644, show_current_governor, - store_current_governor); +static SYSDEV_CLASS_ATTR(available_governors, 0444, show_available_governors, + NULL); +static SYSDEV_CLASS_ATTR(current_governor, 0644, show_current_governor, + store_current_governor); static struct attribute *cpuclass_switch_attrs[] = { &attr_available_governors.attr, diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c index 001622eb86f..3bf8ee120d4 100644 --- a/drivers/firmware/memmap.c +++ b/drivers/firmware/memmap.c @@ -84,20 +84,23 @@ static struct kobj_type memmap_ktype = { */ /* - * Firmware memory map entries + * Firmware memory map entries. No locking is needed because the + * firmware_map_add() and firmware_map_add_early() functions are called + * in firmware initialisation code in one single thread of execution. */ static LIST_HEAD(map_entries); /** - * Common implementation of firmware_map_add() and firmware_map_add_early() - * which expects a pre-allocated struct firmware_map_entry. - * + * firmware_map_add_entry() - Does the real work to add a firmware memmap entry. * @start: Start of the memory range. * @end: End of the memory range (inclusive). * @type: Type of the memory range. * @entry: Pre-allocated (either kmalloc() or bootmem allocator), uninitialised * entry. - */ + * + * Common implementation of firmware_map_add() and firmware_map_add_early() + * which expects a pre-allocated struct firmware_map_entry. + **/ static int firmware_map_add_entry(resource_size_t start, resource_size_t end, const char *type, struct firmware_map_entry *entry) @@ -115,33 +118,52 @@ static int firmware_map_add_entry(resource_size_t start, resource_size_t end, return 0; } -/* - * See <linux/firmware-map.h> for documentation. - */ +/** + * firmware_map_add() - Adds a firmware mapping entry. + * @start: Start of the memory range. + * @end: End of the memory range (inclusive). + * @type: Type of the memory range. + * + * This function uses kmalloc() for memory + * allocation. Use firmware_map_add_early() if you want to use the bootmem + * allocator. + * + * That function must be called before late_initcall. + * + * Returns 0 on success, or -ENOMEM if no memory could be allocated. + **/ int firmware_map_add(resource_size_t start, resource_size_t end, const char *type) { struct firmware_map_entry *entry; entry = kmalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC); - WARN_ON(!entry); if (!entry) return -ENOMEM; return firmware_map_add_entry(start, end, type, entry); } -/* - * See <linux/firmware-map.h> for documentation. - */ +/** + * firmware_map_add_early() - Adds a firmware mapping entry. + * @start: Start of the memory range. + * @end: End of the memory range (inclusive). + * @type: Type of the memory range. + * + * Adds a firmware mapping entry. This function uses the bootmem allocator + * for memory allocation. Use firmware_map_add() if you want to use kmalloc(). + * + * That function must be called before late_initcall. + * + * Returns 0 on success, or -ENOMEM if no memory could be allocated. + **/ int __init firmware_map_add_early(resource_size_t start, resource_size_t end, const char *type) { struct firmware_map_entry *entry; entry = alloc_bootmem_low(sizeof(struct firmware_map_entry)); - WARN_ON(!entry); - if (!entry) + if (WARN_ON(!entry)) return -ENOMEM; return firmware_map_add_entry(start, end, type, entry); @@ -183,7 +205,10 @@ static ssize_t memmap_attr_show(struct kobject *kobj, /* * Initialises stuff and adds the entries in the map_entries list to * sysfs. Important is that firmware_map_add() and firmware_map_add_early() - * must be called before late_initcall. + * must be called before late_initcall. That's just because that function + * is called as late_initcall() function, which means that if you call + * firmware_map_add() or firmware_map_add_early() afterwards, the entries + * are not added to sysfs. */ static int __init memmap_init(void) { @@ -192,13 +217,13 @@ static int __init memmap_init(void) struct kset *memmap_kset; memmap_kset = kset_create_and_add("memmap", NULL, firmware_kobj); - WARN_ON(!memmap_kset); - if (!memmap_kset) + if (WARN_ON(!memmap_kset)) return -ENOMEM; list_for_each_entry(entry, &map_entries, list) { entry->kobj.kset = memmap_kset; - kobject_add(&entry->kobj, NULL, "%d", i++); + if (kobject_add(&entry->kobj, NULL, "%d", i++)) + kobject_put(&entry->kobj); } return 0; diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 7880c273c2c..8f9595f2fb5 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -54,11 +54,11 @@ enum lm75_type { /* keep sorted in alphabetical order */ tmp75, }; -/* Addresses scanned by legacy style driver binding */ +/* Addresses scanned */ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -/* Insmod parameters (only for legacy style driver binding) */ +/* Insmod parameters */ I2C_CLIENT_INSMOD_1(lm75); @@ -72,7 +72,6 @@ static const u8 LM75_REG_TEMP[3] = { /* Each client has this additional data */ struct lm75_data { - struct i2c_client *client; struct device *hwmon_dev; struct mutex update_lock; u8 orig_conf; @@ -138,7 +137,7 @@ static const struct attribute_group lm75_group = { /*-----------------------------------------------------------------------*/ -/* "New style" I2C driver binding -- following the driver model */ +/* device probe and removal */ static int lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -157,8 +156,6 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) return -ENOMEM; i2c_set_clientdata(client, data); - - data->client = client; mutex_init(&data->update_lock); /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. @@ -236,45 +233,16 @@ static const struct i2c_device_id lm75_ids[] = { }; MODULE_DEVICE_TABLE(i2c, lm75_ids); -static struct i2c_driver lm75_driver = { - .driver = { - .name = "lm75", - }, - .probe = lm75_probe, - .remove = lm75_remove, - .id_table = lm75_ids, -}; - -/*-----------------------------------------------------------------------*/ - -/* "Legacy" I2C driver binding */ - -static struct i2c_driver lm75_legacy_driver; - -/* This function is called by i2c_probe */ -static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int lm75_detect(struct i2c_client *new_client, int kind, + struct i2c_board_info *info) { + struct i2c_adapter *adapter = new_client->adapter; int i; - struct i2c_client *new_client; - int err = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid address. We create the - client structure, even though there may be no sensor present. - But it allows us to use i2c_smbus_read_*_data() calls. */ - new_client = kzalloc(sizeof *new_client, GFP_KERNEL); - if (!new_client) { - err = -ENOMEM; - goto exit; - } - - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm75_legacy_driver; - new_client->flags = 0; + return -ENODEV; /* Now, we do the remaining detection. There is no identification- dedicated register so we have to rely on several tricks: @@ -294,71 +262,44 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) || i2c_smbus_read_word_data(new_client, 5) != hyst || i2c_smbus_read_word_data(new_client, 6) != hyst || i2c_smbus_read_word_data(new_client, 7) != hyst) - goto exit_free; + return -ENODEV; os = i2c_smbus_read_word_data(new_client, 3); if (i2c_smbus_read_word_data(new_client, 4) != os || i2c_smbus_read_word_data(new_client, 5) != os || i2c_smbus_read_word_data(new_client, 6) != os || i2c_smbus_read_word_data(new_client, 7) != os) - goto exit_free; + return -ENODEV; /* Unused bits */ if (conf & 0xe0) - goto exit_free; + return -ENODEV; /* Addresses cycling */ for (i = 8; i < 0xff; i += 8) if (i2c_smbus_read_byte_data(new_client, i + 1) != conf || i2c_smbus_read_word_data(new_client, i + 2) != hyst || i2c_smbus_read_word_data(new_client, i + 3) != os) - goto exit_free; + return -ENODEV; } /* NOTE: we treat "force=..." and "force_lm75=..." the same. * Only new-style driver binding distinguishes chip types. */ - strlcpy(new_client->name, "lm75", I2C_NAME_SIZE); - - /* Tell the I2C layer a new client has arrived */ - err = i2c_attach_client(new_client); - if (err) - goto exit_free; - - err = lm75_probe(new_client, NULL); - if (err < 0) - goto exit_detach; + strlcpy(info->type, "lm75", I2C_NAME_SIZE); return 0; - -exit_detach: - i2c_detach_client(new_client); -exit_free: - kfree(new_client); -exit: - return err; -} - -static int lm75_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_probe(adapter, &addr_data, lm75_detect); } -static int lm75_detach_client(struct i2c_client *client) -{ - lm75_remove(client); - i2c_detach_client(client); - kfree(client); - return 0; -} - -static struct i2c_driver lm75_legacy_driver = { +static struct i2c_driver lm75_driver = { + .class = I2C_CLASS_HWMON, .driver = { - .name = "lm75_legacy", + .name = "lm75", }, - .attach_adapter = lm75_attach_adapter, - .detach_client = lm75_detach_client, + .probe = lm75_probe, + .remove = lm75_remove, + .id_table = lm75_ids, + .detect = lm75_detect, + .address_data = &addr_data, }; /*-----------------------------------------------------------------------*/ @@ -424,22 +365,11 @@ static struct lm75_data *lm75_update_device(struct device *dev) static int __init sensors_lm75_init(void) { - int status; - - status = i2c_add_driver(&lm75_driver); - if (status < 0) - return status; - - status = i2c_add_driver(&lm75_legacy_driver); - if (status < 0) - i2c_del_driver(&lm75_driver); - - return status; + return i2c_add_driver(&lm75_driver); } static void __exit sensors_lm75_exit(void) { - i2c_del_driver(&lm75_legacy_driver); i2c_del_driver(&lm75_driver); } diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 96867347bcb..711ca08ab77 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -38,6 +38,20 @@ config I2C_CHARDEV This support is also available as a module. If so, the module will be called i2c-dev. +config I2C_HELPER_AUTO + bool "Autoselect pertinent helper modules" + default y + help + Some I2C bus drivers require so-called "I2C algorithm" modules + to work. These are basically software-only abstractions of generic + I2C interfaces. This option will autoselect them so that you don't + have to care. + + Unselect this only if you need to enable additional helper + modules, for example for use with external I2C bus drivers. + + In doubt, say Y. + source drivers/i2c/algos/Kconfig source drivers/i2c/busses/Kconfig source drivers/i2c/chips/Kconfig diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig index 7137a17402f..b788579b822 100644 --- a/drivers/i2c/algos/Kconfig +++ b/drivers/i2c/algos/Kconfig @@ -2,15 +2,20 @@ # I2C algorithm drivers configuration # +menu "I2C Algorithms" + depends on !I2C_HELPER_AUTO + config I2C_ALGOBIT - tristate + tristate "I2C bit-banging interfaces" config I2C_ALGOPCF - tristate + tristate "I2C PCF 8584 interfaces" config I2C_ALGOPCA - tristate + tristate "I2C PCA 9564 interfaces" config I2C_ALGO_SGI tristate depends on SGI_IP22 || SGI_IP32 || X86_VISWS + +endmenu diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index 72872d1e63e..8ba2bcf727d 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -155,6 +155,9 @@ static int __init amd756_s4882_init(void) int i, error; union i2c_smbus_data ioconfig; + if (!amd756_smbus.dev.parent) + return -ENODEV; + /* Configure the PCA9556 multiplexer */ ioconfig.byte = 0x00; /* All I/O to output mode */ error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03, @@ -168,11 +171,7 @@ static int __init amd756_s4882_init(void) /* Unregister physical bus */ error = i2c_del_adapter(&amd756_smbus); if (error) { - if (error == -EINVAL) - error = -ENODEV; - else - dev_err(&amd756_smbus.dev, "Physical bus removal " - "failed\n"); + dev_err(&amd756_smbus.dev, "Physical bus removal failed\n"); goto ERROR0; } diff --git a/drivers/i2c/busses/i2c-nforce2-s4985.c b/drivers/i2c/busses/i2c-nforce2-s4985.c index d1a4cbcf2aa..29015eb9ca4 100644 --- a/drivers/i2c/busses/i2c-nforce2-s4985.c +++ b/drivers/i2c/busses/i2c-nforce2-s4985.c @@ -150,6 +150,9 @@ static int __init nforce2_s4985_init(void) int i, error; union i2c_smbus_data ioconfig; + if (!nforce2_smbus) + return -ENODEV; + /* Configure the PCA9556 multiplexer */ ioconfig.byte = 0x00; /* All I/O to output mode */ error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03, @@ -161,8 +164,6 @@ static int __init nforce2_s4985_init(void) } /* Unregister physical bus */ - if (!nforce2_smbus) - return -ENODEV; error = i2c_del_adapter(nforce2_smbus); if (error) { dev_err(&nforce2_smbus->dev, "Physical bus removal failed\n"); diff --git a/drivers/i2c/chips/at24.c b/drivers/i2c/chips/at24.c index e764c94f3e3..2a4acb26956 100644 --- a/drivers/i2c/chips/at24.c +++ b/drivers/i2c/chips/at24.c @@ -188,7 +188,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, count = I2C_SMBUS_BLOCK_MAX; status = i2c_smbus_read_i2c_block_data(client, offset, count, buf); - dev_dbg(&client->dev, "smbus read %zd@%d --> %d\n", + dev_dbg(&client->dev, "smbus read %zu@%d --> %d\n", count, offset, status); return (status < 0) ? -EIO : status; } @@ -214,7 +214,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, msg[1].len = count; status = i2c_transfer(client->adapter, msg, 2); - dev_dbg(&client->dev, "i2c read %zd@%d --> %d\n", + dev_dbg(&client->dev, "i2c read %zu@%d --> %d\n", count, offset, status); if (status == 2) @@ -334,7 +334,7 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, char *buf, if (status == 1) status = count; } - dev_dbg(&client->dev, "write %zd@%d --> %zd (%ld)\n", + dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", count, offset, status, jiffies); if (status == count) @@ -512,7 +512,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) i2c_set_clientdata(client, at24); - dev_info(&client->dev, "%Zd byte %s EEPROM %s\n", + dev_info(&client->dev, "%zu byte %s EEPROM %s\n", at24->bin.size, client->name, writable ? "(writable)" : "(read-only)"); dev_dbg(&client->dev, diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 7bf38c41808..550853f79ae 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -813,7 +813,12 @@ static int i2c_check_addr(struct i2c_adapter *adapter, int addr) int i2c_attach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - int res = 0; + int res; + + /* Check for address business */ + res = i2c_check_addr(adapter, client->addr); + if (res) + return res; client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; @@ -1451,9 +1456,11 @@ i2c_new_probed_device(struct i2c_adapter *adap, if ((addr_list[i] & ~0x07) == 0x30 || (addr_list[i] & ~0x0f) == 0x50 || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) { + union i2c_smbus_data data; + if (i2c_smbus_xfer(adap, addr_list[i], 0, I2C_SMBUS_READ, 0, - I2C_SMBUS_BYTE, NULL) >= 0) + I2C_SMBUS_BYTE, &data) >= 0) break; } else { if (i2c_smbus_xfer(adap, addr_list[i], 0, diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 9d55c6383b2..af4491fa7e3 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -147,7 +147,7 @@ static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count, if (tmp==NULL) return -ENOMEM; - pr_debug("i2c-dev: i2c-%d reading %zd bytes.\n", + pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n", iminor(file->f_path.dentry->d_inode), count); ret = i2c_master_recv(client,tmp,count); @@ -175,7 +175,7 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c return -EFAULT; } - pr_debug("i2c-dev: i2c-%d writing %zd bytes.\n", + pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n", iminor(file->f_path.dentry->d_inode), count); ret = i2c_master_send(client,tmp,count); diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 0b0618edd64..1ab919f836a 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -156,6 +156,14 @@ struct ehca_mod_qp_parm { #define EHCA_MOD_QP_PARM_MAX 4 +#define QMAP_IDX_MASK 0xFFFFULL + +/* struct for tracking if cqes have been reported to the application */ +struct ehca_qmap_entry { + u16 app_wr_id; + u16 reported; +}; + struct ehca_qp { union { struct ib_qp ib_qp; @@ -165,6 +173,7 @@ struct ehca_qp { enum ehca_ext_qp_type ext_type; enum ib_qp_state state; struct ipz_queue ipz_squeue; + struct ehca_qmap_entry *sq_map; struct ipz_queue ipz_rqueue; struct h_galpas galpas; u32 qkey; diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h index 818803057eb..5d28e3e98a2 100644 --- a/drivers/infiniband/hw/ehca/ehca_qes.h +++ b/drivers/infiniband/hw/ehca/ehca_qes.h @@ -213,6 +213,7 @@ struct ehca_wqe { #define WC_STATUS_ERROR_BIT 0x80000000 #define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800 #define WC_STATUS_PURGE_BIT 0x10 +#define WC_SEND_RECEIVE_BIT 0x80 struct ehca_cqe { u64 work_request_id; diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index ea13efddf17..b6bcee03673 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -412,6 +412,7 @@ static struct ehca_qp *internal_create_qp( struct ehca_shca *shca = container_of(pd->device, struct ehca_shca, ib_device); struct ib_ucontext *context = NULL; + u32 nr_qes; u64 h_ret; int is_llqp = 0, has_srq = 0; int qp_type, max_send_sge, max_recv_sge, ret; @@ -715,6 +716,15 @@ static struct ehca_qp *internal_create_qp( "and pages ret=%i", ret); goto create_qp_exit2; } + nr_qes = my_qp->ipz_squeue.queue_length / + my_qp->ipz_squeue.qe_size; + my_qp->sq_map = vmalloc(nr_qes * + sizeof(struct ehca_qmap_entry)); + if (!my_qp->sq_map) { + ehca_err(pd->device, "Couldn't allocate squeue " + "map ret=%i", ret); + goto create_qp_exit3; + } } if (HAS_RQ(my_qp)) { @@ -724,7 +734,7 @@ static struct ehca_qp *internal_create_qp( if (ret) { ehca_err(pd->device, "Couldn't initialize rqueue " "and pages ret=%i", ret); - goto create_qp_exit3; + goto create_qp_exit4; } } @@ -770,7 +780,7 @@ static struct ehca_qp *internal_create_qp( if (!my_qp->mod_qp_parm) { ehca_err(pd->device, "Could not alloc mod_qp_parm"); - goto create_qp_exit4; + goto create_qp_exit5; } } } @@ -780,7 +790,7 @@ static struct ehca_qp *internal_create_qp( h_ret = ehca_define_sqp(shca, my_qp, init_attr); if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); - goto create_qp_exit5; + goto create_qp_exit6; } } @@ -789,7 +799,7 @@ static struct ehca_qp *internal_create_qp( if (ret) { ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%i", ret); - goto create_qp_exit5; + goto create_qp_exit6; } } @@ -815,22 +825,26 @@ static struct ehca_qp *internal_create_qp( if (ib_copy_to_udata(udata, &resp, sizeof resp)) { ehca_err(pd->device, "Copy to udata failed"); ret = -EINVAL; - goto create_qp_exit6; + goto create_qp_exit7; } } return my_qp; -create_qp_exit6: +create_qp_exit7: ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num); -create_qp_exit5: +create_qp_exit6: kfree(my_qp->mod_qp_parm); -create_qp_exit4: +create_qp_exit5: if (HAS_RQ(my_qp)) ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); +create_qp_exit4: + if (HAS_SQ(my_qp)) + vfree(my_qp->sq_map); + create_qp_exit3: if (HAS_SQ(my_qp)) ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); @@ -1534,8 +1548,6 @@ static int internal_modify_qp(struct ib_qp *ibqp, if (attr_mask & IB_QP_QKEY) my_qp->qkey = attr->qkey; - my_qp->state = qp_new_state; - modify_qp_exit2: if (squeue_locked) { /* this means: sqe -> rts */ spin_unlock_irqrestore(&my_qp->spinlock_s, flags); @@ -1551,6 +1563,8 @@ modify_qp_exit1: int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata) { + int ret = 0; + struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca, ib_device); struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); @@ -1597,12 +1611,18 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, attr->qp_state, my_qp->init_attr.port_num, ibqp->qp_type); spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); - return 0; + goto out; } spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); } - return internal_modify_qp(ibqp, attr, attr_mask, 0); + ret = internal_modify_qp(ibqp, attr, attr_mask, 0); + +out: + if ((ret == 0) && (attr_mask & IB_QP_STATE)) + my_qp->state = attr->qp_state; + + return ret; } void ehca_recover_sqp(struct ib_qp *sqp) @@ -1973,8 +1993,10 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, if (HAS_RQ(my_qp)) ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); - if (HAS_SQ(my_qp)) + if (HAS_SQ(my_qp)) { ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); + vfree(my_qp->sq_map); + } kmem_cache_free(qp_cache, my_qp); atomic_dec(&shca->num_qps); return 0; diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index 898c8b5c38d..4426d82fe79 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -139,6 +139,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr) static inline int ehca_write_swqe(struct ehca_qp *qp, struct ehca_wqe *wqe_p, const struct ib_send_wr *send_wr, + u32 sq_map_idx, int hidden) { u32 idx; @@ -157,7 +158,11 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, /* clear wqe header until sglist */ memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); - wqe_p->work_request_id = send_wr->wr_id; + wqe_p->work_request_id = send_wr->wr_id & ~QMAP_IDX_MASK; + wqe_p->work_request_id |= sq_map_idx & QMAP_IDX_MASK; + + qp->sq_map[sq_map_idx].app_wr_id = send_wr->wr_id & QMAP_IDX_MASK; + qp->sq_map[sq_map_idx].reported = 0; switch (send_wr->opcode) { case IB_WR_SEND: @@ -381,6 +386,7 @@ static inline int post_one_send(struct ehca_qp *my_qp, { struct ehca_wqe *wqe_p; int ret; + u32 sq_map_idx; u64 start_offset = my_qp->ipz_squeue.current_q_offset; /* get pointer next to free WQE */ @@ -393,8 +399,15 @@ static inline int post_one_send(struct ehca_qp *my_qp, "qp_num=%x", my_qp->ib_qp.qp_num); return -ENOMEM; } + + /* + * Get the index of the WQE in the send queue. The same index is used + * for writing into the sq_map. + */ + sq_map_idx = start_offset / my_qp->ipz_squeue.qe_size; + /* write a SEND WQE into the QUEUE */ - ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, hidden); + ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, sq_map_idx, hidden); /* * if something failed, * reset the free entry pointer to the start value @@ -589,7 +602,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) struct ehca_qp *my_qp; int cqe_count = 0, is_error; -poll_cq_one_read_cqe: +repoll: cqe = (struct ehca_cqe *) ipz_qeit_get_inc_valid(&my_cq->ipz_queue); if (!cqe) { @@ -617,7 +630,7 @@ poll_cq_one_read_cqe: ehca_dmp(cqe, 64, "cq_num=%x qp_num=%x", my_cq->cq_number, cqe->local_qp_number); /* ignore this purged cqe */ - goto poll_cq_one_read_cqe; + goto repoll; } spin_lock_irqsave(&qp->spinlock_s, flags); purgeflag = qp->sqerr_purgeflag; @@ -636,7 +649,7 @@ poll_cq_one_read_cqe: * that caused sqe and turn off purge flag */ qp->sqerr_purgeflag = 0; - goto poll_cq_one_read_cqe; + goto repoll; } } @@ -654,8 +667,34 @@ poll_cq_one_read_cqe: my_cq, my_cq->cq_number); } - /* we got a completion! */ - wc->wr_id = cqe->work_request_id; + read_lock(&ehca_qp_idr_lock); + my_qp = idr_find(&ehca_qp_idr, cqe->qp_token); + read_unlock(&ehca_qp_idr_lock); + if (!my_qp) + goto repoll; + wc->qp = &my_qp->ib_qp; + + if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT)) { + struct ehca_qmap_entry *qmap_entry; + /* + * We got a send completion and need to restore the original + * wr_id. + */ + qmap_entry = &my_qp->sq_map[cqe->work_request_id & + QMAP_IDX_MASK]; + + if (qmap_entry->reported) { + ehca_warn(cq->device, "Double cqe on qp_num=%#x", + my_qp->real_qp_num); + /* found a double cqe, discard it and read next one */ + goto repoll; + } + wc->wr_id = cqe->work_request_id & ~QMAP_IDX_MASK; + wc->wr_id |= qmap_entry->app_wr_id; + qmap_entry->reported = 1; + } else + /* We got a receive completion. */ + wc->wr_id = cqe->work_request_id; /* eval ib_wc_opcode */ wc->opcode = ib_wc_opcode[cqe->optype]-1; @@ -667,7 +706,7 @@ poll_cq_one_read_cqe: ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x", my_cq, my_cq->cq_number); /* update also queue adder to throw away this entry!!! */ - goto poll_cq_one_exit0; + goto repoll; } /* eval ib_wc_status */ @@ -678,11 +717,6 @@ poll_cq_one_read_cqe: } else wc->status = IB_WC_SUCCESS; - read_lock(&ehca_qp_idr_lock); - my_qp = idr_find(&ehca_qp_idr, cqe->qp_token); - wc->qp = &my_qp->ib_qp; - read_unlock(&ehca_qp_idr_lock); - wc->byte_len = cqe->nr_bytes_transferred; wc->pkey_index = cqe->pkey_index; wc->slid = cqe->rlid; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 7ebc400a4b3..341ffedafed 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -202,7 +202,7 @@ static void ipoib_cm_free_rx_ring(struct net_device *dev, dev_kfree_skb_any(rx_ring[i].skb); } - kfree(rx_ring); + vfree(rx_ring); } static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv *priv) @@ -352,9 +352,14 @@ static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_i int ret; int i; - rx->rx_ring = kcalloc(ipoib_recvq_size, sizeof *rx->rx_ring, GFP_KERNEL); - if (!rx->rx_ring) + rx->rx_ring = vmalloc(ipoib_recvq_size * sizeof *rx->rx_ring); + if (!rx->rx_ring) { + printk(KERN_WARNING "%s: failed to allocate CM non-SRQ ring (%d entries)\n", + priv->ca->name, ipoib_recvq_size); return -ENOMEM; + } + + memset(rx->rx_ring, 0, ipoib_recvq_size * sizeof *rx->rx_ring); t = kmalloc(sizeof *t, GFP_KERNEL); if (!t) { @@ -1494,14 +1499,16 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) return; } - priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring, - GFP_KERNEL); + priv->cm.srq_ring = vmalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring); if (!priv->cm.srq_ring) { printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n", priv->ca->name, ipoib_recvq_size); ib_destroy_srq(priv->cm.srq); priv->cm.srq = NULL; + return; } + + memset(priv->cm.srq_ring, 0, ipoib_recvq_size * sizeof *priv->cm.srq_ring); } int ipoib_cm_dev_init(struct net_device *dev) diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index d93500f24fb..81d0c605344 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c @@ -108,9 +108,8 @@ static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr) } /*:*/ -/*M:014 get_pfn is slow; it takes the mmap sem and calls get_user_pages. We - * could probably try to grab batches of pages here as an optimization - * (ie. pre-faulting). :*/ +/*M:014 get_pfn is slow: we could probably try to grab batches of pages here as + * an optimization (ie. pre-faulting). :*/ /*H:350 This routine takes a page number given by the Guest and converts it to * an actual, physical page number. It can fail for several reasons: the @@ -123,19 +122,13 @@ static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr) static unsigned long get_pfn(unsigned long virtpfn, int write) { struct page *page; - /* This value indicates failure. */ - unsigned long ret = -1UL; - /* get_user_pages() is a complex interface: it gets the "struct - * vm_area_struct" and "struct page" assocated with a range of pages. - * It also needs the task's mmap_sem held, and is not very quick. - * It returns the number of pages it got. */ - down_read(¤t->mm->mmap_sem); - if (get_user_pages(current, current->mm, virtpfn << PAGE_SHIFT, - 1, write, 1, &page, NULL) == 1) - ret = page_to_pfn(page); - up_read(¤t->mm->mmap_sem); - return ret; + /* gup me one page at this address please! */ + if (get_user_pages_fast(virtpfn << PAGE_SHIFT, 1, write, &page) == 1) + return page_to_pfn(page); + + /* This value indicates failure. */ + return -1UL; } /*H:340 Converting a Guest page table entry to a shadow (ie. real) page table @@ -174,7 +167,7 @@ static pte_t gpte_to_spte(struct lg_cpu *cpu, pte_t gpte, int write) /*H:460 And to complete the chain, release_pte() looks like this: */ static void release_pte(pte_t pte) { - /* Remember that get_user_pages() took a reference to the page, in + /* Remember that get_user_pages_fast() took a reference to the page, in * get_pfn()? We have to put it back now. */ if (pte_flags(pte) & _PAGE_PRESENT) put_page(pfn_to_page(pte_pfn(pte))); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 883e7ea31de..10c44d3fe01 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -50,10 +50,31 @@ config HTC_PASIC3 HTC Magician devices, respectively. Actual functionality is handled by the leds-pasic3 and ds1wm drivers. +config MFD_TMIO + bool + default n + +config MFD_T7L66XB + bool "Support Toshiba T7L66XB" + depends on ARM + select MFD_CORE + select MFD_TMIO + help + Support for Toshiba Mobile IO Controller T7L66XB + +config MFD_TC6387XB + bool "Support Toshiba TC6387XB" + depends on ARM + select MFD_CORE + select MFD_TMIO + help + Support for Toshiba Mobile IO Controller TC6387XB + config MFD_TC6393XB bool "Support Toshiba TC6393XB" depends on GPIOLIB && ARM select MFD_CORE + select MFD_TMIO help Support for Toshiba Mobile IO Controller TC6393XB diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 33daa2f45dd..03ad239ecef 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -8,6 +8,8 @@ obj-$(CONFIG_MFD_ASIC3) += asic3.o obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o +obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o +obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o obj-$(CONFIG_MFD_CORE) += mfd-core.o diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c new file mode 100644 index 00000000000..49a0fffc02a --- /dev/null +++ b/drivers/mfd/t7l66xb.c @@ -0,0 +1,419 @@ +/* + * + * Toshiba T7L66XB core mfd support + * + * Copyright (c) 2005, 2007, 2008 Ian Molton + * Copyright (c) 2008 Dmitry Baryshkov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * T7L66 features: + * + * Supported in this driver: + * SD/MMC + * SM/NAND flash controller + * + * As yet not supported + * GPIO interface (on NAND pins) + * Serial interface + * TFT 'interface converter' + * PCMCIA interface logic + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/mfd/core.h> +#include <linux/mfd/tmio.h> +#include <linux/mfd/t7l66xb.h> + +enum { + T7L66XB_CELL_NAND, + T7L66XB_CELL_MMC, +}; + +#define SCR_REVID 0x08 /* b Revision ID */ +#define SCR_IMR 0x42 /* b Interrupt Mask */ +#define SCR_DEV_CTL 0xe0 /* b Device control */ +#define SCR_ISR 0xe1 /* b Interrupt Status */ +#define SCR_GPO_OC 0xf0 /* b GPO output control */ +#define SCR_GPO_OS 0xf1 /* b GPO output enable */ +#define SCR_GPI_S 0xf2 /* w GPI status */ +#define SCR_APDC 0xf8 /* b Active pullup down ctrl */ + +#define SCR_DEV_CTL_USB BIT(0) /* USB enable */ +#define SCR_DEV_CTL_MMC BIT(1) /* MMC enable */ + +/*--------------------------------------------------------------------------*/ + +struct t7l66xb { + void __iomem *scr; + /* Lock to protect registers requiring read/modify/write ops. */ + spinlock_t lock; + + struct resource rscr; + int irq; + int irq_base; +}; + +/*--------------------------------------------------------------------------*/ + +static int t7l66xb_mmc_enable(struct platform_device *mmc) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + unsigned long flags; + u8 dev_ctl; + + if (pdata->enable_clk32k) + pdata->enable_clk32k(dev); + + spin_lock_irqsave(&t7l66xb->lock, flags); + + dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); + dev_ctl |= SCR_DEV_CTL_MMC; + tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); + + spin_unlock_irqrestore(&t7l66xb->lock, flags); + + return 0; +} + +static int t7l66xb_mmc_disable(struct platform_device *mmc) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + unsigned long flags; + u8 dev_ctl; + + spin_lock_irqsave(&t7l66xb->lock, flags); + + dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); + dev_ctl &= ~SCR_DEV_CTL_MMC; + tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); + + spin_unlock_irqrestore(&t7l66xb->lock, flags); + + if (pdata->disable_clk32k) + pdata->disable_clk32k(dev); + + return 0; +} + +/*--------------------------------------------------------------------------*/ + +const static struct resource t7l66xb_mmc_resources[] = { + { + .start = 0x800, + .end = 0x9ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x200, + .end = 0x2ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_T7L66XB_MMC, + .end = IRQ_T7L66XB_MMC, + .flags = IORESOURCE_IRQ, + }, +}; + +const static struct resource t7l66xb_nand_resources[] = { + { + .start = 0xc00, + .end = 0xc07, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x0100, + .end = 0x01ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_T7L66XB_NAND, + .end = IRQ_T7L66XB_NAND, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell t7l66xb_cells[] = { + [T7L66XB_CELL_MMC] = { + .name = "tmio-mmc", + .enable = t7l66xb_mmc_enable, + .disable = t7l66xb_mmc_disable, + .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), + .resources = t7l66xb_mmc_resources, + }, + [T7L66XB_CELL_NAND] = { + .name = "tmio-nand", + .num_resources = ARRAY_SIZE(t7l66xb_nand_resources), + .resources = t7l66xb_nand_resources, + }, +}; + +/*--------------------------------------------------------------------------*/ + +/* Handle the T7L66XB interrupt mux */ +static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) +{ + struct t7l66xb *t7l66xb = get_irq_data(irq); + unsigned int isr; + unsigned int i, irq_base; + + irq_base = t7l66xb->irq_base; + + while ((isr = tmio_ioread8(t7l66xb->scr + SCR_ISR) & + ~tmio_ioread8(t7l66xb->scr + SCR_IMR))) + for (i = 0; i < T7L66XB_NR_IRQS; i++) + if (isr & (1 << i)) + generic_handle_irq(irq_base + i); +} + +static void t7l66xb_irq_mask(unsigned int irq) +{ + struct t7l66xb *t7l66xb = get_irq_chip_data(irq); + unsigned long flags; + u8 imr; + + spin_lock_irqsave(&t7l66xb->lock, flags); + imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); + imr |= 1 << (irq - t7l66xb->irq_base); + tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); + spin_unlock_irqrestore(&t7l66xb->lock, flags); +} + +static void t7l66xb_irq_unmask(unsigned int irq) +{ + struct t7l66xb *t7l66xb = get_irq_chip_data(irq); + unsigned long flags; + u8 imr; + + spin_lock_irqsave(&t7l66xb->lock, flags); + imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); + imr &= ~(1 << (irq - t7l66xb->irq_base)); + tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); + spin_unlock_irqrestore(&t7l66xb->lock, flags); +} + +static struct irq_chip t7l66xb_chip = { + .name = "t7l66xb", + .ack = t7l66xb_irq_mask, + .mask = t7l66xb_irq_mask, + .unmask = t7l66xb_irq_unmask, +}; + +/*--------------------------------------------------------------------------*/ + +/* Install the IRQ handler */ +static void t7l66xb_attach_irq(struct platform_device *dev) +{ + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + unsigned int irq, irq_base; + + irq_base = t7l66xb->irq_base; + + for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { + set_irq_chip(irq, &t7l66xb_chip); + set_irq_chip_data(irq, t7l66xb); + set_irq_handler(irq, handle_level_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); +#endif + } + + set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); + set_irq_data(t7l66xb->irq, t7l66xb); + set_irq_chained_handler(t7l66xb->irq, t7l66xb_irq); +} + +static void t7l66xb_detach_irq(struct platform_device *dev) +{ + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + unsigned int irq, irq_base; + + irq_base = t7l66xb->irq_base; + + set_irq_chained_handler(t7l66xb->irq, NULL); + set_irq_data(t7l66xb->irq, NULL); + + for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { +#ifdef CONFIG_ARM + set_irq_flags(irq, 0); +#endif + set_irq_chip(irq, NULL); + set_irq_chip_data(irq, NULL); + } +} + +/*--------------------------------------------------------------------------*/ + +#ifdef CONFIG_PM +static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) +{ + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + + if (pdata && pdata->suspend) + pdata->suspend(dev); + + return 0; +} + +static int t7l66xb_resume(struct platform_device *dev) +{ + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + + if (pdata && pdata->resume) + pdata->resume(dev); + + return 0; +} +#else +#define t7l66xb_suspend NULL +#define t7l66xb_resume NULL +#endif + +/*--------------------------------------------------------------------------*/ + +static int t7l66xb_probe(struct platform_device *dev) +{ + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb *t7l66xb; + struct resource *iomem, *rscr; + int ret; + + iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!iomem) + return -EINVAL; + + t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL); + if (!t7l66xb) + return -ENOMEM; + + spin_lock_init(&t7l66xb->lock); + + platform_set_drvdata(dev, t7l66xb); + + ret = platform_get_irq(dev, 0); + if (ret >= 0) + t7l66xb->irq = ret; + else + goto err_noirq; + + t7l66xb->irq_base = pdata->irq_base; + + rscr = &t7l66xb->rscr; + rscr->name = "t7l66xb-core"; + rscr->start = iomem->start; + rscr->end = iomem->start + 0xff; + rscr->flags = IORESOURCE_MEM; + + ret = request_resource(iomem, rscr); + if (ret) + goto err_request_scr; + + t7l66xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); + if (!t7l66xb->scr) { + ret = -ENOMEM; + goto err_ioremap; + } + + if (pdata && pdata->enable) + pdata->enable(dev); + + /* Mask all interrupts */ + tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR); + + printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n", + dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID), + (unsigned long)iomem->start, t7l66xb->irq); + + t7l66xb_attach_irq(dev); + + t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data; + t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = + &t7l66xb_cells[T7L66XB_CELL_NAND]; + t7l66xb_cells[T7L66XB_CELL_NAND].data_size = + sizeof(t7l66xb_cells[T7L66XB_CELL_NAND]); + + t7l66xb_cells[T7L66XB_CELL_MMC].platform_data = + &t7l66xb_cells[T7L66XB_CELL_MMC]; + t7l66xb_cells[T7L66XB_CELL_MMC].data_size = + sizeof(t7l66xb_cells[T7L66XB_CELL_MMC]); + + ret = mfd_add_devices(&dev->dev, dev->id, + t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), + iomem, t7l66xb->irq_base); + + if (!ret) + return 0; + + t7l66xb_detach_irq(dev); + iounmap(t7l66xb->scr); +err_ioremap: + release_resource(&t7l66xb->rscr); +err_noirq: +err_request_scr: + kfree(t7l66xb); + return ret; +} + +static int t7l66xb_remove(struct platform_device *dev) +{ + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + int ret; + + ret = pdata->disable(dev); + + t7l66xb_detach_irq(dev); + iounmap(t7l66xb->scr); + release_resource(&t7l66xb->rscr); + mfd_remove_devices(&dev->dev); + platform_set_drvdata(dev, NULL); + kfree(t7l66xb); + + return ret; + +} + +static struct platform_driver t7l66xb_platform_driver = { + .driver = { + .name = "t7l66xb", + .owner = THIS_MODULE, + }, + .suspend = t7l66xb_suspend, + .resume = t7l66xb_resume, + .probe = t7l66xb_probe, + .remove = t7l66xb_remove, +}; + +/*--------------------------------------------------------------------------*/ + +static int __init t7l66xb_init(void) +{ + int retval = 0; + + retval = platform_driver_register(&t7l66xb_platform_driver); + return retval; +} + +static void __exit t7l66xb_exit(void) +{ + platform_driver_unregister(&t7l66xb_platform_driver); +} + +module_init(t7l66xb_init); +module_exit(t7l66xb_exit); + +MODULE_DESCRIPTION("Toshiba T7L66XB core driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ian Molton"); +MODULE_ALIAS("platform:t7l66xb"); diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c new file mode 100644 index 00000000000..a22b21ac6cf --- /dev/null +++ b/drivers/mfd/tc6387xb.c @@ -0,0 +1,181 @@ +/* + * Toshiba TC6387XB support + * Copyright (c) 2005 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains TC6387XB base support. + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/mfd/core.h> +#include <linux/mfd/tmio.h> +#include <linux/mfd/tc6387xb.h> + +enum { + TC6387XB_CELL_MMC, +}; + +#ifdef CONFIG_PM +static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) +{ + struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev); + + if (pdata && pdata->suspend) + pdata->suspend(dev); + + return 0; +} + +static int tc6387xb_resume(struct platform_device *dev) +{ + struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev); + + if (pdata && pdata->resume) + pdata->resume(dev); + + return 0; +} +#else +#define tc6387xb_suspend NULL +#define tc6387xb_resume NULL +#endif + +/*--------------------------------------------------------------------------*/ + +static int tc6387xb_mmc_enable(struct platform_device *mmc) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data; + + if (tc6387xb->enable_clk32k) + tc6387xb->enable_clk32k(dev); + + return 0; +} + +static int tc6387xb_mmc_disable(struct platform_device *mmc) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data; + + if (tc6387xb->disable_clk32k) + tc6387xb->disable_clk32k(dev); + + return 0; +} + +/*--------------------------------------------------------------------------*/ + +static struct resource tc6387xb_mmc_resources[] = { + { + .start = 0x800, + .end = 0x9ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x200, + .end = 0x2ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell tc6387xb_cells[] = { + [TC6387XB_CELL_MMC] = { + .name = "tmio-mmc", + .enable = tc6387xb_mmc_enable, + .disable = tc6387xb_mmc_disable, + .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), + .resources = tc6387xb_mmc_resources, + }, +}; + +static int tc6387xb_probe(struct platform_device *dev) +{ + struct tc6387xb_platform_data *data = platform_get_drvdata(dev); + struct resource *iomem; + int irq, ret; + + iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!iomem) { + ret = -EINVAL; + goto err_resource; + } + + ret = platform_get_irq(dev, 0); + if (ret >= 0) + irq = ret; + else + goto err_resource; + + if (data && data->enable) + data->enable(dev); + + printk(KERN_INFO "Toshiba tc6387xb initialised\n"); + + tc6387xb_cells[TC6387XB_CELL_MMC].platform_data = + &tc6387xb_cells[TC6387XB_CELL_MMC]; + tc6387xb_cells[TC6387XB_CELL_MMC].data_size = + sizeof(tc6387xb_cells[TC6387XB_CELL_MMC]); + + ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, + ARRAY_SIZE(tc6387xb_cells), iomem, irq); + + if (!ret) + return 0; + +err_resource: + return ret; +} + +static int tc6387xb_remove(struct platform_device *dev) +{ + struct tc6387xb_platform_data *data = platform_get_drvdata(dev); + + if (data && data->disable) + data->disable(dev); + + /* FIXME - free the resources! */ + + return 0; +} + + +static struct platform_driver tc6387xb_platform_driver = { + .driver = { + .name = "tc6387xb", + }, + .probe = tc6387xb_probe, + .remove = tc6387xb_remove, + .suspend = tc6387xb_suspend, + .resume = tc6387xb_resume, +}; + + +static int __init tc6387xb_init(void) +{ + return platform_driver_register(&tc6387xb_platform_driver); +} + +static void __exit tc6387xb_exit(void) +{ + platform_driver_unregister(&tc6387xb_platform_driver); +} + +module_init(tc6387xb_init); +module_exit(tc6387xb_exit); + +MODULE_DESCRIPTION("Toshiba TC6387XB core driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ian Molton"); +MODULE_ALIAS("platform:tc6387xb"); diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index f4fd797c159..e4c1c788b5f 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -19,8 +19,8 @@ #include <linux/io.h> #include <linux/irq.h> #include <linux/platform_device.h> -#include <linux/fb.h> #include <linux/clk.h> +#include <linux/err.h> #include <linux/mfd/core.h> #include <linux/mfd/tmio.h> #include <linux/mfd/tc6393xb.h> @@ -112,6 +112,7 @@ struct tc6393xb { enum { TC6393XB_CELL_NAND, + TC6393XB_CELL_MMC, }; /*--------------------------------------------------------------------------*/ @@ -126,7 +127,7 @@ static int tc6393xb_nand_enable(struct platform_device *nand) /* SMD buffer on */ dev_dbg(&dev->dev, "SMD buffer on\n"); - iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); + tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); spin_unlock_irqrestore(&tc6393xb->lock, flags); @@ -135,25 +136,40 @@ static int tc6393xb_nand_enable(struct platform_device *nand) static struct resource __devinitdata tc6393xb_nand_resources[] = { { - .name = TMIO_NAND_CONFIG, - .start = 0x0100, - .end = 0x01ff, + .start = 0x1000, + .end = 0x1007, .flags = IORESOURCE_MEM, }, { - .name = TMIO_NAND_CONTROL, - .start = 0x1000, - .end = 0x1007, + .start = 0x0100, + .end = 0x01ff, .flags = IORESOURCE_MEM, }, { - .name = TMIO_NAND_IRQ, .start = IRQ_TC6393_NAND, .end = IRQ_TC6393_NAND, .flags = IORESOURCE_IRQ, }, }; +static struct resource __devinitdata tc6393xb_mmc_resources[] = { + { + .start = 0x800, + .end = 0x9ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x200, + .end = 0x2ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_TC6393_MMC, + .end = IRQ_TC6393_MMC, + .flags = IORESOURCE_IRQ, + }, +}; + static struct mfd_cell __devinitdata tc6393xb_cells[] = { [TC6393XB_CELL_NAND] = { .name = "tmio-nand", @@ -161,6 +177,11 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = { .num_resources = ARRAY_SIZE(tc6393xb_nand_resources), .resources = tc6393xb_nand_resources, }, + [TC6393XB_CELL_MMC] = { + .name = "tmio-mmc", + .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), + .resources = tc6393xb_mmc_resources, + }, }; /*--------------------------------------------------------------------------*/ @@ -171,7 +192,7 @@ static int tc6393xb_gpio_get(struct gpio_chip *chip, struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); /* XXX: does dsr also represent inputs? */ - return ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) + return tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) & TC_GPIO_BIT(offset); } @@ -181,13 +202,13 @@ static void __tc6393xb_gpio_set(struct gpio_chip *chip, struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); u8 dsr; - dsr = ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); + dsr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); if (value) dsr |= TC_GPIO_BIT(offset); else dsr &= ~TC_GPIO_BIT(offset); - iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); + tmio_iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); } static void tc6393xb_gpio_set(struct gpio_chip *chip, @@ -212,9 +233,9 @@ static int tc6393xb_gpio_direction_input(struct gpio_chip *chip, spin_lock_irqsave(&tc6393xb->lock, flags); - doecr = ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); + doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); doecr &= ~TC_GPIO_BIT(offset); - iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); + tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); spin_unlock_irqrestore(&tc6393xb->lock, flags); @@ -232,9 +253,9 @@ static int tc6393xb_gpio_direction_output(struct gpio_chip *chip, __tc6393xb_gpio_set(chip, offset, value); - doecr = ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); + doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); doecr |= TC_GPIO_BIT(offset); - iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); + tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); spin_unlock_irqrestore(&tc6393xb->lock, flags); @@ -265,8 +286,8 @@ tc6393xb_irq(unsigned int irq, struct irq_desc *desc) irq_base = tc6393xb->irq_base; - while ((isr = ioread8(tc6393xb->scr + SCR_ISR) & - ~ioread8(tc6393xb->scr + SCR_IMR))) + while ((isr = tmio_ioread8(tc6393xb->scr + SCR_ISR) & + ~tmio_ioread8(tc6393xb->scr + SCR_IMR))) for (i = 0; i < TC6393XB_NR_IRQS; i++) { if (isr & (1 << i)) generic_handle_irq(irq_base + i); @@ -284,9 +305,9 @@ static void tc6393xb_irq_mask(unsigned int irq) u8 imr; spin_lock_irqsave(&tc6393xb->lock, flags); - imr = ioread8(tc6393xb->scr + SCR_IMR); + imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); imr |= 1 << (irq - tc6393xb->irq_base); - iowrite8(imr, tc6393xb->scr + SCR_IMR); + tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); spin_unlock_irqrestore(&tc6393xb->lock, flags); } @@ -297,9 +318,9 @@ static void tc6393xb_irq_unmask(unsigned int irq) u8 imr; spin_lock_irqsave(&tc6393xb->lock, flags); - imr = ioread8(tc6393xb->scr + SCR_IMR); + imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); imr &= ~(1 << (irq - tc6393xb->irq_base)); - iowrite8(imr, tc6393xb->scr + SCR_IMR); + tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); spin_unlock_irqrestore(&tc6393xb->lock, flags); } @@ -380,9 +401,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) { struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; struct tc6393xb *tc6393xb; - struct resource *iomem; - struct resource *rscr; - int retval, temp; + struct resource *iomem, *rscr; + int ret, temp; int i; iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -391,20 +411,26 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) tc6393xb = kzalloc(sizeof *tc6393xb, GFP_KERNEL); if (!tc6393xb) { - retval = -ENOMEM; + ret = -ENOMEM; goto err_kzalloc; } spin_lock_init(&tc6393xb->lock); platform_set_drvdata(dev, tc6393xb); + + ret = platform_get_irq(dev, 0); + if (ret >= 0) + tc6393xb->irq = ret; + else + goto err_noirq; + tc6393xb->iomem = iomem; - tc6393xb->irq = platform_get_irq(dev, 0); tc6393xb->irq_base = tcpd->irq_base; - tc6393xb->clk = clk_get(&dev->dev, "GPIO27_CLK" /* "CK3P6MI" */); + tc6393xb->clk = clk_get(&dev->dev, "CLK_CK3P6MI"); if (IS_ERR(tc6393xb->clk)) { - retval = PTR_ERR(tc6393xb->clk); + ret = PTR_ERR(tc6393xb->clk); goto err_clk_get; } @@ -414,71 +440,73 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) rscr->end = iomem->start + 0xff; rscr->flags = IORESOURCE_MEM; - retval = request_resource(iomem, rscr); - if (retval) + ret = request_resource(iomem, rscr); + if (ret) goto err_request_scr; tc6393xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); if (!tc6393xb->scr) { - retval = -ENOMEM; + ret = -ENOMEM; goto err_ioremap; } - retval = clk_enable(tc6393xb->clk); - if (retval) + ret = clk_enable(tc6393xb->clk); + if (ret) goto err_clk_enable; - retval = tcpd->enable(dev); - if (retval) + ret = tcpd->enable(dev); + if (ret) goto err_enable; tc6393xb->suspend_state.fer = 0; + for (i = 0; i < 3; i++) { tc6393xb->suspend_state.gpo_dsr[i] = (tcpd->scr_gpo_dsr >> (8 * i)) & 0xff; tc6393xb->suspend_state.gpo_doecr[i] = (tcpd->scr_gpo_doecr >> (8 * i)) & 0xff; } - /* - * It may be necessary to change this back to - * platform-dependant code - */ + tc6393xb->suspend_state.ccr = SCR_CCR_UNK1 | SCR_CCR_HCLK_48; - retval = tc6393xb_hw_init(dev); - if (retval) + ret = tc6393xb_hw_init(dev); + if (ret) goto err_hw_init; printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n", - ioread8(tc6393xb->scr + SCR_REVID), + tmio_ioread8(tc6393xb->scr + SCR_REVID), (unsigned long) iomem->start, tc6393xb->irq); tc6393xb->gpio.base = -1; if (tcpd->gpio_base >= 0) { - retval = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base); - if (retval) + ret = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base); + if (ret) goto err_gpio_add; } - if (tc6393xb->irq) - tc6393xb_attach_irq(dev); + tc6393xb_attach_irq(dev); tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = &tc6393xb_cells[TC6393XB_CELL_NAND]; tc6393xb_cells[TC6393XB_CELL_NAND].data_size = sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); + tc6393xb_cells[TC6393XB_CELL_MMC].platform_data = + &tc6393xb_cells[TC6393XB_CELL_MMC]; + tc6393xb_cells[TC6393XB_CELL_MMC].data_size = + sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]); + - retval = mfd_add_devices(&dev->dev, dev->id, + ret = mfd_add_devices(&dev->dev, dev->id, tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), iomem, tcpd->irq_base); - return 0; + if (!ret) + return 0; - if (tc6393xb->irq) - tc6393xb_detach_irq(dev); + tc6393xb_detach_irq(dev); err_gpio_add: if (tc6393xb->gpio.base != -1) @@ -493,10 +521,11 @@ err_ioremap: release_resource(&tc6393xb->rscr); err_request_scr: clk_put(tc6393xb->clk); +err_noirq: err_clk_get: kfree(tc6393xb); err_kzalloc: - return retval; + return ret; } static int __devexit tc6393xb_remove(struct platform_device *dev) @@ -506,9 +535,7 @@ static int __devexit tc6393xb_remove(struct platform_device *dev) int ret; mfd_remove_devices(&dev->dev); - - if (tc6393xb->irq) - tc6393xb_detach_irq(dev); + tc6393xb_detach_irq(dev); if (tc6393xb->gpio.base != -1) { ret = gpiochip_remove(&tc6393xb->gpio); @@ -519,17 +546,11 @@ static int __devexit tc6393xb_remove(struct platform_device *dev) } ret = tcpd->disable(dev); - clk_disable(tc6393xb->clk); - iounmap(tc6393xb->scr); - release_resource(&tc6393xb->rscr); - platform_set_drvdata(dev, NULL); - clk_put(tc6393xb->clk); - kfree(tc6393xb); return ret; @@ -540,8 +561,7 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) { struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - int i; - + int i, ret; tc6393xb->suspend_state.ccr = ioread16(tc6393xb->scr + SCR_CCR); tc6393xb->suspend_state.fer = ioread8(tc6393xb->scr + SCR_FER); @@ -554,14 +574,21 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) tc6393xb->suspend_state.gpi_bcr[i] = ioread8(tc6393xb->scr + SCR_GPI_BCR(i)); } + ret = tcpd->suspend(dev); + clk_disable(tc6393xb->clk); - return tcpd->suspend(dev); + return ret; } static int tc6393xb_resume(struct platform_device *dev) { struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; - int ret = tcpd->resume(dev); + struct tc6393xb *tc6393xb = platform_get_drvdata(dev); + int ret; + + clk_enable(tc6393xb->clk); + + ret = tcpd->resume(dev); if (ret) return ret; @@ -598,7 +625,7 @@ static void __exit tc6393xb_exit(void) subsys_initcall(tc6393xb_init); module_exit(tc6393xb_exit); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer"); MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller"); MODULE_ALIAS("platform:tc6393xb"); diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index 4251018f70f..a78f70deeb5 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h @@ -279,7 +279,7 @@ struct gru_stats_s { #if defined CONFIG_IA64 #define VADDR_HI_BIT 64 #define GRUREGION(addr) ((addr) >> (VADDR_HI_BIT - 3) & 3) -#elif defined __x86_64 +#elif defined CONFIG_X86_64 #define VADDR_HI_BIT 48 #define GRUREGION(addr) (0) /* ZZZ could do better */ #else diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index dc6f2579f85..ea8d7a3490d 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -174,3 +174,9 @@ config MMC_SDRICOH_CS To compile this driver as a module, choose M here: the module will be called sdricoh_cs. +config MMC_TMIO + tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" + depends on MFD_TMIO + help + This provides support for the SD/MMC cell found in TC6393XB, + T7L66XB and also ipaq ASIC3 diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index db52eebfb50..c794cc5ce44 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -21,4 +21,5 @@ obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o obj-$(CONFIG_MMC_S3C) += s3cmci.o obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o +obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c new file mode 100644 index 00000000000..95430b81ec1 --- /dev/null +++ b/drivers/mmc/host/tmio_mmc.c @@ -0,0 +1,691 @@ +/* + * linux/drivers/mmc/tmio_mmc.c + * + * Copyright (C) 2004 Ian Molton + * Copyright (C) 2007 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Driver for the MMC / SD / SDIO cell found in: + * + * TC6393XB TC6391XB TC6387XB T7L66XB + * + * This driver draws mainly on scattered spec sheets, Reverse engineering + * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit + * support). (Further 4 bit support from a later datasheet). + * + * TODO: + * Investigate using a workqueue for PIO transfers + * Eliminate FIXMEs + * SDIO support + * Better Power management + * Handle MMC errors better + * double buffer support + * + */ +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/mmc/host.h> +#include <linux/mfd/core.h> +#include <linux/mfd/tmio.h> + +#include "tmio_mmc.h" + +/* + * Fixme - documentation conflicts on what the clock values are for the + * various dividers. + * One document I have says that its a divisor of a 24MHz clock, another 33. + * This probably depends on HCLK for a given platform, so we may need to + * require HCLK be passed to us from the MFD core. + * + */ + +static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) +{ + void __iomem *cnf = host->cnf; + void __iomem *ctl = host->ctl; + u32 clk = 0, clock; + + if (new_clock) { + for (clock = 46875, clk = 0x100; new_clock >= (clock<<1); ) { + clock <<= 1; + clk >>= 1; + } + if (clk & 0x1) + clk = 0x20000; + + clk >>= 2; + tmio_iowrite8((clk & 0x8000) ? 0 : 1, cnf + CNF_SD_CLK_MODE); + clk |= 0x100; + } + + tmio_iowrite16(clk, ctl + CTL_SD_CARD_CLK_CTL); +} + +static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) +{ + void __iomem *ctl = host->ctl; + + tmio_iowrite16(0x0000, ctl + CTL_CLK_AND_WAIT_CTL); + msleep(10); + tmio_iowrite16(tmio_ioread16(ctl + CTL_SD_CARD_CLK_CTL) & ~0x0100, + ctl + CTL_SD_CARD_CLK_CTL); + msleep(10); +} + +static void tmio_mmc_clk_start(struct tmio_mmc_host *host) +{ + void __iomem *ctl = host->ctl; + + tmio_iowrite16(tmio_ioread16(ctl + CTL_SD_CARD_CLK_CTL) | 0x0100, + ctl + CTL_SD_CARD_CLK_CTL); + msleep(10); + tmio_iowrite16(0x0100, ctl + CTL_CLK_AND_WAIT_CTL); + msleep(10); +} + +static void reset(struct tmio_mmc_host *host) +{ + void __iomem *ctl = host->ctl; + + /* FIXME - should we set stop clock reg here */ + tmio_iowrite16(0x0000, ctl + CTL_RESET_SD); + tmio_iowrite16(0x0000, ctl + CTL_RESET_SDIO); + msleep(10); + tmio_iowrite16(0x0001, ctl + CTL_RESET_SD); + tmio_iowrite16(0x0001, ctl + CTL_RESET_SDIO); + msleep(10); +} + +static void +tmio_mmc_finish_request(struct tmio_mmc_host *host) +{ + struct mmc_request *mrq = host->mrq; + + host->mrq = NULL; + host->cmd = NULL; + host->data = NULL; + + mmc_request_done(host->mmc, mrq); +} + +/* These are the bitmasks the tmio chip requires to implement the MMC response + * types. Note that R1 and R6 are the same in this scheme. */ +#define APP_CMD 0x0040 +#define RESP_NONE 0x0300 +#define RESP_R1 0x0400 +#define RESP_R1B 0x0500 +#define RESP_R2 0x0600 +#define RESP_R3 0x0700 +#define DATA_PRESENT 0x0800 +#define TRANSFER_READ 0x1000 +#define TRANSFER_MULTI 0x2000 +#define SECURITY_CMD 0x4000 + +static int +tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) +{ + void __iomem *ctl = host->ctl; + struct mmc_data *data = host->data; + int c = cmd->opcode; + + /* Command 12 is handled by hardware */ + if (cmd->opcode == 12 && !cmd->arg) { + tmio_iowrite16(0x001, ctl + CTL_STOP_INTERNAL_ACTION); + return 0; + } + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: c |= RESP_NONE; break; + case MMC_RSP_R1: c |= RESP_R1; break; + case MMC_RSP_R1B: c |= RESP_R1B; break; + case MMC_RSP_R2: c |= RESP_R2; break; + case MMC_RSP_R3: c |= RESP_R3; break; + default: + pr_debug("Unknown response type %d\n", mmc_resp_type(cmd)); + return -EINVAL; + } + + host->cmd = cmd; + +/* FIXME - this seems to be ok comented out but the spec suggest this bit should + * be set when issuing app commands. + * if(cmd->flags & MMC_FLAG_ACMD) + * c |= APP_CMD; + */ + if (data) { + c |= DATA_PRESENT; + if (data->blocks > 1) { + tmio_iowrite16(0x100, ctl + CTL_STOP_INTERNAL_ACTION); + c |= TRANSFER_MULTI; + } + if (data->flags & MMC_DATA_READ) + c |= TRANSFER_READ; + } + + enable_mmc_irqs(ctl, TMIO_MASK_CMD); + + /* Fire off the command */ + tmio_iowrite32(cmd->arg, ctl + CTL_ARG_REG); + tmio_iowrite16(c, ctl + CTL_SD_CMD); + + return 0; +} + +/* This chip always returns (at least?) as much data as you ask for. + * I'm unsure what happens if you ask for less than a block. This should be + * looked into to ensure that a funny length read doesnt hose the controller. + * + */ +static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host) +{ + void __iomem *ctl = host->ctl; + struct mmc_data *data = host->data; + unsigned short *buf; + unsigned int count; + unsigned long flags; + + if (!data) { + pr_debug("Spurious PIO IRQ\n"); + return; + } + + buf = (unsigned short *)(tmio_mmc_kmap_atomic(host, &flags) + + host->sg_off); + + count = host->sg_ptr->length - host->sg_off; + if (count > data->blksz) + count = data->blksz; + + pr_debug("count: %08x offset: %08x flags %08x\n", + count, host->sg_off, data->flags); + + /* Transfer the data */ + if (data->flags & MMC_DATA_READ) + tmio_ioread16_rep(ctl + CTL_SD_DATA_PORT, buf, count >> 1); + else + tmio_iowrite16_rep(ctl + CTL_SD_DATA_PORT, buf, count >> 1); + + host->sg_off += count; + + tmio_mmc_kunmap_atomic(host, &flags); + + if (host->sg_off == host->sg_ptr->length) + tmio_mmc_next_sg(host); + + return; +} + +static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host) +{ + void __iomem *ctl = host->ctl; + struct mmc_data *data = host->data; + struct mmc_command *stop = data->stop; + + host->data = NULL; + + if (!data) { + pr_debug("Spurious data end IRQ\n"); + return; + } + + /* FIXME - return correct transfer count on errors */ + if (!data->error) + data->bytes_xfered = data->blocks * data->blksz; + else + data->bytes_xfered = 0; + + pr_debug("Completed data request\n"); + + /*FIXME - other drivers allow an optional stop command of any given type + * which we dont do, as the chip can auto generate them. + * Perhaps we can be smarter about when to use auto CMD12 and + * only issue the auto request when we know this is the desired + * stop command, allowing fallback to the stop command the + * upper layers expect. For now, we do what works. + */ + + if (data->flags & MMC_DATA_READ) + disable_mmc_irqs(ctl, TMIO_MASK_READOP); + else + disable_mmc_irqs(ctl, TMIO_MASK_WRITEOP); + + if (stop) { + if (stop->opcode == 12 && !stop->arg) + tmio_iowrite16(0x000, ctl + CTL_STOP_INTERNAL_ACTION); + else + BUG(); + } + + tmio_mmc_finish_request(host); +} + +static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, + unsigned int stat) +{ + void __iomem *ctl = host->ctl, *addr; + struct mmc_command *cmd = host->cmd; + int i; + + if (!host->cmd) { + pr_debug("Spurious CMD irq\n"); + return; + } + + host->cmd = NULL; + + /* This controller is sicker than the PXA one. Not only do we need to + * drop the top 8 bits of the first response word, we also need to + * modify the order of the response for short response command types. + */ + + for (i = 3, addr = ctl + CTL_RESPONSE ; i >= 0 ; i--, addr += 4) + cmd->resp[i] = tmio_ioread32(addr); + + if (cmd->flags & MMC_RSP_136) { + cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24); + cmd->resp[1] = (cmd->resp[1] << 8) | (cmd->resp[2] >> 24); + cmd->resp[2] = (cmd->resp[2] << 8) | (cmd->resp[3] >> 24); + cmd->resp[3] <<= 8; + } else if (cmd->flags & MMC_RSP_R3) { + cmd->resp[0] = cmd->resp[3]; + } + + if (stat & TMIO_STAT_CMDTIMEOUT) + cmd->error = -ETIMEDOUT; + else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC) + cmd->error = -EILSEQ; + + /* If there is data to handle we enable data IRQs here, and + * we will ultimatley finish the request in the data_end handler. + * If theres no data or we encountered an error, finish now. + */ + if (host->data && !cmd->error) { + if (host->data->flags & MMC_DATA_READ) + enable_mmc_irqs(ctl, TMIO_MASK_READOP); + else + enable_mmc_irqs(ctl, TMIO_MASK_WRITEOP); + } else { + tmio_mmc_finish_request(host); + } + + return; +} + + +static irqreturn_t tmio_mmc_irq(int irq, void *devid) +{ + struct tmio_mmc_host *host = devid; + void __iomem *ctl = host->ctl; + unsigned int ireg, irq_mask, status; + + pr_debug("MMC IRQ begin\n"); + + status = tmio_ioread32(ctl + CTL_STATUS); + irq_mask = tmio_ioread32(ctl + CTL_IRQ_MASK); + ireg = status & TMIO_MASK_IRQ & ~irq_mask; + + pr_debug_status(status); + pr_debug_status(ireg); + + if (!ireg) { + disable_mmc_irqs(ctl, status & ~irq_mask); + + pr_debug("tmio_mmc: Spurious irq, disabling! " + "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); + pr_debug_status(status); + + goto out; + } + + while (ireg) { + /* Card insert / remove attempts */ + if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { + ack_mmc_irqs(ctl, TMIO_STAT_CARD_INSERT | + TMIO_STAT_CARD_REMOVE); + mmc_detect_change(host->mmc, 0); + } + + /* CRC and other errors */ +/* if (ireg & TMIO_STAT_ERR_IRQ) + * handled |= tmio_error_irq(host, irq, stat); + */ + + /* Command completion */ + if (ireg & TMIO_MASK_CMD) { + ack_mmc_irqs(ctl, TMIO_MASK_CMD); + tmio_mmc_cmd_irq(host, status); + } + + /* Data transfer */ + if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { + ack_mmc_irqs(ctl, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); + tmio_mmc_pio_irq(host); + } + + /* Data transfer completion */ + if (ireg & TMIO_STAT_DATAEND) { + ack_mmc_irqs(ctl, TMIO_STAT_DATAEND); + tmio_mmc_data_irq(host); + } + + /* Check status - keep going until we've handled it all */ + status = tmio_ioread32(ctl + CTL_STATUS); + irq_mask = tmio_ioread32(ctl + CTL_IRQ_MASK); + ireg = status & TMIO_MASK_IRQ & ~irq_mask; + + pr_debug("Status at end of loop: %08x\n", status); + pr_debug_status(status); + } + pr_debug("MMC IRQ end\n"); + +out: + return IRQ_HANDLED; +} + +static int tmio_mmc_start_data(struct tmio_mmc_host *host, + struct mmc_data *data) +{ + void __iomem *ctl = host->ctl; + + pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n", + data->blksz, data->blocks); + + /* Hardware cannot perform 1 and 2 byte requests in 4 bit mode */ + if (data->blksz < 4 && host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) { + printk(KERN_ERR "%s: %d byte block unsupported in 4 bit mode\n", + mmc_hostname(host->mmc), data->blksz); + return -EINVAL; + } + + tmio_mmc_init_sg(host, data); + host->data = data; + + /* Set transfer length / blocksize */ + tmio_iowrite16(data->blksz, ctl + CTL_SD_XFER_LEN); + tmio_iowrite16(data->blocks, ctl + CTL_XFER_BLK_COUNT); + + return 0; +} + +/* Process requests from the MMC layer */ +static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + int ret; + + if (host->mrq) + pr_debug("request not null\n"); + + host->mrq = mrq; + + if (mrq->data) { + ret = tmio_mmc_start_data(host, mrq->data); + if (ret) + goto fail; + } + + ret = tmio_mmc_start_command(host, mrq->cmd); + + if (!ret) + return; + +fail: + mrq->cmd->error = ret; + mmc_request_done(mmc, mrq); +} + +/* Set MMC clock / power. + * Note: This controller uses a simple divider scheme therefore it cannot + * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as + * MMC wont run that fast, it has to be clocked at 12MHz which is the next + * slowest setting. + */ +static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + void __iomem *cnf = host->cnf; + void __iomem *ctl = host->ctl; + + if (ios->clock) + tmio_mmc_set_clock(host, ios->clock); + + /* Power sequence - OFF -> ON -> UP */ + switch (ios->power_mode) { + case MMC_POWER_OFF: /* power down SD bus */ + tmio_iowrite8(0x00, cnf + CNF_PWR_CTL_2); + tmio_mmc_clk_stop(host); + break; + case MMC_POWER_ON: /* power up SD bus */ + + tmio_iowrite8(0x02, cnf + CNF_PWR_CTL_2); + break; + case MMC_POWER_UP: /* start bus clock */ + tmio_mmc_clk_start(host); + break; + } + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + tmio_iowrite16(0x80e0, ctl + CTL_SD_MEM_CARD_OPT); + break; + case MMC_BUS_WIDTH_4: + tmio_iowrite16(0x00e0, ctl + CTL_SD_MEM_CARD_OPT); + break; + } + + /* Let things settle. delay taken from winCE driver */ + udelay(140); +} + +static int tmio_mmc_get_ro(struct mmc_host *mmc) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + void __iomem *ctl = host->ctl; + + return (tmio_ioread16(ctl + CTL_STATUS) & TMIO_STAT_WRPROTECT) ? 0 : 1; +} + +static struct mmc_host_ops tmio_mmc_ops = { + .request = tmio_mmc_request, + .set_ios = tmio_mmc_set_ios, + .get_ro = tmio_mmc_get_ro, +}; + +#ifdef CONFIG_PM +static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + struct mmc_host *mmc = platform_get_drvdata(dev); + int ret; + + ret = mmc_suspend_host(mmc, state); + + /* Tell MFD core it can disable us now.*/ + if (!ret && cell->disable) + cell->disable(dev); + + return ret; +} + +static int tmio_mmc_resume(struct platform_device *dev) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + struct mmc_host *mmc = platform_get_drvdata(dev); + struct tmio_mmc_host *host = mmc_priv(mmc); + void __iomem *cnf = host->cnf; + int ret = 0; + + /* Enable the MMC/SD Control registers */ + tmio_iowrite16(SDCREN, cnf + CNF_CMD); + tmio_iowrite32(dev->resource[0].start & 0xfffe, cnf + CNF_CTL_BASE); + + /* Tell the MFD core we are ready to be enabled */ + if (cell->enable) { + ret = cell->enable(dev); + if (ret) + goto out; + } + + mmc_resume_host(mmc); + +out: + return ret; +} +#else +#define tmio_mmc_suspend NULL +#define tmio_mmc_resume NULL +#endif + +static int __devinit tmio_mmc_probe(struct platform_device *dev) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + struct resource *res_ctl, *res_cnf; + struct tmio_mmc_host *host; + struct mmc_host *mmc; + int ret = -ENOMEM; + + if (dev->num_resources != 3) + goto out; + + res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0); + res_cnf = platform_get_resource(dev, IORESOURCE_MEM, 1); + if (!res_ctl || !res_cnf) { + ret = -EINVAL; + goto out; + } + + mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &dev->dev); + if (!mmc) + goto out; + + host = mmc_priv(mmc); + host->mmc = mmc; + platform_set_drvdata(dev, mmc); + + host->ctl = ioremap(res_ctl->start, res_ctl->end - res_ctl->start); + if (!host->ctl) + goto host_free; + + host->cnf = ioremap(res_cnf->start, res_cnf->end - res_cnf->start); + if (!host->cnf) + goto unmap_ctl; + + mmc->ops = &tmio_mmc_ops; + mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->f_min = 46875; /* 24000000 / 512 */ + mmc->f_max = 24000000; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + + /* Enable the MMC/SD Control registers */ + tmio_iowrite16(SDCREN, host->cnf + CNF_CMD); + tmio_iowrite32(dev->resource[0].start & 0xfffe, + host->cnf + CNF_CTL_BASE); + + /* Tell the MFD core we are ready to be enabled */ + if (cell->enable) { + ret = cell->enable(dev); + if (ret) + goto unmap_cnf; + } + + /* Disable SD power during suspend */ + tmio_iowrite8(0x01, host->cnf + CNF_PWR_CTL_3); + + /* The below is required but why? FIXME */ + tmio_iowrite8(0x1f, host->cnf + CNF_STOP_CLK_CTL); + + /* Power down SD bus*/ + tmio_iowrite8(0x0, host->cnf + CNF_PWR_CTL_2); + + tmio_mmc_clk_stop(host); + reset(host); + + ret = platform_get_irq(dev, 0); + if (ret >= 0) + host->irq = ret; + else + goto unmap_cnf; + + disable_mmc_irqs(host->ctl, TMIO_MASK_ALL); + + ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED, "tmio-mmc", + host); + if (ret) + goto unmap_cnf; + + set_irq_type(host->irq, IRQ_TYPE_EDGE_FALLING); + + mmc_add_host(mmc); + + printk(KERN_INFO "%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), + (unsigned long)host->ctl, host->irq); + + /* Unmask the IRQs we want to know about */ + enable_mmc_irqs(host->ctl, TMIO_MASK_IRQ); + + return 0; + +unmap_cnf: + iounmap(host->cnf); +unmap_ctl: + iounmap(host->ctl); +host_free: + mmc_free_host(mmc); +out: + return ret; +} + +static int __devexit tmio_mmc_remove(struct platform_device *dev) +{ + struct mmc_host *mmc = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + + if (mmc) { + struct tmio_mmc_host *host = mmc_priv(mmc); + mmc_remove_host(mmc); + mmc_free_host(mmc); + free_irq(host->irq, host); + iounmap(host->ctl); + iounmap(host->cnf); + } + + return 0; +} + +/* ------------------- device registration ----------------------- */ + +static struct platform_driver tmio_mmc_driver = { + .driver = { + .name = "tmio-mmc", + .owner = THIS_MODULE, + }, + .probe = tmio_mmc_probe, + .remove = __devexit_p(tmio_mmc_remove), + .suspend = tmio_mmc_suspend, + .resume = tmio_mmc_resume, +}; + + +static int __init tmio_mmc_init(void) +{ + return platform_driver_register(&tmio_mmc_driver); +} + +static void __exit tmio_mmc_exit(void) +{ + platform_driver_unregister(&tmio_mmc_driver); +} + +module_init(tmio_mmc_init); +module_exit(tmio_mmc_exit); + +MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver"); +MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:tmio-mmc"); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h new file mode 100644 index 00000000000..9e647a06054 --- /dev/null +++ b/drivers/mmc/host/tmio_mmc.h @@ -0,0 +1,194 @@ +/* Definitons for use with the tmio_mmc.c + * + * (c) 2004 Ian Molton <spyro@f2s.com> + * (c) 2007 Ian Molton <spyro@f2s.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#define CNF_CMD 0x04 +#define CNF_CTL_BASE 0x10 +#define CNF_INT_PIN 0x3d +#define CNF_STOP_CLK_CTL 0x40 +#define CNF_GCLK_CTL 0x41 +#define CNF_SD_CLK_MODE 0x42 +#define CNF_PIN_STATUS 0x44 +#define CNF_PWR_CTL_1 0x48 +#define CNF_PWR_CTL_2 0x49 +#define CNF_PWR_CTL_3 0x4a +#define CNF_CARD_DETECT_MODE 0x4c +#define CNF_SD_SLOT 0x50 +#define CNF_EXT_GCLK_CTL_1 0xf0 +#define CNF_EXT_GCLK_CTL_2 0xf1 +#define CNF_EXT_GCLK_CTL_3 0xf9 +#define CNF_SD_LED_EN_1 0xfa +#define CNF_SD_LED_EN_2 0xfe + +#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/ + +#define CTL_SD_CMD 0x00 +#define CTL_ARG_REG 0x04 +#define CTL_STOP_INTERNAL_ACTION 0x08 +#define CTL_XFER_BLK_COUNT 0xa +#define CTL_RESPONSE 0x0c +#define CTL_STATUS 0x1c +#define CTL_IRQ_MASK 0x20 +#define CTL_SD_CARD_CLK_CTL 0x24 +#define CTL_SD_XFER_LEN 0x26 +#define CTL_SD_MEM_CARD_OPT 0x28 +#define CTL_SD_ERROR_DETAIL_STATUS 0x2c +#define CTL_SD_DATA_PORT 0x30 +#define CTL_TRANSACTION_CTL 0x34 +#define CTL_RESET_SD 0xe0 +#define CTL_SDIO_REGS 0x100 +#define CTL_CLK_AND_WAIT_CTL 0x138 +#define CTL_RESET_SDIO 0x1e0 + +/* Definitions for values the CTRL_STATUS register can take. */ +#define TMIO_STAT_CMDRESPEND 0x00000001 +#define TMIO_STAT_DATAEND 0x00000004 +#define TMIO_STAT_CARD_REMOVE 0x00000008 +#define TMIO_STAT_CARD_INSERT 0x00000010 +#define TMIO_STAT_SIGSTATE 0x00000020 +#define TMIO_STAT_WRPROTECT 0x00000080 +#define TMIO_STAT_CARD_REMOVE_A 0x00000100 +#define TMIO_STAT_CARD_INSERT_A 0x00000200 +#define TMIO_STAT_SIGSTATE_A 0x00000400 +#define TMIO_STAT_CMD_IDX_ERR 0x00010000 +#define TMIO_STAT_CRCFAIL 0x00020000 +#define TMIO_STAT_STOPBIT_ERR 0x00040000 +#define TMIO_STAT_DATATIMEOUT 0x00080000 +#define TMIO_STAT_RXOVERFLOW 0x00100000 +#define TMIO_STAT_TXUNDERRUN 0x00200000 +#define TMIO_STAT_CMDTIMEOUT 0x00400000 +#define TMIO_STAT_RXRDY 0x01000000 +#define TMIO_STAT_TXRQ 0x02000000 +#define TMIO_STAT_ILL_FUNC 0x20000000 +#define TMIO_STAT_CMD_BUSY 0x40000000 +#define TMIO_STAT_ILL_ACCESS 0x80000000 + +/* Define some IRQ masks */ +/* This is the mask used at reset by the chip */ +#define TMIO_MASK_ALL 0x837f031d +#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND | \ + TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) +#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND | \ + TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) +#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ + TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) +#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) + +#define enable_mmc_irqs(ctl, i) \ + do { \ + u32 mask;\ + mask = tmio_ioread32((ctl) + CTL_IRQ_MASK); \ + mask &= ~((i) & TMIO_MASK_IRQ); \ + tmio_iowrite32(mask, (ctl) + CTL_IRQ_MASK); \ + } while (0) + +#define disable_mmc_irqs(ctl, i) \ + do { \ + u32 mask;\ + mask = tmio_ioread32((ctl) + CTL_IRQ_MASK); \ + mask |= ((i) & TMIO_MASK_IRQ); \ + tmio_iowrite32(mask, (ctl) + CTL_IRQ_MASK); \ + } while (0) + +#define ack_mmc_irqs(ctl, i) \ + do { \ + u32 mask;\ + mask = tmio_ioread32((ctl) + CTL_STATUS); \ + mask &= ~((i) & TMIO_MASK_IRQ); \ + tmio_iowrite32(mask, (ctl) + CTL_STATUS); \ + } while (0) + + +struct tmio_mmc_host { + void __iomem *cnf; + void __iomem *ctl; + struct mmc_command *cmd; + struct mmc_request *mrq; + struct mmc_data *data; + struct mmc_host *mmc; + int irq; + + /* pio related stuff */ + struct scatterlist *sg_ptr; + unsigned int sg_len; + unsigned int sg_off; +}; + +#include <linux/scatterlist.h> +#include <linux/blkdev.h> + +static inline void tmio_mmc_init_sg(struct tmio_mmc_host *host, + struct mmc_data *data) +{ + host->sg_len = data->sg_len; + host->sg_ptr = data->sg; + host->sg_off = 0; +} + +static inline int tmio_mmc_next_sg(struct tmio_mmc_host *host) +{ + host->sg_ptr = sg_next(host->sg_ptr); + host->sg_off = 0; + return --host->sg_len; +} + +static inline char *tmio_mmc_kmap_atomic(struct tmio_mmc_host *host, + unsigned long *flags) +{ + struct scatterlist *sg = host->sg_ptr; + + local_irq_save(*flags); + return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; +} + +static inline void tmio_mmc_kunmap_atomic(struct tmio_mmc_host *host, + unsigned long *flags) +{ + kunmap_atomic(sg_page(host->sg_ptr), KM_BIO_SRC_IRQ); + local_irq_restore(*flags); +} + +#ifdef CONFIG_MMC_DEBUG + +#define STATUS_TO_TEXT(a) \ + do { \ + if (status & TMIO_STAT_##a) \ + printf(#a); \ + } while (0) + +void debug_status(u32 status) +{ + printk(KERN_DEBUG "status: %08x = ", status); + STATUS_TO_TEXT(CARD_REMOVE); + STATUS_TO_TEXT(CARD_INSERT); + STATUS_TO_TEXT(SIGSTATE); + STATUS_TO_TEXT(WRPROTECT); + STATUS_TO_TEXT(CARD_REMOVE_A); + STATUS_TO_TEXT(CARD_INSERT_A); + STATUS_TO_TEXT(SIGSTATE_A); + STATUS_TO_TEXT(CMD_IDX_ERR); + STATUS_TO_TEXT(STOPBIT_ERR); + STATUS_TO_TEXT(ILL_FUNC); + STATUS_TO_TEXT(CMD_BUSY); + STATUS_TO_TEXT(CMDRESPEND); + STATUS_TO_TEXT(DATAEND); + STATUS_TO_TEXT(CRCFAIL); + STATUS_TO_TEXT(DATATIMEOUT); + STATUS_TO_TEXT(CMDTIMEOUT); + STATUS_TO_TEXT(RXOVERFLOW); + STATUS_TO_TEXT(TXUNDERRUN); + STATUS_TO_TEXT(RXRDY); + STATUS_TO_TEXT(TXRQ); + STATUS_TO_TEXT(ILL_ACCESS); + printk("\n"); +} + +#else +#define pr_debug_status(s) do { } while (0) +#endif diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 02f9cc30d77..41f361c49b3 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -351,6 +351,13 @@ config MTD_NAND_PASEMI Enables support for NAND Flash interface on PA Semi PWRficient based boards +config MTD_NAND_TMIO + tristate "NAND Flash device on Toshiba Mobile IO Controller" + depends on MTD_NAND && MFD_TMIO + help + Support for NAND flash connected to a Toshiba Mobile IO + Controller in some PDAs, including the Sharp SL6000x. + config MTD_NAND_NANDSIM tristate "Support for NAND Flash Simulator" depends on MTD_PARTITIONS diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index d772581de57..b786c5da82d 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o +obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o obj-$(CONFIG_MTD_ALAUDA) += alauda.o obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c new file mode 100644 index 00000000000..cbab654b03c --- /dev/null +++ b/drivers/mtd/nand/tmio_nand.c @@ -0,0 +1,556 @@ +/* + * Toshiba TMIO NAND flash controller driver + * + * Slightly murky pre-git history of the driver: + * + * Copyright (c) Ian Molton 2004, 2005, 2008 + * Original work, independant of sharps code. Included hardware ECC support. + * Hard ECC did not work for writes in the early revisions. + * Copyright (c) Dirk Opfer 2005. + * Modifications developed from sharps code but + * NOT containing any, ported onto Ians base. + * Copyright (c) Chris Humbert 2005 + * Copyright (c) Dmitry Baryshkov 2008 + * Minor fixes + * + * Parts copyright Sebastian Carlier + * + * This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + */ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mfd/core.h> +#include <linux/mfd/tmio.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +/*--------------------------------------------------------------------------*/ + +/* + * NAND Flash Host Controller Configuration Register + */ +#define CCR_COMMAND 0x04 /* w Command */ +#define CCR_BASE 0x10 /* l NAND Flash Control Reg Base Addr */ +#define CCR_INTP 0x3d /* b Interrupt Pin */ +#define CCR_INTE 0x48 /* b Interrupt Enable */ +#define CCR_EC 0x4a /* b Event Control */ +#define CCR_ICC 0x4c /* b Internal Clock Control */ +#define CCR_ECCC 0x5b /* b ECC Control */ +#define CCR_NFTC 0x60 /* b NAND Flash Transaction Control */ +#define CCR_NFM 0x61 /* b NAND Flash Monitor */ +#define CCR_NFPSC 0x62 /* b NAND Flash Power Supply Control */ +#define CCR_NFDC 0x63 /* b NAND Flash Detect Control */ + +/* + * NAND Flash Control Register + */ +#define FCR_DATA 0x00 /* bwl Data Register */ +#define FCR_MODE 0x04 /* b Mode Register */ +#define FCR_STATUS 0x05 /* b Status Register */ +#define FCR_ISR 0x06 /* b Interrupt Status Register */ +#define FCR_IMR 0x07 /* b Interrupt Mask Register */ + +/* FCR_MODE Register Command List */ +#define FCR_MODE_DATA 0x94 /* Data Data_Mode */ +#define FCR_MODE_COMMAND 0x95 /* Data Command_Mode */ +#define FCR_MODE_ADDRESS 0x96 /* Data Address_Mode */ + +#define FCR_MODE_HWECC_CALC 0xB4 /* HW-ECC Data */ +#define FCR_MODE_HWECC_RESULT 0xD4 /* HW-ECC Calc result Read_Mode */ +#define FCR_MODE_HWECC_RESET 0xF4 /* HW-ECC Reset */ + +#define FCR_MODE_POWER_ON 0x0C /* Power Supply ON to SSFDC card */ +#define FCR_MODE_POWER_OFF 0x08 /* Power Supply OFF to SSFDC card */ + +#define FCR_MODE_LED_OFF 0x00 /* LED OFF */ +#define FCR_MODE_LED_ON 0x04 /* LED ON */ + +#define FCR_MODE_EJECT_ON 0x68 /* Ejection events active */ +#define FCR_MODE_EJECT_OFF 0x08 /* Ejection events ignored */ + +#define FCR_MODE_LOCK 0x6C /* Lock_Mode. Eject Switch Invalid */ +#define FCR_MODE_UNLOCK 0x0C /* UnLock_Mode. Eject Switch is valid */ + +#define FCR_MODE_CONTROLLER_ID 0x40 /* Controller ID Read */ +#define FCR_MODE_STANDBY 0x00 /* SSFDC card Changes Standby State */ + +#define FCR_MODE_WE 0x80 +#define FCR_MODE_ECC1 0x40 +#define FCR_MODE_ECC0 0x20 +#define FCR_MODE_CE 0x10 +#define FCR_MODE_PCNT1 0x08 +#define FCR_MODE_PCNT0 0x04 +#define FCR_MODE_ALE 0x02 +#define FCR_MODE_CLE 0x01 + +#define FCR_STATUS_BUSY 0x80 + +/*--------------------------------------------------------------------------*/ + +struct tmio_nand { + struct mtd_info mtd; + struct nand_chip chip; + + struct platform_device *dev; + + void __iomem *ccr; + void __iomem *fcr; + unsigned long fcr_phys; + + unsigned int irq; + + /* for tmio_nand_read_byte */ + u8 read; + unsigned read_good:1; +}; + +#define mtd_to_tmio(m) container_of(m, struct tmio_nand, mtd) + +#ifdef CONFIG_MTD_CMDLINE_PARTS +static const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + +/*--------------------------------------------------------------------------*/ + +static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + u8 mode; + + if (ctrl & NAND_NCE) { + mode = FCR_MODE_DATA; + + if (ctrl & NAND_CLE) + mode |= FCR_MODE_CLE; + else + mode &= ~FCR_MODE_CLE; + + if (ctrl & NAND_ALE) + mode |= FCR_MODE_ALE; + else + mode &= ~FCR_MODE_ALE; + } else { + mode = FCR_MODE_STANDBY; + } + + tmio_iowrite8(mode, tmio->fcr + FCR_MODE); + tmio->read_good = 0; + } + + if (cmd != NAND_CMD_NONE) + tmio_iowrite8(cmd, chip->IO_ADDR_W); +} + +static int tmio_nand_dev_ready(struct mtd_info *mtd) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + + return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY); +} + +static irqreturn_t tmio_irq(int irq, void *__tmio) +{ + struct tmio_nand *tmio = __tmio; + struct nand_chip *nand_chip = &tmio->chip; + + /* disable RDYREQ interrupt */ + tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); + + if (unlikely(!waitqueue_active(&nand_chip->controller->wq))) + dev_warn(&tmio->dev->dev, "spurious interrupt\n"); + + wake_up(&nand_chip->controller->wq); + return IRQ_HANDLED; +} + +/* + *The TMIO core has a RDYREQ interrupt on the posedge of #SMRB. + *This interrupt is normally disabled, but for long operations like + *erase and write, we enable it to wake us up. The irq handler + *disables the interrupt. + */ +static int +tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + long timeout; + + /* enable RDYREQ interrupt */ + tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); + tmio_iowrite8(0x81, tmio->fcr + FCR_IMR); + + timeout = wait_event_timeout(nand_chip->controller->wq, + tmio_nand_dev_ready(mtd), + msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20)); + + if (unlikely(!tmio_nand_dev_ready(mtd))) { + tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); + dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n", + nand_chip->state == FL_ERASING ? "erase" : "program", + nand_chip->state == FL_ERASING ? 400 : 20); + + } else if (unlikely(!timeout)) { + tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); + dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n"); + } + + nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + return nand_chip->read_byte(mtd); +} + +/* + *The TMIO controller combines two 8-bit data bytes into one 16-bit + *word. This function separates them so nand_base.c works as expected, + *especially its NAND_CMD_READID routines. + * + *To prevent stale data from being read, tmio_nand_hwcontrol() clears + *tmio->read_good. + */ +static u_char tmio_nand_read_byte(struct mtd_info *mtd) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + unsigned int data; + + if (tmio->read_good--) + return tmio->read; + + data = tmio_ioread16(tmio->fcr + FCR_DATA); + tmio->read = data >> 8; + return data; +} + +/* + *The TMIO controller converts an 8-bit NAND interface to a 16-bit + *bus interface, so all data reads and writes must be 16-bit wide. + *Thus, we implement 16-bit versions of the read, write, and verify + *buffer functions. + */ +static void +tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + + tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1); +} + +static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + + tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1); +} + +static int +tmio_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + u16 *p = (u16 *) buf; + + for (len >>= 1; len; len--) + if (*(p++) != tmio_ioread16(tmio->fcr + FCR_DATA)) + return -EFAULT; + return 0; +} + +static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + + tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE); + tmio_ioread8(tmio->fcr + FCR_DATA); /* dummy read */ + tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE); +} + +static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + unsigned int ecc; + + tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE); + + ecc = tmio_ioread16(tmio->fcr + FCR_DATA); + ecc_code[1] = ecc; /* 000-255 LP7-0 */ + ecc_code[0] = ecc >> 8; /* 000-255 LP15-8 */ + ecc = tmio_ioread16(tmio->fcr + FCR_DATA); + ecc_code[2] = ecc; /* 000-255 CP5-0,11b */ + ecc_code[4] = ecc >> 8; /* 256-511 LP7-0 */ + ecc = tmio_ioread16(tmio->fcr + FCR_DATA); + ecc_code[3] = ecc; /* 256-511 LP15-8 */ + ecc_code[5] = ecc >> 8; /* 256-511 CP5-0,11b */ + + tmio_iowrite8(FCR_MODE_DATA, tmio->fcr + FCR_MODE); + return 0; +} + +static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + int ret; + + if (cell->enable) { + ret = cell->enable(dev); + if (ret) + return ret; + } + + /* (4Ch) CLKRUN Enable 1st spcrunc */ + tmio_iowrite8(0x81, tmio->ccr + CCR_ICC); + + /* (10h)BaseAddress 0x1000 spba.spba2 */ + tmio_iowrite16(tmio->fcr_phys, tmio->ccr + CCR_BASE); + tmio_iowrite16(tmio->fcr_phys >> 16, tmio->ccr + CCR_BASE + 16); + + /* (04h)Command Register I/O spcmd */ + tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND); + + /* (62h) Power Supply Control ssmpwc */ + /* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */ + tmio_iowrite8(0x02, tmio->ccr + CCR_NFPSC); + + /* (63h) Detect Control ssmdtc */ + tmio_iowrite8(0x02, tmio->ccr + CCR_NFDC); + + /* Interrupt status register clear sintst */ + tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); + + /* After power supply, Media are reset smode */ + tmio_iowrite8(FCR_MODE_POWER_ON, tmio->fcr + FCR_MODE); + tmio_iowrite8(FCR_MODE_COMMAND, tmio->fcr + FCR_MODE); + tmio_iowrite8(NAND_CMD_RESET, tmio->fcr + FCR_DATA); + + /* Standby Mode smode */ + tmio_iowrite8(FCR_MODE_STANDBY, tmio->fcr + FCR_MODE); + + mdelay(5); + + return 0; +} + +static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + + tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE); + if (cell->disable) + cell->disable(dev); +} + +static int tmio_probe(struct platform_device *dev) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + struct tmio_nand_data *data = cell->driver_data; + struct resource *fcr = platform_get_resource(dev, + IORESOURCE_MEM, 0); + struct resource *ccr = platform_get_resource(dev, + IORESOURCE_MEM, 1); + int irq = platform_get_irq(dev, 0); + struct tmio_nand *tmio; + struct mtd_info *mtd; + struct nand_chip *nand_chip; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts; + int nbparts = 0; +#endif + int retval; + + if (data == NULL) + dev_warn(&dev->dev, "NULL platform data!\n"); + + tmio = kzalloc(sizeof *tmio, GFP_KERNEL); + if (!tmio) { + retval = -ENOMEM; + goto err_kzalloc; + } + + tmio->dev = dev; + + platform_set_drvdata(dev, tmio); + mtd = &tmio->mtd; + nand_chip = &tmio->chip; + mtd->priv = nand_chip; + mtd->name = "tmio-nand"; + + tmio->ccr = ioremap(ccr->start, ccr->end - ccr->start + 1); + if (!tmio->ccr) { + retval = -EIO; + goto err_iomap_ccr; + } + + tmio->fcr_phys = (unsigned long)fcr->start; + tmio->fcr = ioremap(fcr->start, fcr->end - fcr->start + 1); + if (!tmio->fcr) { + retval = -EIO; + goto err_iomap_fcr; + } + + retval = tmio_hw_init(dev, tmio); + if (retval) + goto err_hwinit; + + /* Set address of NAND IO lines */ + nand_chip->IO_ADDR_R = tmio->fcr; + nand_chip->IO_ADDR_W = tmio->fcr; + + /* Set address of hardware control function */ + nand_chip->cmd_ctrl = tmio_nand_hwcontrol; + nand_chip->dev_ready = tmio_nand_dev_ready; + nand_chip->read_byte = tmio_nand_read_byte; + nand_chip->write_buf = tmio_nand_write_buf; + nand_chip->read_buf = tmio_nand_read_buf; + nand_chip->verify_buf = tmio_nand_verify_buf; + + /* set eccmode using hardware ECC */ + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.size = 512; + nand_chip->ecc.bytes = 6; + nand_chip->ecc.hwctl = tmio_nand_enable_hwecc; + nand_chip->ecc.calculate = tmio_nand_calculate_ecc; + nand_chip->ecc.correct = nand_correct_data; + + if (data) + nand_chip->badblock_pattern = data->badblock_pattern; + + /* 15 us command delay time */ + nand_chip->chip_delay = 15; + + retval = request_irq(irq, &tmio_irq, + IRQF_DISABLED, dev->dev.bus_id, tmio); + if (retval) { + dev_err(&dev->dev, "request_irq error %d\n", retval); + goto err_irq; + } + + tmio->irq = irq; + nand_chip->waitfunc = tmio_nand_wait; + + /* Scan to find existence of the device */ + if (nand_scan(mtd, 1)) { + retval = -ENODEV; + goto err_scan; + } + /* Register the partitions */ +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + nbparts = parse_mtd_partitions(mtd, part_probes, &parts, 0); +#endif + if (nbparts <= 0 && data) { + parts = data->partition; + nbparts = data->num_partitions; + } + + if (nbparts) + retval = add_mtd_partitions(mtd, parts, nbparts); + else +#endif + retval = add_mtd_device(mtd); + + if (!retval) + return retval; + + nand_release(mtd); + +err_scan: + if (tmio->irq) + free_irq(tmio->irq, tmio); +err_irq: + tmio_hw_stop(dev, tmio); +err_hwinit: + iounmap(tmio->fcr); +err_iomap_fcr: + iounmap(tmio->ccr); +err_iomap_ccr: + kfree(tmio); +err_kzalloc: + return retval; +} + +static int tmio_remove(struct platform_device *dev) +{ + struct tmio_nand *tmio = platform_get_drvdata(dev); + + nand_release(&tmio->mtd); + if (tmio->irq) + free_irq(tmio->irq, tmio); + tmio_hw_stop(dev, tmio); + iounmap(tmio->fcr); + iounmap(tmio->ccr); + kfree(tmio); + return 0; +} + +#ifdef CONFIG_PM +static int tmio_suspend(struct platform_device *dev, pm_message_t state) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + + if (cell->suspend) + cell->suspend(dev); + + tmio_hw_stop(dev, platform_get_drvdata(dev)); + return 0; +} + +static int tmio_resume(struct platform_device *dev) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + + /* FIXME - is this required or merely another attack of the broken + * SHARP platform? Looks suspicious. + */ + tmio_hw_init(dev, platform_get_drvdata(dev)); + + if (cell->resume) + cell->resume(dev); + + return 0; +} +#else +#define tmio_suspend NULL +#define tmio_resume NULL +#endif + +static struct platform_driver tmio_driver = { + .driver.name = "tmio-nand", + .driver.owner = THIS_MODULE, + .probe = tmio_probe, + .remove = tmio_remove, + .suspend = tmio_suspend, + .resume = tmio_resume, +}; + +static int __init tmio_init(void) +{ + return platform_driver_register(&tmio_driver); +} + +static void __exit tmio_exit(void) +{ + platform_driver_unregister(&tmio_driver); +} + +module_init(tmio_init); +module_exit(tmio_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ian Molton, Dirk Opfer, Chris Humbert, Dmitry Baryshkov"); +MODULE_DESCRIPTION("NAND flash driver on Toshiba Mobile IO controller"); +MODULE_ALIAS("platform:tmio-nand"); diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 35264c244cf..82d7be1655d 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -47,7 +47,7 @@ MODULE_DESCRIPTION("Atheros 1000M Ethernet Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -static inline void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter); +static void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter); static const u16 atl1e_rx_page_vld_regs[AT_MAX_RECEIVE_QUEUE][AT_PAGE_NUM_PER_QUEUE] = @@ -1037,7 +1037,7 @@ static inline void atl1e_configure_dma(struct atl1e_adapter *adapter) return; } -static inline void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter) +static void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter) { u32 value; struct atl1e_hw *hw = &adapter->hw; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 18354817173..4a10b5624f7 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -308,9 +308,8 @@ static void __pci_restore_msi_state(struct pci_dev *dev) entry->msi_attrib.masked); pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); - control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); - if (entry->msi_attrib.maskbit || !entry->msi_attrib.masked) - control |= PCI_MSI_FLAGS_ENABLE; + control &= ~PCI_MSI_FLAGS_QSIZE; + control |= PCI_MSI_FLAGS_ENABLE; pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0a3d856833f..c9884bba22d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1060,7 +1060,7 @@ bool pci_pme_capable(struct pci_dev *dev, pci_power_t state) * The caller must verify that the device is capable of generating PME# before * calling this function with @enable equal to 'true'. */ -static void pci_pme_active(struct pci_dev *dev, bool enable) +void pci_pme_active(struct pci_dev *dev, bool enable) { u16 pmcsr; @@ -1941,6 +1941,7 @@ EXPORT_SYMBOL(pci_set_power_state); EXPORT_SYMBOL(pci_save_state); EXPORT_SYMBOL(pci_restore_state); EXPORT_SYMBOL(pci_pme_capable); +EXPORT_SYMBOL(pci_pme_active); EXPORT_SYMBOL(pci_enable_wake); EXPORT_SYMBOL(pci_target_state); EXPORT_SYMBOL(pci_prepare_to_sleep); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 7098dfb0744..a04498d390c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -52,27 +52,49 @@ EXPORT_SYMBOL(no_pci_devices); * Some platforms allow access to legacy I/O port and ISA memory space on * a per-bus basis. This routine creates the files and ties them into * their associated read, write and mmap files from pci-sysfs.c + * + * On error unwind, but don't propogate the error to the caller + * as it is ok to set up the PCI bus without these files. */ static void pci_create_legacy_files(struct pci_bus *b) { + int error; + b->legacy_io = kzalloc(sizeof(struct bin_attribute) * 2, GFP_ATOMIC); - if (b->legacy_io) { - b->legacy_io->attr.name = "legacy_io"; - b->legacy_io->size = 0xffff; - b->legacy_io->attr.mode = S_IRUSR | S_IWUSR; - b->legacy_io->read = pci_read_legacy_io; - b->legacy_io->write = pci_write_legacy_io; - device_create_bin_file(&b->dev, b->legacy_io); - - /* Allocated above after the legacy_io struct */ - b->legacy_mem = b->legacy_io + 1; - b->legacy_mem->attr.name = "legacy_mem"; - b->legacy_mem->size = 1024*1024; - b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR; - b->legacy_mem->mmap = pci_mmap_legacy_mem; - device_create_bin_file(&b->dev, b->legacy_mem); - } + if (!b->legacy_io) + goto kzalloc_err; + + b->legacy_io->attr.name = "legacy_io"; + b->legacy_io->size = 0xffff; + b->legacy_io->attr.mode = S_IRUSR | S_IWUSR; + b->legacy_io->read = pci_read_legacy_io; + b->legacy_io->write = pci_write_legacy_io; + error = device_create_bin_file(&b->dev, b->legacy_io); + if (error) + goto legacy_io_err; + + /* Allocated above after the legacy_io struct */ + b->legacy_mem = b->legacy_io + 1; + b->legacy_mem->attr.name = "legacy_mem"; + b->legacy_mem->size = 1024*1024; + b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR; + b->legacy_mem->mmap = pci_mmap_legacy_mem; + error = device_create_bin_file(&b->dev, b->legacy_mem); + if (error) + goto legacy_mem_err; + + return; + +legacy_mem_err: + device_remove_bin_file(&b->dev, b->legacy_io); +legacy_io_err: + kfree(b->legacy_io); + b->legacy_io = NULL; +kzalloc_err: + printk(KERN_WARNING "pci: warning: could not create legacy I/O port " + "and ISA memory resources to sysfs\n"); + return; } void pci_remove_legacy_files(struct pci_bus *b) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0fb36507428..9236e7f869c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1756,9 +1756,14 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_c */ static void __devinit quirk_brcm_570x_limit_vpd(struct pci_dev *dev) { - /* Only disable the VPD capability for 5706, 5708, and 5709 rev. A */ + /* + * Only disable the VPD capability for 5706, 5706S, 5708, + * 5708S and 5709 rev. A + */ if ((dev->device == PCI_DEVICE_ID_NX2_5706) || + (dev->device == PCI_DEVICE_ID_NX2_5706S) || (dev->device == PCI_DEVICE_ID_NX2_5708) || + (dev->device == PCI_DEVICE_ID_NX2_5708S) || ((dev->device == PCI_DEVICE_ID_NX2_5709) && (dev->revision & 0xf0) == 0x0)) { if (dev->vpd) diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 856cc1af40d..35dcc06eb3e 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/rtc.h> -#include <linux/smp_lock.h> #include "rtc-core.h" static dev_t rtc_devt; @@ -27,11 +26,8 @@ static int rtc_dev_open(struct inode *inode, struct file *file) struct rtc_device, char_dev); const struct rtc_class_ops *ops = rtc->ops; - lock_kernel(); - if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) { - err = -EBUSY; - goto out; - } + if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) + return -EBUSY; file->private_data = rtc; @@ -41,13 +37,11 @@ static int rtc_dev_open(struct inode *inode, struct file *file) rtc->irq_data = 0; spin_unlock_irq(&rtc->irq_lock); - goto out; + return 0; } /* something has gone wrong */ clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); -out: - unlock_kernel(); return err; } diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index fbb90b1e409..a81adab6e51 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -482,7 +482,7 @@ isl1208_sysfs_register(struct device *dev) static int isl1208_sysfs_unregister(struct device *dev) { - device_remove_file(dev, &dev_attr_atrim); + device_remove_file(dev, &dev_attr_dtrim); device_remove_file(dev, &dev_attr_atrim); device_remove_file(dev, &dev_attr_usr); diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index fcdd73f2562..994da56fffe 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -680,7 +680,7 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) } -const struct scsi_dh_devlist alua_dev_list[] = { +static const struct scsi_dh_devlist alua_dev_list[] = { {"HP", "MSA VOLUME" }, {"HP", "HSV101" }, {"HP", "HSV111" }, diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index aa46b131b20..b9d23e9e9a4 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -562,7 +562,7 @@ done: return result; } -const struct scsi_dh_devlist clariion_dev_list[] = { +static const struct scsi_dh_devlist clariion_dev_list[] = { {"DGC", "RAID"}, {"DGC", "DISK"}, {"DGC", "VRAID"}, diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 9c7a1f8ebb7..a6a4ef3ad51 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -282,7 +282,7 @@ static int hp_sw_activate(struct scsi_device *sdev) return ret; } -const struct scsi_dh_devlist hp_sw_dh_data_list[] = { +static const struct scsi_dh_devlist hp_sw_dh_data_list[] = { {"COMPAQ", "MSA1000 VOLUME"}, {"COMPAQ", "HSV110"}, {"HP", "HSV100"}, diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index b093a501f8a..e7c7b4ebc1f 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -574,7 +574,7 @@ static int rdac_check_sense(struct scsi_device *sdev, return SCSI_RETURN_NOT_HANDLED; } -const struct scsi_dh_devlist rdac_dev_list[] = { +static const struct scsi_dh_devlist rdac_dev_list[] = { {"IBM", "1722"}, {"IBM", "1724"}, {"IBM", "1726"}, diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c index d94aa738760..b897f6554ec 100644 --- a/drivers/usb/misc/isight_firmware.c +++ b/drivers/usb/misc/isight_firmware.c @@ -48,7 +48,8 @@ static int isight_firmware_load(struct usb_interface *intf, if (request_firmware(&firmware, "isight.fw", &dev->dev) != 0) { printk(KERN_ERR "Unable to load isight firmware\n"); - return -ENODEV; + ret = -ENODEV; + goto out; } ptr = firmware->data; @@ -91,7 +92,6 @@ static int isight_firmware_load(struct usb_interface *intf, buf, llen, 300) != llen) { printk(KERN_ERR "Failed to load isight firmware\n"); - kfree(buf); ret = -ENODEV; goto out; } diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index e7018a2f56a..9c5925927ec 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -39,7 +39,9 @@ #endif #if defined(CONFIG_ARCH_AT91) -#define ATMEL_LCDFB_FBINFO_DEFAULT FBINFO_DEFAULT +#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ + | FBINFO_PARTIAL_PAN_OK \ + | FBINFO_HWACCEL_YPAN) static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, struct fb_var_screeninfo *var) @@ -177,7 +179,7 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, .xpanstep = 0, - .ypanstep = 0, + .ypanstep = 1, .ywrapstep = 0, .accel = FB_ACCEL_NONE, }; @@ -240,9 +242,11 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) { struct fb_info *info = sinfo->info; struct fb_var_screeninfo *var = &info->var; + unsigned int smem_len; - info->fix.smem_len = (var->xres_virtual * var->yres_virtual - * ((var->bits_per_pixel + 7) / 8)); + smem_len = (var->xres_virtual * var->yres_virtual + * ((var->bits_per_pixel + 7) / 8)); + info->fix.smem_len = max(smem_len, sinfo->smem_len); info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len, (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); @@ -794,6 +798,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) sinfo->default_monspecs = pdata_sinfo->default_monspecs; sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; sinfo->guard_time = pdata_sinfo->guard_time; + sinfo->smem_len = pdata_sinfo->smem_len; sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode; } else { diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c index 4d13f68436e..aa95f835024 100644 --- a/drivers/video/aty/radeon_accel.c +++ b/drivers/video/aty/radeon_accel.c @@ -55,6 +55,10 @@ static void radeonfb_prim_fillrect(struct radeonfb_info *rinfo, OUTREG(DP_WRITE_MSK, 0xffffffff); OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM)); + radeon_fifo_wait(2); + OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL); + OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE)); + radeon_fifo_wait(2); OUTREG(DST_Y_X, (region->dy << 16) | region->dx); OUTREG(DST_WIDTH_HEIGHT, (region->width << 16) | region->height); @@ -116,6 +120,10 @@ static void radeonfb_prim_copyarea(struct radeonfb_info *rinfo, OUTREG(DP_CNTL, (xdir>=0 ? DST_X_LEFT_TO_RIGHT : 0) | (ydir>=0 ? DST_Y_TOP_TO_BOTTOM : 0)); + radeon_fifo_wait(2); + OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL); + OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE)); + radeon_fifo_wait(3); OUTREG(SRC_Y_X, (sy << 16) | sx); OUTREG(DST_Y_X, (dy << 16) | dx); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 33859934a8e..c6299e8a041 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2518,7 +2518,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, c = vc->vc_video_erase_char; vc->vc_video_erase_char = ((c & 0xfe00) >> 1) | (c & 0xff); - c = vc->vc_def_color; + c = vc->vc_scrl_erase_char; vc->vc_scrl_erase_char = ((c & 0xFE00) >> 1) | (c & 0xFF); vc->vc_attr >>= 1; @@ -2551,7 +2551,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, if (vc->vc_can_do_color) { vc->vc_video_erase_char = ((c & 0xff00) << 1) | (c & 0xff); - c = vc->vc_def_color; + c = vc->vc_scrl_erase_char; vc->vc_scrl_erase_char = ((c & 0xFF00) << 1) | (c & 0xFF); vc->vc_attr <<= 1; diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index de1b1365279..a6e38e9ea73 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -92,7 +92,7 @@ struct fbcon_ops { #define attr_fgcol(fgshift,s) \ (((s) >> (fgshift)) & 0x0f) #define attr_bgcol(bgshift,s) \ - (((s) >> (bgshift)) & 0x07) + (((s) >> (bgshift)) & 0x0f) /* Monochrome */ #define attr_bold(s) \ diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c index 75ee5a12e54..c14e3e2212b 100644 --- a/drivers/video/matrox/i2c-matroxfb.c +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -87,13 +87,7 @@ static int matroxfb_gpio_getscl(void* data) { return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0; } -static struct i2c_adapter matrox_i2c_adapter_template = -{ - .owner = THIS_MODULE, - .id = I2C_HW_B_G400, -}; - -static struct i2c_algo_bit_data matrox_i2c_algo_template = +static const struct i2c_algo_bit_data matrox_i2c_algo_template = { .setsda = matroxfb_gpio_setsda, .setscl = matroxfb_gpio_setscl, @@ -112,7 +106,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, b->minfo = minfo; b->mask.data = data; b->mask.clock = clock; - b->adapter = matrox_i2c_adapter_template; + b->adapter.owner = THIS_MODULE; snprintf(b->adapter.name, sizeof(b->adapter.name), name, minfo->fbcon.node); i2c_set_adapdata(&b->adapter, b); @@ -187,6 +181,17 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) { MAT_DATA, MAT_CLK, "MAVEN:fb%u", 0); if (err) printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n"); + else { + struct i2c_board_info maven_info = { + I2C_BOARD_INFO("maven", 0x1b), + }; + unsigned short const addr_list[2] = { + 0x1b, I2C_CLIENT_END + }; + + i2c_new_probed_device(&m2info->maven.adapter, + &maven_info, addr_list); + } } return m2info; fail_ddc1:; diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 89da27bd5c4..042408a8c63 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -19,8 +19,6 @@ #include <linux/matroxfb.h> #include <asm/div64.h> -#define MAVEN_I2CID (0x1B) - #define MGATVO_B 1 #define MGATVO_C 2 @@ -128,7 +126,7 @@ static int get_ctrl_id(__u32 v4l2_id) { struct maven_data { struct matrox_fb_info* primary_head; - struct i2c_client client; + struct i2c_client *client; int version; }; @@ -974,7 +972,7 @@ static inline int maven_compute_timming(struct maven_data* md, static int maven_program_timming(struct maven_data* md, const struct mavenregs* m) { - struct i2c_client* c = &md->client; + struct i2c_client *c = md->client; if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) { LR(0x80); @@ -1011,7 +1009,7 @@ static int maven_program_timming(struct maven_data* md, } static inline int maven_resync(struct maven_data* md) { - struct i2c_client* c = &md->client; + struct i2c_client *c = md->client; maven_set_reg(c, 0x95, 0x20); /* start whole thing */ return 0; } @@ -1069,48 +1067,48 @@ static int maven_set_control (struct maven_data* md, maven_compute_bwlevel(md, &blacklevel, &whitelevel); blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8); whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8); - maven_set_reg_pair(&md->client, 0x0e, blacklevel); - maven_set_reg_pair(&md->client, 0x1e, whitelevel); + maven_set_reg_pair(md->client, 0x0e, blacklevel); + maven_set_reg_pair(md->client, 0x1e, whitelevel); } break; case V4L2_CID_SATURATION: { - maven_set_reg(&md->client, 0x20, p->value); - maven_set_reg(&md->client, 0x22, p->value); + maven_set_reg(md->client, 0x20, p->value); + maven_set_reg(md->client, 0x22, p->value); } break; case V4L2_CID_HUE: { - maven_set_reg(&md->client, 0x25, p->value); + maven_set_reg(md->client, 0x25, p->value); } break; case V4L2_CID_GAMMA: { const struct maven_gamma* g; g = maven_compute_gamma(md); - maven_set_reg(&md->client, 0x83, g->reg83); - maven_set_reg(&md->client, 0x84, g->reg84); - maven_set_reg(&md->client, 0x85, g->reg85); - maven_set_reg(&md->client, 0x86, g->reg86); - maven_set_reg(&md->client, 0x87, g->reg87); - maven_set_reg(&md->client, 0x88, g->reg88); - maven_set_reg(&md->client, 0x89, g->reg89); - maven_set_reg(&md->client, 0x8a, g->reg8a); - maven_set_reg(&md->client, 0x8b, g->reg8b); + maven_set_reg(md->client, 0x83, g->reg83); + maven_set_reg(md->client, 0x84, g->reg84); + maven_set_reg(md->client, 0x85, g->reg85); + maven_set_reg(md->client, 0x86, g->reg86); + maven_set_reg(md->client, 0x87, g->reg87); + maven_set_reg(md->client, 0x88, g->reg88); + maven_set_reg(md->client, 0x89, g->reg89); + maven_set_reg(md->client, 0x8a, g->reg8a); + maven_set_reg(md->client, 0x8b, g->reg8b); } break; case MATROXFB_CID_TESTOUT: { unsigned char val - = maven_get_reg(&md->client,0x8d); + = maven_get_reg(md->client, 0x8d); if (p->value) val |= 0x10; else val &= ~0x10; - maven_set_reg(&md->client, 0x8d, val); + maven_set_reg(md->client, 0x8d, val); } break; case MATROXFB_CID_DEFLICKER: { - maven_set_reg(&md->client, 0x93, maven_compute_deflicker(md)); + maven_set_reg(md->client, 0x93, maven_compute_deflicker(md)); } break; } @@ -1189,6 +1187,7 @@ static int maven_init_client(struct i2c_client* clnt) { MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo); md->primary_head = MINFO; + md->client = clnt; down_write(&ACCESS_FBINFO(altout.lock)); ACCESS_FBINFO(outputs[1]).output = &maven_altout; ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src; @@ -1232,14 +1231,11 @@ static int maven_shutdown_client(struct i2c_client* clnt) { return 0; } -static const unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; -I2C_CLIENT_INSMOD; - -static struct i2c_driver maven_driver; - -static int maven_detect_client(struct i2c_adapter* adapter, int address, int kind) { - int err = 0; - struct i2c_client* new_client; +static int maven_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + int err = -ENODEV; struct maven_data* data; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA | @@ -1250,50 +1246,37 @@ static int maven_detect_client(struct i2c_adapter* adapter, int address, int kin err = -ENOMEM; goto ERROR0; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &maven_driver; - new_client->flags = 0; - strlcpy(new_client->name, "maven", I2C_NAME_SIZE); - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - err = maven_init_client(new_client); + i2c_set_clientdata(client, data); + err = maven_init_client(client); if (err) goto ERROR4; return 0; ERROR4:; - i2c_detach_client(new_client); -ERROR3:; - kfree(new_client); + kfree(data); ERROR0:; return err; } -static int maven_attach_adapter(struct i2c_adapter* adapter) { - if (adapter->id == I2C_HW_B_G400) - return i2c_probe(adapter, &addr_data, &maven_detect_client); - return 0; -} - -static int maven_detach_client(struct i2c_client* client) { - int err; - - if ((err = i2c_detach_client(client))) - return err; +static int maven_remove(struct i2c_client *client) +{ maven_shutdown_client(client); kfree(i2c_get_clientdata(client)); return 0; } +static const struct i2c_device_id maven_id[] = { + { "maven", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, maven_id); + static struct i2c_driver maven_driver={ .driver = { .name = "maven", }, - .id = I2C_DRIVERID_MGATVO, - .attach_adapter = maven_attach_adapter, - .detach_client = maven_detach_client, + .probe = maven_probe, + .remove = maven_remove, + .id_table = maven_id, }; static int __init matroxfb_maven_init(void) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 32b9fe15364..db20542796b 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -285,10 +285,11 @@ config ALIM1535_WDT config ALIM7101_WDT tristate "ALi M7101 PMU Computer Watchdog" - depends on X86 && PCI + depends on PCI help This is the driver for the hardware watchdog on the ALi M7101 PMU - as used in the x86 Cobalt servers. + as used in the x86 Cobalt servers and also found in some + SPARC Netra servers too. To compile this driver as a module, choose M here: the module will be called alim7101_wdt. diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 049c9189569..ca3dc043d78 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -66,7 +66,10 @@ obj-$(CONFIG_IB700_WDT) += ib700wdt.o obj-$(CONFIG_IBMASR) += ibmasr.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o -obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o +obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o +ifeq ($(CONFIG_ITCO_VENDOR_SUPPORT),y) +obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o +endif obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index bacd867dd22..d061f0ad2d2 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c @@ -128,7 +128,7 @@ static struct watchdog_info at91_wdt_info = { /* * Handle commands from user-space. */ -static long at91_wdt_ioct(struct file *file, +static long at91_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; diff --git a/drivers/watchdog/ixp4xx_wdt.c b/drivers/watchdog/ixp4xx_wdt.c index 41264a5f173..8302ef005be 100644 --- a/drivers/watchdog/ixp4xx_wdt.c +++ b/drivers/watchdog/ixp4xx_wdt.c @@ -29,7 +29,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; static int heartbeat = 60; /* (secs) Default is 1 minute */ static unsigned long wdt_status; static unsigned long boot_status; -static spin_lock_t wdt_lock; +static DEFINE_SPINLOCK(wdt_lock); #define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL) diff --git a/drivers/watchdog/pcwd.c b/drivers/watchdog/pcwd.c index 3b0ddc7fcf3..9e1331a3b21 100644 --- a/drivers/watchdog/pcwd.c +++ b/drivers/watchdog/pcwd.c @@ -168,7 +168,7 @@ static const int heartbeat_tbl[] = { static int cards_found; /* internal variables */ -static atomic_t open_allowed = ATOMIC_INIT(1); +static unsigned long open_allowed; static char expect_close; static int temp_panic; diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index 824125adf90..cdc7138be30 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c @@ -30,7 +30,7 @@ #include <linux/mm.h> #include <linux/io.h> #include <linux/uaccess.h> -#include <linux/watchdog.h> +#include <asm/watchdog.h> #define PFX "shwdt: " @@ -68,7 +68,7 @@ static int clock_division_ratio = WTCSR_CKS_4096; static void sh_wdt_ping(unsigned long data); static unsigned long shwdt_is_open; -static struct watchdog_info sh_wdt_info; +static const struct watchdog_info sh_wdt_info; static char shwdt_expect_close; static DEFINE_TIMER(timer, sh_wdt_ping, 0, 0); static unsigned long next_heartbeat; @@ -89,7 +89,7 @@ static void sh_wdt_start(void) __u8 csr; unsigned long flags; - spin_lock_irqsave(&wdt_lock, flags); + spin_lock_irqsave(&shwdt_lock, flags); next_heartbeat = jiffies + (heartbeat * HZ); mod_timer(&timer, next_ping_period(clock_division_ratio)); @@ -127,7 +127,7 @@ static void sh_wdt_start(void) csr &= ~RSTCSR_RSTS; sh_wdt_write_rstcsr(csr); #endif - spin_unlock_irqrestore(&wdt_lock, flags); + spin_unlock_irqrestore(&shwdt_lock, flags); } /** @@ -139,14 +139,14 @@ static void sh_wdt_stop(void) __u8 csr; unsigned long flags; - spin_lock_irqsave(&wdt_lock, flags); + spin_lock_irqsave(&shwdt_lock, flags); del_timer(&timer); csr = sh_wdt_read_csr(); csr &= ~WTCSR_TME; sh_wdt_write_csr(csr); - spin_unlock_irqrestore(&wdt_lock, flags); + spin_unlock_irqrestore(&shwdt_lock, flags); } /** @@ -157,9 +157,9 @@ static inline void sh_wdt_keepalive(void) { unsigned long flags; - spin_lock_irqsave(&wdt_lock, flags); + spin_lock_irqsave(&shwdt_lock, flags); next_heartbeat = jiffies + (heartbeat * HZ); - spin_unlock_irqrestore(&wdt_lock, flags); + spin_unlock_irqrestore(&shwdt_lock, flags); } /** @@ -173,9 +173,9 @@ static int sh_wdt_set_heartbeat(int t) if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */ return -EINVAL; - spin_lock_irqsave(&wdt_lock, flags); + spin_lock_irqsave(&shwdt_lock, flags); heartbeat = t; - spin_unlock_irqrestore(&wdt_lock, flags); + spin_unlock_irqrestore(&shwdt_lock, flags); return 0; } @@ -189,7 +189,7 @@ static void sh_wdt_ping(unsigned long data) { unsigned long flags; - spin_lock_irqsave(&wdt_lock, flags); + spin_lock_irqsave(&shwdt_lock, flags); if (time_before(jiffies, next_heartbeat)) { __u8 csr; @@ -203,7 +203,7 @@ static void sh_wdt_ping(unsigned long data) } else printk(KERN_WARNING PFX "Heartbeat lost! Will not ping " "the watchdog\n"); - spin_unlock_irqrestore(&wdt_lock, flags); + spin_unlock_irqrestore(&shwdt_lock, flags); } /** diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c index dbbc018a5f4..6adab77fbbb 100644 --- a/drivers/watchdog/txx9wdt.c +++ b/drivers/watchdog/txx9wdt.c @@ -45,7 +45,7 @@ static unsigned long txx9wdt_alive; static int expect_close; static struct txx9_tmr_reg __iomem *txx9wdt_reg; static struct clk *txx9_imclk; -static DECLARE_LOCK(txx9_lock); +static DEFINE_SPINLOCK(txx9_lock); static void txx9wdt_ping(void) { diff --git a/drivers/watchdog/wdt285.c b/drivers/watchdog/wdt285.c index c8d7f1b2df0..db362c34958 100644 --- a/drivers/watchdog/wdt285.c +++ b/drivers/watchdog/wdt285.c @@ -208,7 +208,7 @@ static int __init footbridge_watchdog_init(void) soft_margin); if (machine_is_cats()) - printk(KERN_WARN + printk(KERN_WARNING "Warning: Watchdog reset may not work on this machine.\n"); return 0; } |