From 0254768a57593b300b3c241a5db4bf2056bd071e Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Fri, 23 May 2003 03:28:59 -0500 Subject: ISDN: Fix jiffies / flags types jiffies are unsigned long, so are flags, as kindly pointed out by gcc's warnings... --- include/linux/isdn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/isdn.h b/include/linux/isdn.h index a54091f5ff89..2c0da5f18944 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -285,7 +285,7 @@ typedef struct atemu { #endif int mdmcmdl; /* Length of Modem-Commandbuffer */ int pluscount; /* Counter for +++ sequence */ - int lastplus; /* Timestamp of last + */ + unsigned long lastplus; /* Timestamp of last + */ char mdmcmd[255]; /* Modem-Commandbuffer */ unsigned int charge; /* Charge units of current connection */ } atemu; -- cgit v1.2.3 From 082bd7df7a4336d9a5f4f4db9d943aeee3a53226 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Sun, 15 Jun 2003 20:07:05 -0700 Subject: [driver model] Remove struct sys_device::entry It was added by accident from another patch and is redundant with struct sys_device::kobj.entry. --- drivers/base/sys.c | 3 --- include/linux/sysdev.h | 1 - 2 files changed, 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/sys.c b/drivers/base/sys.c index e8a4daa442e8..4a73bd9340c0 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -218,9 +218,6 @@ void sys_device_unregister(struct sys_device * sysdev) if (drv->remove) drv->remove(sysdev); } - - list_del_init(&sysdev->entry); - up_write(&system_subsys.rwsem); kobject_unregister(&sysdev->kobj); diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h index 614200d60389..4bc3e22b5104 100644 --- a/include/linux/sysdev.h +++ b/include/linux/sysdev.h @@ -72,7 +72,6 @@ struct sys_device { u32 id; struct sysdev_class * cls; struct kobject kobj; - struct list_head entry; }; extern int sys_device_register(struct sys_device *); -- cgit v1.2.3 From feb6667875ea77e4620a813b890e490e37d2693c Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Tue, 17 Jun 2003 03:36:51 -0700 Subject: ACPI: acpiphp update (Takayoshi Kochi) --- drivers/pci/hotplug/acpiphp.h | 16 +++++------- drivers/pci/hotplug/acpiphp_core.c | 15 +++++------- drivers/pci/hotplug/acpiphp_glue.c | 50 ++++++++++++++++++-------------------- drivers/pci/hotplug/acpiphp_pci.c | 4 +-- drivers/pci/hotplug/acpiphp_res.c | 4 +-- include/linux/acpi.h | 4 +-- 6 files changed, 42 insertions(+), 51 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 3becefc4024c..247714b9f80e 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -5,8 +5,8 @@ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001 IBM Corp. * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation + * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) + * Copyright (c) 2002,2003 NEC Corporation * * All rights reserved. * @@ -26,8 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to , - * , - * + * * */ @@ -35,6 +34,7 @@ #define _ACPIPHP_H #include +#include /* for KOBJ_NAME_LEN */ #include "pci_hotplug.h" #define dbg(format, arg...) \ @@ -49,7 +49,7 @@ #define SLOT_MAGIC 0x67267322 /* name size which is used for entries in pcihpfs */ -#define SLOT_NAME_SIZE 32 /* ACPI{_SUN}-{BUS}:{DEV} */ +#define SLOT_NAME_SIZE KOBJ_NAME_LEN /* {_SUN} */ struct acpiphp_bridge; struct acpiphp_slot; @@ -212,11 +212,7 @@ struct acpiphp_func { #define FUNC_HAS_PS2 (0x00000040) #define FUNC_HAS_PS3 (0x00000080) -/* not yet */ -#define SLOT_SUPPORT_66MHZ (0x00010000) -#define SLOT_SUPPORT_100MHZ (0x00020000) -#define SLOT_SUPPORT_133MHZ (0x00040000) -#define SLOT_SUPPORT_PCIX (0x00080000) +#define FUNC_EXISTS (0x10000000) /* to make sure we call _EJ0 only for existing funcs */ /* function prototypes */ diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index cffa85dba2c8..b839e6d5e407 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -5,8 +5,8 @@ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001 IBM Corp. * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation + * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) + * Copyright (c) 2002,2003 NEC Corporation * * All rights reserved. * @@ -26,8 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to , - * , - * + * * */ @@ -57,7 +56,7 @@ int acpiphp_debug; static int num_slots; #define DRIVER_VERSION "0.4" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " +#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" MODULE_AUTHOR(DRIVER_AUTHOR); @@ -376,10 +375,8 @@ static int init_acpi (void) */ static void make_slot_name (struct slot *slot) { - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x", - slot->acpi_slot->sun, - slot->acpi_slot->bridge->bus, - slot->acpi_slot->device); + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%u", + slot->acpi_slot->sun); } /** diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 9ab2cda79548..3af6ad4adbe7 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1,9 +1,9 @@ /* * ACPI PCI HotPlug glue functions to ACPI CA subsystem * - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 NEC Corporation + * Copyright (c) 2002,2003 NEC Corporation * * All rights reserved. * @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to + * Send feedback to * */ @@ -204,7 +204,6 @@ register_slot (acpi_handle handle, u32 lvl, void *context, void **rv) if (ACPI_FAILURE(status)) { err("failed to register interrupt notify handler\n"); - kfree(newfunc); return status; } @@ -617,9 +616,8 @@ find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv) /* find hot-pluggable slots, and then find P2P bridge */ -static int add_bridges(struct acpi_device *device) +static int add_bridge(acpi_handle handle) { - acpi_handle *handle = device->handle; acpi_status status; unsigned long tmp; int seg, bus; @@ -673,6 +671,12 @@ static int add_bridges(struct acpi_device *device) } +static void remove_bridge (acpi_handle handle) +{ + /* No-op for now .. */ +} + + static int power_on_slot (struct acpiphp_slot *slot) { acpi_status status; @@ -725,9 +729,7 @@ static int power_off_slot (struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->flags & FUNC_HAS_PS3) { - dbg("%s: executing _PS3 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); + if (func->flags & (FUNC_HAS_PS3 | FUNC_EXISTS)) { status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS3 failed\n", __FUNCTION__); @@ -740,10 +742,8 @@ static int power_off_slot (struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->flags & FUNC_HAS_EJ0) { - dbg("%s: executing _EJ0 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); - + /* We don't want to call _EJ0 on non-existing functions. */ + if (func->flags & (FUNC_HAS_EJ0 | FUNC_EXISTS)) { /* _EJ0 method take one argument */ arg_list.count = 1; arg_list.pointer = &arg; @@ -756,6 +756,7 @@ static int power_off_slot (struct acpiphp_slot *slot) retval = -1; goto err_exit; } + func->flags &= (~FUNC_EXISTS); } } @@ -835,6 +836,8 @@ static int enable_device (struct acpiphp_slot *slot) retval = acpiphp_configure_function(func); if (retval) goto err_exit; + + func->flags |= FUNC_EXISTS; } slot->flags |= SLOT_ENABLED; @@ -1029,13 +1032,10 @@ static void handle_hotplug_event_func (acpi_handle handle, u32 type, void *conte } } -static struct acpi_driver acpi_pci_hp_driver = { - .name = "pci_hp", - .class = "", - .ids = ACPI_PCI_HOST_HID, - .ops = { - .add = add_bridges, - } + +static struct acpi_pci_driver acpi_pci_hp_driver = { + .add = add_bridge, + .remove = remove_bridge, }; /** @@ -1044,17 +1044,15 @@ static struct acpi_driver acpi_pci_hp_driver = { */ int acpiphp_glue_init (void) { - acpi_status status; + int num; if (list_empty(&pci_root_buses)) return -1; - status = acpi_bus_register_driver(&acpi_pci_hp_driver); + num = acpi_pci_register_driver(&acpi_pci_hp_driver); - if (ACPI_FAILURE(status)) { - err("%s: acpi_walk_namespace() failed\n", __FUNCTION__); + if (num <= 0) return -1; - } return 0; } @@ -1296,7 +1294,7 @@ u8 acpiphp_get_power_status (struct acpiphp_slot *slot) /* * attention LED ON: 1 - * OFF: 0 + * OFF: 0 * * TBD * no direct attention led status information via ACPI diff --git a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c index 6ebbb975d6f7..529f170a235f 100644 --- a/drivers/pci/hotplug/acpiphp_pci.c +++ b/drivers/pci/hotplug/acpiphp_pci.c @@ -4,7 +4,7 @@ * Copyright (c) 1995,2001 Compaq Computer Corporation * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001,2002 IBM Corp. - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (c) 2002 NEC Corporation * @@ -25,7 +25,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to + * Send feedback to * */ diff --git a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c index ea79c3c32b18..5ed1036617c1 100644 --- a/drivers/pci/hotplug/acpiphp_res.c +++ b/drivers/pci/hotplug/acpiphp_res.c @@ -5,7 +5,7 @@ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001 IBM Corp. * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (c) 2002 NEC Corporation * * All rights reserved. @@ -25,7 +25,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to , + * Send feedback to , * */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d2711ab6b024..8528f26c4a95 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -403,8 +403,8 @@ int acpi_pci_irq_init (void); struct acpi_pci_driver { struct acpi_pci_driver *next; - int (*add)(acpi_handle *handle); - void (*remove)(acpi_handle *handle); + int (*add)(acpi_handle handle); + void (*remove)(acpi_handle handle); }; int acpi_pci_register_driver(struct acpi_pci_driver *driver); -- cgit v1.2.3 From a549a455881d95cfd246978041018aa244cda949 Mon Sep 17 00:00:00 2001 From: David Mosberger Date: Wed, 18 Jun 2003 00:56:52 -0700 Subject: [PATCH] PCI: move pci_domain_nr() inside "#ifdef CONFIG_PCI" bracket Trivial build fix: pci_domain_nr() cannot be declared unless CONFIG_PCI is defined (otherwise, struct pci_bus hasn't been defined). --- include/linux/pci.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index 1983191d32c8..b5cb05a32c90 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -743,6 +743,15 @@ static inline int pci_module_init(struct pci_driver *drv) return rc; } +/* + * PCI domain support. Sometimes called PCI segment (eg by ACPI), + * a PCI domain is defined to be a set of PCI busses which share + * configuration space. + */ +#ifndef CONFIG_PCI_DOMAINS +static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } +#endif + #endif /* !CONFIG_PCI */ /* these helpers provide future and backwards compatibility @@ -800,15 +809,5 @@ extern int pci_pci_problems; #define PCIPCI_VSFX 16 #define PCIPCI_ALIMAGIK 32 -/* - * PCI domain support. Sometimes called PCI segment (eg by ACPI), - * a PCI domain is defined to be a set of PCI busses which share - * configuration space. - */ - -#ifndef CONFIG_PCI_DOMAINS -static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } -#endif - #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ -- cgit v1.2.3 From f55c3d5c532ec4ff66015b2fe6f23e34991cb281 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Wed, 18 Jun 2003 13:40:27 -0500 Subject: ISDN: Make PPP compressors unload-safe. Remove MOD_{INC,DEC}_USE_COUNT and introduce .owner instead. --- drivers/isdn/i4l/isdn_bsdcomp.c | 4 +--- drivers/isdn/i4l/isdn_ppp_ccp.c | 22 +++++++++++++++++----- include/linux/isdn_ppp.h | 1 + 3 files changed, 19 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index c48275b76141..16fda695fd42 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -300,7 +300,6 @@ static void bsd_free (void *state) * Finally release the structure itself. */ kfree (db); - MOD_DEC_USE_COUNT; } } @@ -355,8 +354,6 @@ static void *bsd_alloc (struct isdn_ppp_comp_data *data) return NULL; } - MOD_INC_USE_COUNT; - /* * If this is the compression buffer then there is no length data. * For decompression, the length information is needed as well. @@ -907,6 +904,7 @@ static int bsd_decompress (void *state, struct sk_buff *skb_in, struct sk_buff * *************************************************************/ static struct isdn_ppp_compressor ippp_bsd_compress = { + .owner = THIS_MODULE, .num = CI_BSD_COMPRESS, .alloc = bsd_alloc, .free = bsd_free, diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.c b/drivers/isdn/i4l/isdn_ppp_ccp.c index 155e76b1b3d0..ee9908882ab1 100644 --- a/drivers/isdn/i4l/isdn_ppp_ccp.c +++ b/drivers/isdn/i4l/isdn_ppp_ccp.c @@ -259,11 +259,14 @@ ippp_ccp_free(struct ippp_ccp *ccp) { int id; - if (ccp->comp_stat) + if (ccp->comp_stat) { ccp->compressor->free(ccp->comp_stat); - if (ccp->decomp_stat) + module_put(ccp->compressor->owner); + } + if (ccp->decomp_stat) { ccp->decompressor->free(ccp->decomp_stat); - + module_put(ccp->decompressor->owner); + } for (id = 0; id < 256; id++) { if (ccp->reset->rs[id]) ippp_ccp_reset_free_state(ccp, id); @@ -572,25 +575,34 @@ ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, if (ipc->num != num) continue; + if (!try_module_get(ipc->owner)) + continue; + stat = ipc->alloc(data); if (!stat) { printk(KERN_ERR "Can't alloc (de)compression!\n"); + module_put(ipc->owner); break; } ret = ipc->init(stat, data, unit, 0); if(!ret) { printk(KERN_ERR "Can't init (de)compression!\n"); ipc->free(stat); + module_put(ipc->owner); break; } if (data->flags & IPPP_COMP_FLAG_XMIT) { - if (ccp->comp_stat) + if (ccp->comp_stat) { ccp->compressor->free(ccp->comp_stat); + module_put(ccp->compressor->owner); + } ccp->comp_stat = stat; ccp->compressor = ipc; } else { - if (ccp->decomp_stat) + if (ccp->decomp_stat) { ccp->decompressor->free(ccp->decomp_stat); + module_put(ccp->decompressor->owner); + } ccp->decomp_stat = stat; ccp->decompressor = ipc; } diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index 669822e2868a..f4306f93e528 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -95,6 +95,7 @@ struct isdn_ppp_resetparams { * check the original include for more information */ struct isdn_ppp_compressor { + struct module *owner; struct isdn_ppp_compressor *next, *prev; int num; /* CCP compression protocol number */ -- cgit v1.2.3 From 6565c3f93d5a7a3230c5aaeaec6f1cb8327bbfee Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Wed, 18 Jun 2003 13:48:17 -0500 Subject: ISDN: Use standard list for PPP compressors replace the somewhat weird open-coded doubly-linked list with a list. --- drivers/isdn/i4l/isdn_ppp_ccp.c | 23 ++++++----------------- include/linux/isdn_ppp.h | 2 +- 2 files changed, 7 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.c b/drivers/isdn/i4l/isdn_ppp_ccp.c index ee9908882ab1..ad58aaf27d64 100644 --- a/drivers/isdn/i4l/isdn_ppp_ccp.c +++ b/drivers/isdn/i4l/isdn_ppp_ccp.c @@ -556,13 +556,13 @@ ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb) } } -static struct isdn_ppp_compressor *ipc_head = NULL; +static LIST_HEAD(ipc_head); int ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, struct isdn_ppp_comp_data *data) { - struct isdn_ppp_compressor *ipc = ipc_head; + struct isdn_ppp_compressor *ipc; int ret; void *stat; int num = data->num; @@ -571,7 +571,7 @@ ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, printk(KERN_DEBUG "[%d] Set %scompressor type %d\n", unit, data->flags & IPPP_COMP_FLAG_XMIT ? "" : "de", num); - for (ipc = ipc_head; ipc; ipc = ipc->next) { + list_for_each_entry(ipc, &ipc_head, list) { if (ipc->num != num) continue; @@ -618,7 +618,7 @@ ippp_ccp_get_compressors(unsigned long protos[8]) int i, j; memset(protos, 0, sizeof(unsigned long) * 8); - for (ipc = ipc_head; ipc; ipc = ipc->next) { + list_for_each_entry(ipc, &ipc_head, list) { j = ipc->num / (sizeof(long)*8); i = ipc->num % (sizeof(long)*8); if (j < 8) @@ -629,25 +629,14 @@ ippp_ccp_get_compressors(unsigned long protos[8]) int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) { - ipc->next = ipc_head; - ipc->prev = NULL; - if (ipc_head) { - ipc_head->prev = ipc; - } - ipc_head = ipc; + list_add_tail(&ipc->list, &ipc_head); return 0; } int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) { - if (ipc->prev) - ipc->prev->next = ipc->next; - else - ipc_head = ipc->next; - if (ipc->next) - ipc->next->prev = ipc->prev; - ipc->prev = ipc->next = NULL; + list_del(&ipc->list); return 0; } diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index f4306f93e528..c32f338a5a28 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -96,7 +96,7 @@ struct isdn_ppp_resetparams { */ struct isdn_ppp_compressor { struct module *owner; - struct isdn_ppp_compressor *next, *prev; + struct list_head list; int num; /* CCP compression protocol number */ void *(*alloc) (struct isdn_ppp_comp_data *); -- cgit v1.2.3 From 40ca599a8191fcf8fd1ebf288154fac3ab5e4c6e Mon Sep 17 00:00:00 2001 From: Adam Belay Date: Wed, 18 Jun 2003 22:23:14 +0000 Subject: [PNP] Resource Management Cleanups and Updates This patch does the following... 1.) changes struct pnp_resources to pnp_option for clarity 2.) greatly cleans up resource option registration 3.) removes some of the current conflict prevention code in order to increase flexibility, (users will have more control) 4.) various manager cleanups, resulting code is more efficient 5.) fixes the locking bugs many have reported (now uses a mutex) 6.) removes the conflict displaying interface - it is better to handle such things in user space 7.) also many misc. cleanups --- drivers/pnp/base.h | 20 +- drivers/pnp/core.c | 6 +- drivers/pnp/interface.c | 209 +++--------- drivers/pnp/isapnp/core.c | 199 +++++------ drivers/pnp/manager.c | 848 +++++++++++++++++----------------------------- drivers/pnp/quirks.c | 18 +- drivers/pnp/resource.c | 506 ++++++++------------------- drivers/pnp/support.c | 65 ++-- drivers/serial/8250_pnp.c | 62 ++-- include/linux/pnp.h | 127 +++---- 10 files changed, 737 insertions(+), 1323 deletions(-) (limited to 'include/linux') diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index e991aa70220e..d479e099b259 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -4,29 +4,11 @@ void *pnp_alloc(long size); int pnp_interface_attach_device(struct pnp_dev *dev); void pnp_name_device(struct pnp_dev *dev); void pnp_fixup_device(struct pnp_dev *dev); -void pnp_free_resources(struct pnp_resources *resources); +void pnp_free_option(struct pnp_option *option); int __pnp_add_device(struct pnp_dev *dev); void __pnp_remove_device(struct pnp_dev *dev); -/* resource conflict types */ -#define CONFLICT_TYPE_NONE 0x0000 /* there are no conflicts, other than those in the link */ -#define CONFLICT_TYPE_RESERVED 0x0001 /* the resource requested was reserved */ -#define CONFLICT_TYPE_IN_USE 0x0002 /* there is a conflict because the resource is in use */ -#define CONFLICT_TYPE_PCI 0x0004 /* there is a conflict with a pci device */ -#define CONFLICT_TYPE_INVALID 0x0008 /* the resource requested is invalid */ -#define CONFLICT_TYPE_INTERNAL 0x0010 /* resources within the device conflict with each ohter */ -#define CONFLICT_TYPE_PNP_WARM 0x0020 /* there is a conflict with a pnp device that is active */ -#define CONFLICT_TYPE_PNP_COLD 0x0040 /* there is a conflict with a pnp device that is disabled */ - -/* conflict search modes */ -#define SEARCH_WARM 1 /* check for conflicts with active devices */ -#define SEARCH_COLD 0 /* check for conflicts with disabled devices */ - -struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode); int pnp_check_port(struct pnp_dev * dev, int idx); -struct pnp_dev * pnp_check_mem_conflicts(struct pnp_dev * dev, int idx, int mode); int pnp_check_mem(struct pnp_dev * dev, int idx); -struct pnp_dev * pnp_check_irq_conflicts(struct pnp_dev * dev, int idx, int mode); int pnp_check_irq(struct pnp_dev * dev, int idx); -struct pnp_dev * pnp_check_dma_conflicts(struct pnp_dev * dev, int idx, int mode); int pnp_check_dma(struct pnp_dev * dev, int idx); diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index 7ca8de1a140f..313604dba12a 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c @@ -104,8 +104,8 @@ static void pnp_free_ids(struct pnp_dev *dev) static void pnp_release_device(struct device *dmdev) { struct pnp_dev * dev = to_pnp_dev(dmdev); - if (dev->possible) - pnp_free_resources(dev->possible); + pnp_free_option(dev->independent); + pnp_free_option(dev->dependent); pnp_free_ids(dev); kfree(dev); } @@ -122,7 +122,7 @@ int __pnp_add_device(struct pnp_dev *dev) list_add_tail(&dev->global_list, &pnp_global); list_add_tail(&dev->protocol_list, &dev->protocol->devices); spin_unlock(&pnp_lock); - pnp_auto_config_dev(dev); + ret = device_register(&dev->dev); if (ret == 0) pnp_interface_attach_device(dev); diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 00f4f9463e96..adf85eb325c3 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -168,7 +168,8 @@ static void pnp_print_mem(pnp_info_buffer_t *buffer, char *space, struct pnp_mem pnp_printf(buffer, ", %s\n", s); } -static void pnp_print_resources(pnp_info_buffer_t *buffer, char *space, struct pnp_resources *res, int dep) +static void pnp_print_option(pnp_info_buffer_t *buffer, char *space, + struct pnp_option *option, int dep) { char *s; struct pnp_port *port; @@ -176,49 +177,55 @@ static void pnp_print_resources(pnp_info_buffer_t *buffer, char *space, struct p struct pnp_dma *dma; struct pnp_mem *mem; - switch (res->priority) { - case PNP_RES_PRIORITY_PREFERRED: - s = "preferred"; - break; - case PNP_RES_PRIORITY_ACCEPTABLE: - s = "acceptable"; - break; - case PNP_RES_PRIORITY_FUNCTIONAL: - s = "functional"; - break; - default: - s = "invalid"; - } - if (dep > 0) + if (dep) { + switch (option->priority) { + case PNP_RES_PRIORITY_PREFERRED: + s = "preferred"; + break; + case PNP_RES_PRIORITY_ACCEPTABLE: + s = "acceptable"; + break; + case PNP_RES_PRIORITY_FUNCTIONAL: + s = "functional"; + break; + default: + s = "invalid"; + } pnp_printf(buffer, "Dependent: %02i - Priority %s\n",dep, s); - for (port = res->port; port; port = port->next) + } + + for (port = option->port; port; port = port->next) pnp_print_port(buffer, space, port); - for (irq = res->irq; irq; irq = irq->next) + for (irq = option->irq; irq; irq = irq->next) pnp_print_irq(buffer, space, irq); - for (dma = res->dma; dma; dma = dma->next) + for (dma = option->dma; dma; dma = dma->next) pnp_print_dma(buffer, space, dma); - for (mem = res->mem; mem; mem = mem->next) + for (mem = option->mem; mem; mem = mem->next) pnp_print_mem(buffer, space, mem); } -static ssize_t pnp_show_possible_resources(struct device *dmdev, char *buf) + +static ssize_t pnp_show_options(struct device *dmdev, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); - struct pnp_resources * res = dev->possible; - int ret, dep = 0; + struct pnp_option * independent = dev->independent; + struct pnp_option * dependent = dev->dependent; + int ret, dep = 1; + pnp_info_buffer_t *buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t)); if (!buffer) return -ENOMEM; + buffer->len = PAGE_SIZE; buffer->buffer = buf; buffer->curr = buffer->buffer; - while (res){ - if (dep == 0) - pnp_print_resources(buffer, "", res, dep); - else - pnp_print_resources(buffer, " ", res, dep); - res = res->dep; + if (independent) + pnp_print_option(buffer, "", independent, 0); + + while (dependent){ + pnp_print_option(buffer, " ", dependent, dep); + dependent = dependent->next; dep++; } ret = (buffer->curr - buf); @@ -226,97 +233,8 @@ static ssize_t pnp_show_possible_resources(struct device *dmdev, char *buf) return ret; } -static DEVICE_ATTR(possible,S_IRUGO,pnp_show_possible_resources,NULL); - -static void pnp_print_conflict_node(pnp_info_buffer_t *buffer, struct pnp_dev * dev) -{ - if (!dev) - return; - pnp_printf(buffer, "'%s'.\n", dev->dev.bus_id); -} - -static void pnp_print_conflict_desc(pnp_info_buffer_t *buffer, int conflict) -{ - if (!conflict) - return; - pnp_printf(buffer, " Conflict Detected: %2x - ", conflict); - switch (conflict) { - case CONFLICT_TYPE_RESERVED: - pnp_printf(buffer, "manually reserved.\n"); - break; - - case CONFLICT_TYPE_IN_USE: - pnp_printf(buffer, "currently in use.\n"); - break; - - case CONFLICT_TYPE_PCI: - pnp_printf(buffer, "PCI device.\n"); - break; - - case CONFLICT_TYPE_INVALID: - pnp_printf(buffer, "invalid.\n"); - break; - - case CONFLICT_TYPE_INTERNAL: - pnp_printf(buffer, "another resource on this device.\n"); - break; - - case CONFLICT_TYPE_PNP_WARM: - pnp_printf(buffer, "active PnP device "); - break; - - case CONFLICT_TYPE_PNP_COLD: - pnp_printf(buffer, "disabled PnP device "); - break; - default: - pnp_printf(buffer, "Unknown conflict.\n"); - break; - } -} - -static void pnp_print_conflict(pnp_info_buffer_t *buffer, struct pnp_dev * dev, int idx, int type) -{ - struct pnp_dev * cdev, * wdev = NULL; - int conflict; - switch (type) { - case IORESOURCE_IO: - conflict = pnp_check_port(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_port_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_port_conflicts(dev, idx, SEARCH_COLD); - break; - case IORESOURCE_MEM: - conflict = pnp_check_mem(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_mem_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_mem_conflicts(dev, idx, SEARCH_COLD); - break; - case IORESOURCE_IRQ: - conflict = pnp_check_irq(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_irq_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_irq_conflicts(dev, idx, SEARCH_COLD); - break; - case IORESOURCE_DMA: - conflict = pnp_check_dma(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_dma_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_dma_conflicts(dev, idx, SEARCH_COLD); - break; - default: - return; - } - - pnp_print_conflict_desc(buffer, conflict); - - if (wdev) - pnp_print_conflict_node(buffer, wdev); +static DEVICE_ATTR(options,S_IRUGO,pnp_show_options,NULL); - if (cdev) { - pnp_print_conflict_desc(buffer, CONFLICT_TYPE_PNP_COLD); - pnp_print_conflict_node(buffer, cdev); - } -} static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) { @@ -332,12 +250,6 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) buffer->buffer = buf; buffer->curr = buffer->buffer; - pnp_printf(buffer,"mode = "); - if (dev->config_mode & PNP_CONFIG_MANUAL) - pnp_printf(buffer,"manual\n"); - else - pnp_printf(buffer,"auto\n"); - pnp_printf(buffer,"state = "); if (dev->active) pnp_printf(buffer,"active\n"); @@ -350,7 +262,6 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) pnp_printf(buffer," 0x%lx-0x%lx \n", pnp_port_start(dev, i), pnp_port_end(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_IO); } } for (i = 0; i < PNP_MAX_MEM; i++) { @@ -359,21 +270,18 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) pnp_printf(buffer," 0x%lx-0x%lx \n", pnp_mem_start(dev, i), pnp_mem_end(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_MEM); } } for (i = 0; i < PNP_MAX_IRQ; i++) { if (pnp_irq_valid(dev, i)) { pnp_printf(buffer,"irq"); pnp_printf(buffer," %ld \n", pnp_irq(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_IRQ); } } for (i = 0; i < PNP_MAX_DMA; i++) { if (pnp_dma_valid(dev, i)) { pnp_printf(buffer,"dma"); pnp_printf(buffer," %ld \n", pnp_dma(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_DMA); } } ret = (buffer->curr - buf); @@ -381,7 +289,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) return ret; } -extern int pnp_resolve_conflicts(struct pnp_dev *dev); +extern struct semaphore pnp_res_mutex; static ssize_t pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count) @@ -390,6 +298,12 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count char *buf = (void *)ubuf; int retval = 0; + if (dev->status & PNP_ATTACHED) { + retval = -EBUSY; + pnp_info("Device %s cannot be configured because it is in use.", dev->dev.bus_id); + goto done; + } + while (isspace(*buf)) ++buf; if (!strnicmp(buf,"disable",7)) { @@ -400,41 +314,23 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count retval = pnp_activate_dev(dev); goto done; } - if (!strnicmp(buf,"reset",5)) { - if (!dev->active) - goto done; - retval = pnp_disable_dev(dev); - if (retval) + if (!strnicmp(buf,"fill",4)) { + if (dev->active) goto done; - retval = pnp_activate_dev(dev); + retval = pnp_auto_config_dev(dev); goto done; } if (!strnicmp(buf,"auto",4)) { if (dev->active) goto done; + pnp_init_resources(&dev->res); retval = pnp_auto_config_dev(dev); goto done; } if (!strnicmp(buf,"clear",5)) { if (dev->active) goto done; - spin_lock(&pnp_lock); - dev->config_mode = PNP_CONFIG_MANUAL; - pnp_init_resource_table(&dev->res); - if (dev->rule) - dev->rule->depnum = 0; - spin_unlock(&pnp_lock); - goto done; - } - if (!strnicmp(buf,"resolve",7)) { - retval = pnp_resolve_conflicts(dev); - goto done; - } - if (!strnicmp(buf,"get",3)) { - spin_lock(&pnp_lock); - if (pnp_can_read(dev)) - dev->protocol->get(dev, &dev->res); - spin_unlock(&pnp_lock); + pnp_init_resources(&dev->res); goto done; } if (!strnicmp(buf,"set",3)) { @@ -442,9 +338,8 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count if (dev->active) goto done; buf += 3; - spin_lock(&pnp_lock); - dev->config_mode = PNP_CONFIG_MANUAL; - pnp_init_resource_table(&dev->res); + pnp_init_resources(&dev->res); + down(&pnp_res_mutex); while (1) { while (isspace(*buf)) ++buf; @@ -514,7 +409,7 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count } break; } - spin_unlock(&pnp_lock); + up(&pnp_res_mutex); goto done; } done: @@ -543,7 +438,7 @@ static DEVICE_ATTR(id,S_IRUGO,pnp_show_current_ids,NULL); int pnp_interface_attach_device(struct pnp_dev *dev) { - device_create_file(&dev->dev,&dev_attr_possible); + device_create_file(&dev->dev,&dev_attr_options); device_create_file(&dev->dev,&dev_attr_resources); device_create_file(&dev->dev,&dev_attr_id); return 0; diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index 5f659c17cc34..d0018d859a91 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -31,6 +31,7 @@ * 2002-06-06 Made the use of dma channel 0 configurable * Gerald Teschl * 2002-10-06 Ported to PnP Layer - Adam Belay + * 2003-08-11 Resource Management Updates - Adam Belay */ #include @@ -460,6 +461,7 @@ static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int si dev->capabilities |= PNP_READ; dev->capabilities |= PNP_WRITE; dev->capabilities |= PNP_DISABLE; + pnp_init_resources(&dev->res); return dev; } @@ -468,8 +470,8 @@ static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int si * Add IRQ resource to resources list. */ -static void __init isapnp_add_irq_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_irq_resource(struct pnp_option *option, + int size) { unsigned char tmp[3]; struct pnp_irq *irq; @@ -483,7 +485,7 @@ static void __init isapnp_add_irq_resource(struct pnp_dev *dev, irq->flags = tmp[2]; else irq->flags = IORESOURCE_IRQ_HIGHEDGE; - pnp_add_irq_resource(dev, depnum, irq); + pnp_register_irq_resource(option, irq); return; } @@ -491,8 +493,8 @@ static void __init isapnp_add_irq_resource(struct pnp_dev *dev, * Add DMA resource to resources list. */ -static void __init isapnp_add_dma_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_dma_resource(struct pnp_option *option, + int size) { unsigned char tmp[2]; struct pnp_dma *dma; @@ -503,7 +505,7 @@ static void __init isapnp_add_dma_resource(struct pnp_dev *dev, return; dma->map = tmp[0]; dma->flags = tmp[1]; - pnp_add_dma_resource(dev, depnum, dma); + pnp_register_dma_resource(option, dma); return; } @@ -511,8 +513,8 @@ static void __init isapnp_add_dma_resource(struct pnp_dev *dev, * Add port resource to resources list. */ -static void __init isapnp_add_port_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_port_resource(struct pnp_option *option, + int size) { unsigned char tmp[7]; struct pnp_port *port; @@ -526,7 +528,7 @@ static void __init isapnp_add_port_resource(struct pnp_dev *dev, port->align = tmp[5]; port->size = tmp[6]; port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } @@ -534,8 +536,8 @@ static void __init isapnp_add_port_resource(struct pnp_dev *dev, * Add fixed port resource to resources list. */ -static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option, + int size) { unsigned char tmp[3]; struct pnp_port *port; @@ -548,7 +550,7 @@ static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev, port->size = tmp[2]; port->align = 0; port->flags = PNP_PORT_FLAG_FIXED; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } @@ -556,8 +558,8 @@ static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev, * Add memory resource to resources list. */ -static void __init isapnp_add_mem_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_mem_resource(struct pnp_option *option, + int size) { unsigned char tmp[9]; struct pnp_mem *mem; @@ -571,7 +573,7 @@ static void __init isapnp_add_mem_resource(struct pnp_dev *dev, mem->align = (tmp[6] << 8) | tmp[5]; mem->size = ((tmp[8] << 8) | tmp[7]) << 8; mem->flags = tmp[0]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); return; } @@ -579,8 +581,8 @@ static void __init isapnp_add_mem_resource(struct pnp_dev *dev, * Add 32-bit memory resource to resources list. */ -static void __init isapnp_add_mem32_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_mem32_resource(struct pnp_option *option, + int size) { unsigned char tmp[17]; struct pnp_mem *mem; @@ -594,15 +596,15 @@ static void __init isapnp_add_mem32_resource(struct pnp_dev *dev, mem->align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9]; mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13]; mem->flags = tmp[0]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); } /* * Add 32-bit fixed memory resource to resources list. */ -static void __init isapnp_add_fixed_mem32_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option, + int size) { unsigned char tmp[9]; struct pnp_mem *mem; @@ -615,14 +617,14 @@ static void __init isapnp_add_fixed_mem32_resource(struct pnp_dev *dev, mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; mem->align = 0; mem->flags = tmp[0]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); } /* * Parse card name for ISA PnP device. */ - -static void __init + +static void __init isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size) { if (name[0] == '\0') { @@ -634,7 +636,7 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size) /* clean whitespace from end of string */ while (size1 > 0 && name[--size1] == ' ') name[size1] = '\0'; - } + } } /* @@ -644,14 +646,17 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size) static int __init isapnp_create_device(struct pnp_card *card, unsigned short size) { - int number = 0, skip = 0, depnum = 0, dependent = 0, compat = 0; + int number = 0, skip = 0, priority = 0, compat = 0; unsigned char type, tmp[17]; + struct pnp_option *option; struct pnp_dev *dev; if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; - if (pnp_build_resource(dev, 0) == NULL) + option = pnp_register_independent_option(dev); + if (!option) return 1; pnp_add_card_device(card,dev); + while (1) { if (isapnp_read_tag(&type, &size)<0) return 1; @@ -662,15 +667,16 @@ static int __init isapnp_create_device(struct pnp_card *card, if (size >= 5 && size <= 6) { if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; - pnp_build_resource(dev,0); - pnp_add_card_device(card,dev); size = 0; skip = 0; + option = pnp_register_independent_option(dev); + if (!option) + return 1; + pnp_add_card_device(card,dev); } else { skip = 1; } - dependent = 0; - depnum = 0; + priority = 0; compat = 0; break; case _STAG_COMPATDEVID: @@ -684,43 +690,43 @@ static int __init isapnp_create_device(struct pnp_card *card, case _STAG_IRQ: if (size < 2 || size > 3) goto __skip; - isapnp_add_irq_resource(dev, depnum, size); + isapnp_parse_irq_resource(option, size); size = 0; break; case _STAG_DMA: if (size != 2) goto __skip; - isapnp_add_dma_resource(dev, depnum, size); + isapnp_parse_dma_resource(option, size); size = 0; break; case _STAG_STARTDEP: if (size > 1) goto __skip; - dependent = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; + priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; if (size > 0) { isapnp_peek(tmp, size); - dependent = 0x100 | tmp[0]; + priority = 0x100 | tmp[0]; size = 0; } - pnp_build_resource(dev,dependent); - depnum = pnp_get_max_depnum(dev); + option = pnp_register_dependent_option(dev,priority); + if (!option) + return 1; break; case _STAG_ENDDEP: if (size != 0) goto __skip; - dependent = 0; - depnum = 0; + priority = 0; break; case _STAG_IOPORT: if (size != 7) goto __skip; - isapnp_add_port_resource(dev, depnum, size); + isapnp_parse_port_resource(option, size); size = 0; break; case _STAG_FIXEDIO: if (size != 3) goto __skip; - isapnp_add_fixed_port_resource(dev, depnum, size); + isapnp_parse_fixed_port_resource(option, size); size = 0; break; case _STAG_VENDOR: @@ -728,7 +734,7 @@ static int __init isapnp_create_device(struct pnp_card *card, case _LTAG_MEMRANGE: if (size != 9) goto __skip; - isapnp_add_mem_resource(dev, depnum, size); + isapnp_parse_mem_resource(option, size); size = 0; break; case _LTAG_ANSISTR: @@ -743,13 +749,13 @@ static int __init isapnp_create_device(struct pnp_card *card, case _LTAG_MEM32RANGE: if (size != 17) goto __skip; - isapnp_add_mem32_resource(dev, depnum, size); + isapnp_parse_mem32_resource(option, size); size = 0; break; case _LTAG_FIXEDMEM32RANGE: if (size != 9) goto __skip; - isapnp_add_fixed_mem32_resource(dev, depnum, size); + isapnp_parse_fixed_mem32_resource(option, size); size = 0; break; case _STAG_END: @@ -859,63 +865,6 @@ static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor, pnp_add_card_id(id,card); } - -static int isapnp_parse_current_resources(struct pnp_dev *dev, struct pnp_resource_table * res) -{ - int tmp, ret; - struct pnp_rule_table rule; - if (dev->rule) - rule = *dev->rule; - else { - if (!pnp_generate_rule(dev,1,&rule)) - return -EINVAL; - } - - dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE); - if (dev->active) { - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { - ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1)); - if (!ret) - continue; - res->port_resource[tmp].start = ret; - if (rule.port[tmp]) - res->port_resource[tmp].end = ret + rule.port[tmp]->size - 1; - else - res->port_resource[tmp].end = ret + 1; /* all we can do is assume 1 :-( */ - res->port_resource[tmp].flags = IORESOURCE_IO; - } - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { - ret = isapnp_read_dword(ISAPNP_CFG_MEM + (tmp << 3)); - if (!ret) - continue; - res->mem_resource[tmp].start = ret; - if (rule.mem[tmp]) - res->mem_resource[tmp].end = ret + rule.mem[tmp]->size - 1; - else - res->mem_resource[tmp].end = ret + 1; /* all we can do is assume 1 :-( */ - res->mem_resource[tmp].flags = IORESOURCE_MEM; - } - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { - ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8); - if (!ret) - continue; - res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret; - res->irq_resource[tmp].flags = IORESOURCE_IRQ; - } - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { - ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp); - if (ret == 4) - continue; - if (rule.dma[tmp]) { /* some isapnp systems forget to set this to 4 so we have to check */ - res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret; - res->dma_resource[tmp].flags = IORESOURCE_DMA; - } - } - } - return 0; -} - - /* * Build device list for all present ISA PnP devices. */ @@ -925,7 +874,6 @@ static int __init isapnp_build_device_list(void) int csn; unsigned char header[9], checksum; struct pnp_card *card; - struct pnp_dev *dev; isapnp_wait(); isapnp_key(); @@ -959,13 +907,6 @@ static int __init isapnp_build_device_list(void) card->checksum = isapnp_checksum_value; card->protocol = &isapnp_protocol; - /* read the current resource data */ - card_for_each_dev(card,dev) { - isapnp_device(dev->number); - pnp_init_resource_table(&dev->res); - isapnp_parse_current_resources(dev, &dev->res); - } - pnp_add_card(card); } isapnp_wait(); @@ -1041,12 +982,50 @@ EXPORT_SYMBOL(isapnp_write_dword); EXPORT_SYMBOL(isapnp_wake); EXPORT_SYMBOL(isapnp_device); +static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table *res) +{ + int tmp, ret; + + dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE); + if (dev->active) { + for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { + ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1)); + if (!ret) + continue; + res->port_resource[tmp].start = ret; + res->port_resource[tmp].flags = IORESOURCE_IO; + } + for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { + ret = isapnp_read_dword(ISAPNP_CFG_MEM + (tmp << 3)); + if (!ret) + continue; + res->mem_resource[tmp].start = ret; + res->mem_resource[tmp].flags = IORESOURCE_MEM; + } + for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { + ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8); + if (!ret) + continue; + res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret; + res->irq_resource[tmp].flags = IORESOURCE_IRQ; + } + for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { + ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp); + if (ret == 4) + continue; + res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret; + res->dma_resource[tmp].flags = IORESOURCE_DMA; + } + } + return 0; +} + static int isapnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table * res) { int ret; - pnp_init_resource_table(res); + pnp_init_resources(res); isapnp_cfg_begin(dev->card->number, dev->number); - ret = isapnp_parse_current_resources(dev, res); + ret = isapnp_read_resources(dev, res); isapnp_cfg_end(); return ret; } diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index 0b168a7b0c48..34d3620c8e3a 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c @@ -1,6 +1,7 @@ /* * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices * + * based on isapnp.c resource management (c) Jaroslav Kysela * Copyright 2003 Adam Belay * */ @@ -20,551 +21,341 @@ #include #include "base.h" +DECLARE_MUTEX(pnp_res_mutex); -int pnp_max_moves = 4; - - -static int pnp_next_port(struct pnp_dev * dev, int idx) +static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) { - struct pnp_port *port; unsigned long *start, *end, *flags; - if (!dev || idx < 0 || idx >= PNP_MAX_PORT) - return 0; - port = dev->rule->port[idx]; - if (!port) + + if (!dev || !rule) + return -EINVAL; + + if (idx >= PNP_MAX_PORT) { + pnp_err("More than 4 ports is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ + return 1; + } + + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO)) return 1; start = &dev->res.port_resource[idx].start; end = &dev->res.port_resource[idx].end; flags = &dev->res.port_resource[idx].flags; - /* set the initial values if this is the first time */ - if (*start == 0) { - *start = port->min; - *end = *start + port->size - 1; - *flags = port->flags | IORESOURCE_IO; - if (!pnp_check_port(dev, idx)) - return 1; - } + /* set the initial values */ + *start = rule->min; + *end = *start + rule->size - 1; + *flags = *flags | rule->flags | IORESOURCE_IO; /* run through until pnp_check_port is happy */ - do { - *start += port->align; - *end = *start + port->size - 1; - if (*start > port->max || !port->align) + while (!pnp_check_port(dev, idx)) { + *start += rule->align; + *end = *start + rule->size - 1; + if (*start > rule->max || !rule->align) return 0; - } while (pnp_check_port(dev, idx)); + } return 1; } -static int pnp_next_mem(struct pnp_dev * dev, int idx) +static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) { - struct pnp_mem *mem; unsigned long *start, *end, *flags; - if (!dev || idx < 0 || idx >= PNP_MAX_MEM) - return 0; - mem = dev->rule->mem[idx]; - if (!mem) + + if (!dev || !rule) + return -EINVAL; + + if (idx >= PNP_MAX_MEM) { + pnp_err("More than 8 mems is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ + return 1; + } + + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO)) return 1; start = &dev->res.mem_resource[idx].start; end = &dev->res.mem_resource[idx].end; flags = &dev->res.mem_resource[idx].flags; - /* set the initial values if this is the first time */ - if (*start == 0) { - *start = mem->min; - *end = *start + mem->size -1; - *flags = mem->flags | IORESOURCE_MEM; - if (!(mem->flags & IORESOURCE_MEM_WRITEABLE)) - *flags |= IORESOURCE_READONLY; - if (mem->flags & IORESOURCE_MEM_CACHEABLE) - *flags |= IORESOURCE_CACHEABLE; - if (mem->flags & IORESOURCE_MEM_RANGELENGTH) - *flags |= IORESOURCE_RANGELENGTH; - if (mem->flags & IORESOURCE_MEM_SHADOWABLE) - *flags |= IORESOURCE_SHADOWABLE; - if (!pnp_check_mem(dev, idx)) - return 1; - } + /* set the initial values */ + *start = rule->min; + *end = *start + rule->size -1; + *flags = *flags | rule->flags | IORESOURCE_MEM; + + /* convert pnp flags to standard Linux flags */ + if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) + *flags |= IORESOURCE_READONLY; + if (rule->flags & IORESOURCE_MEM_CACHEABLE) + *flags |= IORESOURCE_CACHEABLE; + if (rule->flags & IORESOURCE_MEM_RANGELENGTH) + *flags |= IORESOURCE_RANGELENGTH; + if (rule->flags & IORESOURCE_MEM_SHADOWABLE) + *flags |= IORESOURCE_SHADOWABLE; /* run through until pnp_check_mem is happy */ - do { - *start += mem->align; - *end = *start + mem->size - 1; - if (*start > mem->max || !mem->align) + while (!pnp_check_mem(dev, idx)) { + *start += rule->align; + *end = *start + rule->size - 1; + if (*start > rule->max || !rule->align) return 0; - } while (pnp_check_mem(dev, idx)); + } return 1; } -static int pnp_next_irq(struct pnp_dev * dev, int idx) +static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx) { - struct pnp_irq *irq; unsigned long *start, *end, *flags; - int i, mask; - if (!dev || idx < 0 || idx >= PNP_MAX_IRQ) - return 0; - irq = dev->rule->irq[idx]; - if (!irq) - return 1; + int i; - start = &dev->res.irq_resource[idx].start; - end = &dev->res.irq_resource[idx].end; - flags = &dev->res.irq_resource[idx].flags; + /* IRQ priority: this table is good for i386 */ + static unsigned short xtab[16] = { + 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 + }; - /* set the initial values if this is the first time */ - if (*start == -1) { - *start = *end = 0; - *flags = irq->flags | IORESOURCE_IRQ; - if (!pnp_check_irq(dev, idx)) - return 1; - } + if (!dev || !rule) + return -EINVAL; - mask = irq->map; - for (i = *start + 1; i < 16; i++) - { - if(mask>>i & 0x01) { - *start = *end = i; - if(!pnp_check_irq(dev, idx)) - return 1; - } + if (idx >= PNP_MAX_IRQ) { + pnp_err("More than 2 irqs is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ + return 1; } - return 0; -} -static int pnp_next_dma(struct pnp_dev * dev, int idx) -{ - struct pnp_dma *dma; - unsigned long *start, *end, *flags; - int i, mask; - if (!dev || idx < 0 || idx >= PNP_MAX_DMA) - return -EINVAL; - dma = dev->rule->dma[idx]; - if (!dma) + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO)) return 1; - start = &dev->res.dma_resource[idx].start; - end = &dev->res.dma_resource[idx].end; - flags = &dev->res.dma_resource[idx].flags; + start = &dev->res.irq_resource[idx].start; + end = &dev->res.irq_resource[idx].end; + flags = &dev->res.irq_resource[idx].flags; - /* set the initial values if this is the first time */ - if (*start == -1) { - *start = *end = 0; - *flags = dma->flags | IORESOURCE_DMA; - if (!pnp_check_dma(dev, idx)) - return 1; - } + /* set the initial values */ + *flags = *flags | rule->flags | IORESOURCE_IRQ; - mask = dma->map; - for (i = *start + 1; i < 8; i++) - { - if(mask>>i & 0x01) { - *start = *end = i; - if(!pnp_check_dma(dev, idx)) + for (i = 0; i < 16; i++) { + if(rule->map & (1<rule->depnum; - int max = pnp_get_max_depnum(dev); - int priority = PNP_RES_PRIORITY_PREFERRED; - - if (depnum < 0) - return 0; - - if (max == 0) { - if (pnp_generate_rule(dev, 0, dev->rule)) { - dev->rule->depnum = -1; - return 1; - } - } - - if(depnum > 0) { - struct pnp_resources * res = pnp_find_resources(dev, depnum); - priority = res->priority; - } - - for (; priority <= PNP_RES_PRIORITY_FUNCTIONAL; priority++, depnum = 0) { - depnum += 1; - for (; depnum <= max; depnum++) { - struct pnp_resources * res = pnp_find_resources(dev, depnum); - if (res->priority == priority) { - if(pnp_generate_rule(dev, depnum, dev->rule)) { - dev->rule->depnum = depnum; - return 1; - } - } - } - } - return 0; -} - -struct pnp_change { - struct list_head change_list; - struct list_head changes; - struct pnp_resource_table res_bak; - struct pnp_rule_table rule_bak; - struct pnp_dev * dev; -}; - -static void pnp_free_changes(struct pnp_change * parent) -{ - struct list_head * pos, * temp; - list_for_each_safe(pos, temp, &parent->changes) { - struct pnp_change * change = list_entry(pos, struct pnp_change, change_list); - list_del(&change->change_list); - kfree(change); - } -} - -static void pnp_undo_changes(struct pnp_change * parent) -{ - struct list_head * pos, * temp; - list_for_each_safe(pos, temp, &parent->changes) { - struct pnp_change * change = list_entry(pos, struct pnp_change, change_list); - *change->dev->rule = change->rule_bak; - change->dev->res = change->res_bak; - list_del(&change->change_list); - kfree(change); - } -} - -static struct pnp_change * pnp_add_change(struct pnp_change * parent, struct pnp_dev * dev) -{ - struct pnp_change * change = pnp_alloc(sizeof(struct pnp_change)); - if (!change) - return NULL; - change->res_bak = dev->res; - change->rule_bak = *dev->rule; - change->dev = dev; - INIT_LIST_HEAD(&change->changes); - if (parent) - list_add(&change->change_list, &parent->changes); - return change; -} - -static void pnp_commit_changes(struct pnp_change * parent, struct pnp_change * change) -{ - /* check if it's the root change */ - if (!parent) - return; - if (!list_empty(&change->changes)) - list_splice_init(&change->changes, &parent->changes); -} - -static int pnp_next_config(struct pnp_dev * dev, int move, struct pnp_change * parent); - -static int pnp_next_request(struct pnp_dev * dev, int move, struct pnp_change * parent, struct pnp_change * change) +static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) { + unsigned long *start, *end, *flags; int i; - struct pnp_dev * cdev; - - for (i = 0; i < PNP_MAX_PORT; i++) { - if (dev->res.port_resource[i].start == 0 - || pnp_check_port_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_port(dev,i)) - return 0; - } - do { - cdev = pnp_check_port_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_port(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (dev->res.mem_resource[i].start == 0 - || pnp_check_mem_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_mem(dev,i)) - return 0; - } - do { - cdev = pnp_check_mem_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_mem(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if (dev->res.irq_resource[i].start == -1 - || pnp_check_irq_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_irq(dev,i)) - return 0; - } - do { - cdev = pnp_check_irq_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_irq(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - for (i = 0; i < PNP_MAX_DMA; i++) { - if (dev->res.dma_resource[i].start == -1 - || pnp_check_dma_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_dma(dev,i)) - return 0; - } - do { - cdev = pnp_check_dma_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_dma(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - return 1; -} -static int pnp_next_config(struct pnp_dev * dev, int move, struct pnp_change * parent) -{ - struct pnp_change * change; - move--; - if (!dev->rule) - return 0; - change = pnp_add_change(parent,dev); - if (!change) - return 0; - if (!pnp_can_configure(dev)) - goto fail; - if (!dev->rule->depnum) { - if (!pnp_next_rule(dev)) - goto fail; - } - while (!pnp_next_request(dev, move, parent, change)) { - if(!pnp_next_rule(dev)) - goto fail; - pnp_init_resource_table(&dev->res); - } - if (!parent) { - pnp_free_changes(change); - kfree(change); - } - return 1; + /* DMA priority: this table is good for i386 */ + static unsigned short xtab[8] = { + 1, 3, 5, 6, 7, 0, 2, 4 + }; -fail: - if (!parent) - kfree(change); - return 0; -} + if (!dev || !rule) + return -EINVAL; -/* this advanced algorithm will shuffle other configs to make room and ensure that the most possible devices have configs */ -static int pnp_advanced_config(struct pnp_dev * dev) -{ - int move; - /* if the device cannot be configured skip it */ - if (!pnp_can_configure(dev)) + if (idx >= PNP_MAX_DMA) { + pnp_err("More than 2 dmas is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ return 1; - if (!dev->rule) { - dev->rule = pnp_alloc(sizeof(struct pnp_rule_table)); - if (!dev->rule) - return -ENOMEM; } - spin_lock(&pnp_lock); - for (move = 1; move <= pnp_max_moves; move++) { - dev->rule->depnum = 0; - pnp_init_resource_table(&dev->res); - if (pnp_next_config(dev,move,NULL)) { - spin_unlock(&pnp_lock); - return 1; - } - } + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO)) + return 1; - pnp_init_resource_table(&dev->res); - dev->rule->depnum = 0; - spin_unlock(&pnp_lock); - pnp_err("res: Unable to resolve resource conflicts for the device '%s', some devices may not be usable.", dev->dev.bus_id); - return 0; -} + start = &dev->res.dma_resource[idx].start; + end = &dev->res.dma_resource[idx].end; + flags = &dev->res.dma_resource[idx].flags; -int pnp_resolve_conflicts(struct pnp_dev *dev) -{ - int i; - struct pnp_dev * cdev; - - for (i = 0; i < PNP_MAX_PORT; i++) - { - do { - cdev = pnp_check_port_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - for (i = 0; i < PNP_MAX_MEM; i++) - { - do { - cdev = pnp_check_mem_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - for (i = 0; i < PNP_MAX_IRQ; i++) - { - do { - cdev = pnp_check_irq_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - for (i = 0; i < PNP_MAX_DMA; i++) - { - do { - cdev = pnp_check_dma_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - return 1; -} + /* set the initial values */ + *flags = *flags | rule->flags | IORESOURCE_DMA; -/* this is a much faster algorithm but it may not leave resources for other devices to use */ -static int pnp_simple_config(struct pnp_dev * dev) -{ - int i; - spin_lock(&pnp_lock); - if (dev->active) { - spin_unlock(&pnp_lock); - return 1; - } - if (!dev->rule) { - dev->rule = pnp_alloc(sizeof(struct pnp_rule_table)); - if (!dev->rule) { - spin_unlock(&pnp_lock); - return -ENOMEM; - } - } - dev->rule->depnum = 0; - pnp_init_resource_table(&dev->res); - while (pnp_next_rule(dev)) { - for (i = 0; i < PNP_MAX_PORT; i++) { - if (!pnp_next_port(dev,i)) - continue; - } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (!pnp_next_mem(dev,i)) - continue; - } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if (!pnp_next_irq(dev,i)) - continue; - } - for (i = 0; i < PNP_MAX_DMA; i++) { - if (!pnp_next_dma(dev,i)) - continue; + for (i = 0; i < 8; i++) { + if(rule->map & (1<res); - dev->rule->depnum = 0; - spin_unlock(&pnp_lock); return 0; - -done: - pnp_resolve_conflicts(dev); /* this is required or we will break the advanced configs */ - return 1; } -static int pnp_compare_resources(struct pnp_resource_table * resa, struct pnp_resource_table * resb) +/** + * pnp_init_resources - Resets a resource table to default values. + * @table: pointer to the desired resource table + * + */ +void pnp_init_resources(struct pnp_resource_table *table) { int idx; + down(&pnp_res_mutex); for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - if (resa->irq_resource[idx].start != resb->irq_resource[idx].start) - return 1; + table->irq_resource[idx].name = NULL; + table->irq_resource[idx].start = -1; + table->irq_resource[idx].end = -1; + table->irq_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_DMA; idx++) { - if (resa->dma_resource[idx].start != resb->dma_resource[idx].start) - return 1; + table->dma_resource[idx].name = NULL; + table->dma_resource[idx].start = -1; + table->dma_resource[idx].end = -1; + table->dma_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_PORT; idx++) { - if (resa->port_resource[idx].start != resb->port_resource[idx].start) - return 1; - if (resa->port_resource[idx].end != resb->port_resource[idx].end) - return 1; + table->port_resource[idx].name = NULL; + table->port_resource[idx].start = 0; + table->port_resource[idx].end = 0; + table->port_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_MEM; idx++) { - if (resa->mem_resource[idx].start != resb->mem_resource[idx].start) - return 1; - if (resa->mem_resource[idx].end != resb->mem_resource[idx].end) - return 1; + table->mem_resource[idx].name = NULL; + table->mem_resource[idx].start = 0; + table->mem_resource[idx].end = 0; + table->mem_resource[idx].flags = IORESOURCE_AUTO; } - return 0; + up(&pnp_res_mutex); } - -/* - * PnP Device Resource Management - */ - /** - * pnp_auto_config_dev - determines the best possible resource configuration based on available information - * @dev: pointer to the desired device + * pnp_clean_resources - clears resources that were not manually set + * @res - the resources to clean * */ - -int pnp_auto_config_dev(struct pnp_dev *dev) -{ - int error; - if(!dev) - return -EINVAL; - - dev->config_mode = PNP_CONFIG_AUTO; - - if(dev->active) - error = pnp_resolve_conflicts(dev); - else - error = pnp_advanced_config(dev); - return error; -} - -static void pnp_process_manual_resources(struct pnp_resource_table * ctab, struct pnp_resource_table * ntab) +static void pnp_clean_resources(struct pnp_resource_table * res) { int idx; for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - if (ntab->irq_resource[idx].flags & IORESOURCE_AUTO) + if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO)) continue; - ctab->irq_resource[idx].start = ntab->irq_resource[idx].start; - ctab->irq_resource[idx].end = ntab->irq_resource[idx].end; - ctab->irq_resource[idx].flags = ntab->irq_resource[idx].flags; + res->irq_resource[idx].start = -1; + res->irq_resource[idx].end = -1; + res->irq_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_DMA; idx++) { - if (ntab->dma_resource[idx].flags & IORESOURCE_AUTO) + if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO)) continue; - ctab->dma_resource[idx].start = ntab->dma_resource[idx].start; - ctab->dma_resource[idx].end = ntab->dma_resource[idx].end; - ctab->dma_resource[idx].flags = ntab->dma_resource[idx].flags; + res->dma_resource[idx].start = -1; + res->dma_resource[idx].end = -1; + res->dma_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_PORT; idx++) { - if (ntab->port_resource[idx].flags & IORESOURCE_AUTO) + if (!(res->port_resource[idx].flags & IORESOURCE_AUTO)) continue; - ctab->port_resource[idx].start = ntab->port_resource[idx].start; - ctab->port_resource[idx].end = ntab->port_resource[idx].end; - ctab->port_resource[idx].flags = ntab->port_resource[idx].flags; + res->port_resource[idx].start = 0; + res->port_resource[idx].end = 0; + res->port_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_MEM; idx++) { - if (ntab->irq_resource[idx].flags & IORESOURCE_AUTO) + if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO)) continue; - ctab->irq_resource[idx].start = ntab->mem_resource[idx].start; - ctab->irq_resource[idx].end = ntab->mem_resource[idx].end; - ctab->irq_resource[idx].flags = ntab->mem_resource[idx].flags; + res->mem_resource[idx].start = 0; + res->mem_resource[idx].end = 0; + res->mem_resource[idx].flags = IORESOURCE_AUTO; } } +/** + * pnp_assign_resources - assigns resources to the device based on the specified dependent number + * @dev: pointer to the desired device + * @depnum: the dependent function number + * + * Only set depnum to 0 if the device does not have dependent options. + */ +int pnp_assign_resources(struct pnp_dev *dev, int depnum) +{ + struct pnp_port *port; + struct pnp_mem *mem; + struct pnp_irq *irq; + struct pnp_dma *dma; + int nport = 0, nmem = 0, nirq = 0, ndma = 0; + + if (!pnp_can_configure(dev)) + return -ENODEV; + + down(&pnp_res_mutex); + pnp_clean_resources(&dev->res); /* start with a fresh slate */ + if (dev->independent) { + port = dev->independent->port; + mem = dev->independent->mem; + irq = dev->independent->irq; + dma = dev->independent->dma; + while (port) { + if (!pnp_assign_port(dev, port, nport)) + goto fail; + nport++; + port = port->next; + } + while (mem) { + if (!pnp_assign_mem(dev, mem, nmem)) + goto fail; + nmem++; + mem = mem->next; + } + while (irq) { + if (!pnp_assign_irq(dev, irq, nirq)) + goto fail; + nirq++; + irq = irq->next; + } + while (dma) { + if (!pnp_assign_dma(dev, dma, ndma)) + goto fail; + ndma++; + dma = dma->next; + } + } + + if (depnum) { + struct pnp_option *dep; + int i; + for (i=1,dep=dev->dependent; inext) + if(!dep) + goto fail; + port =dep->port; + mem = dep->mem; + irq = dep->irq; + dma = dep->dma; + while (port) { + if (!pnp_assign_port(dev, port, nport)) + goto fail; + nport++; + port = port->next; + } + while (mem) { + if (!pnp_assign_mem(dev, mem, nmem)) + goto fail; + nmem++; + mem = mem->next; + } + while (irq) { + if (!pnp_assign_irq(dev, irq, nirq)) + goto fail; + nirq++; + irq = irq->next; + } + while (dma) { + if (!pnp_assign_dma(dev, dma, ndma)) + goto fail; + ndma++; + dma = dma->next; + } + } else if (dev->dependent) + goto fail; + + up(&pnp_res_mutex); + return 1; + +fail: + pnp_clean_resources(&dev->res); + up(&pnp_res_mutex); + return 0; +} + /** * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table * @dev: pointer to the desired device @@ -572,22 +363,21 @@ static void pnp_process_manual_resources(struct pnp_resource_table * ctab, struc * * This function can be used by drivers that want to manually set thier resources. */ - int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode) { int i; struct pnp_resource_table * bak; if (!dev || !res) return -EINVAL; - if (dev->active) - return -EBUSY; + if (!pnp_can_configure(dev)) + return -ENODEV; bak = pnp_alloc(sizeof(struct pnp_resource_table)); if (!bak) return -ENOMEM; *bak = dev->res; - spin_lock(&pnp_lock); - pnp_process_manual_resources(&dev->res, res); + down(&pnp_res_mutex); + dev->res = *res; if (!(mode & PNP_CONFIG_FORCE)) { for (i = 0; i < PNP_MAX_PORT; i++) { if(pnp_check_port(dev,i)) @@ -606,27 +396,64 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, goto fail; } } - dev->config_mode = PNP_CONFIG_MANUAL; - spin_unlock(&pnp_lock); + up(&pnp_res_mutex); - pnp_resolve_conflicts(dev); + pnp_auto_config_dev(dev); kfree(bak); return 0; fail: dev->res = *bak; - spin_unlock(&pnp_lock); + up(&pnp_res_mutex); kfree(bak); return -EINVAL; } /** - * pnp_activate_dev - activates a PnP device for use + * pnp_auto_config_dev - automatically assigns resources to a device * @dev: pointer to the desired device * - * finds the best resource configuration and then informs the correct pnp protocol */ +int pnp_auto_config_dev(struct pnp_dev *dev) +{ + struct pnp_option *dep; + int i = 1; + if(!dev) + return -EINVAL; + + if(!pnp_can_configure(dev)) { + pnp_info("Device %s does not support resource configuration.", dev->dev.bus_id); + return -ENODEV; + } + + if (!dev->dependent) { + if (pnp_assign_resources(dev, 0)) + return 1; + else + return 0; + } + + dep = dev->dependent; + do { + if (pnp_assign_resources(dev, i)) + return 1; + + /* if this dependent resource failed, try the next one */ + dep = dep->next; + i++; + } while (dep); + + pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id); + return 0; +} + +/** + * pnp_activate_dev - activates a PnP device for use + * @dev: pointer to the desired device + * + * does not validate or set resources so be careful. + */ int pnp_activate_dev(struct pnp_dev *dev) { if (!dev) @@ -634,55 +461,25 @@ int pnp_activate_dev(struct pnp_dev *dev) if (dev->active) { return 0; /* the device is already active */ } - /* If this condition is true, advanced configuration failed, we need to get this device up and running - * so we use the simple config engine which ignores cold conflicts, this of course may lead to new failures */ - if (!pnp_is_active(dev)) { - if (!pnp_simple_config(dev)) { - pnp_err("res: Unable to resolve resource conflicts for the device '%s'.", dev->dev.bus_id); - goto fail; - } - } - spin_lock(&pnp_lock); /* we lock just in case the device is being configured during this call */ - dev->active = 1; - spin_unlock(&pnp_lock); /* once the device is claimed active we know it won't be configured so we can unlock */ + /* ensure resources are allocated */ + if (!pnp_auto_config_dev(dev)) + return -EBUSY; - if (dev->config_mode & PNP_CONFIG_INVALID) { - pnp_info("res: Unable to activate the PnP device '%s' because its resource configuration is invalid.", dev->dev.bus_id); - goto fail; - } - if (dev->status != PNP_READY && dev->status != PNP_ATTACHED){ - pnp_err("res: Activation failed because the PnP device '%s' is busy.", dev->dev.bus_id); - goto fail; - } if (!pnp_can_write(dev)) { - pnp_info("res: Unable to activate the PnP device '%s' because this feature is not supported.", dev->dev.bus_id); - goto fail; + pnp_info("Device %s does not supported activation.", dev->dev.bus_id); + return -EINVAL; } + if (dev->protocol->set(dev, &dev->res)<0) { - pnp_err("res: The protocol '%s' reports that activating the PnP device '%s' has failed.", dev->protocol->name, dev->dev.bus_id); - goto fail; + pnp_err("Failed to activate device %s.", dev->dev.bus_id); + return -EIO; } - if (pnp_can_read(dev)) { - struct pnp_resource_table * res = pnp_alloc(sizeof(struct pnp_resource_table)); - if (!res) - goto fail; - dev->protocol->get(dev, res); - if (pnp_compare_resources(&dev->res, res)) /* if this happens we may be in big trouble but it's best just to continue */ - pnp_err("res: The resources requested do not match those set for the PnP device '%s'.", dev->dev.bus_id); - kfree(res); - } else - dev->active = pnp_is_active(dev); - pnp_dbg("res: the device '%s' has been activated.", dev->dev.bus_id); - if (dev->rule) { - kfree(dev->rule); - dev->rule = NULL; - } - return 0; -fail: - dev->active = 0; /* fixes incorrect active state */ - return -EINVAL; + dev->active = 1; + pnp_info("Device %s activated.", dev->dev.bus_id); + + return 1; } /** @@ -691,7 +488,6 @@ fail: * * inform the correct pnp protocol so that resources can be used by other devices */ - int pnp_disable_dev(struct pnp_dev *dev) { if (!dev) @@ -699,21 +495,25 @@ int pnp_disable_dev(struct pnp_dev *dev) if (!dev->active) { return 0; /* the device is already disabled */ } - if (dev->status != PNP_READY){ - pnp_info("res: Disable failed becuase the PnP device '%s' is busy.", dev->dev.bus_id); - return -EINVAL; - } + if (!pnp_can_disable(dev)) { - pnp_info("res: Unable to disable the PnP device '%s' because this feature is not supported.", dev->dev.bus_id); + pnp_info("Device %s does not supported disabling.", dev->dev.bus_id); return -EINVAL; } if (dev->protocol->disable(dev)<0) { - pnp_err("res: The protocol '%s' reports that disabling the PnP device '%s' has failed.", dev->protocol->name, dev->dev.bus_id); - return -1; + pnp_err("Failed to disable device %s.", dev->dev.bus_id); + return -EIO; } - dev->active = 0; /* just in case the protocol doesn't do this */ - pnp_dbg("res: the device '%s' has been disabled.", dev->dev.bus_id); - return 0; + + dev->active = 0; + pnp_info("Device %s disabled.", dev->dev.bus_id); + + /* release the resources so that other devices can use them */ + down(&pnp_res_mutex); + pnp_clean_resources(&dev->res); + up(&pnp_res_mutex); + + return 1; } /** @@ -723,7 +523,6 @@ int pnp_disable_dev(struct pnp_dev *dev) * @size: size of region * */ - void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { if (resource == NULL) @@ -734,19 +533,10 @@ void pnp_resource_change(struct resource *resource, unsigned long start, unsigne } -EXPORT_SYMBOL(pnp_auto_config_dev); +EXPORT_SYMBOL(pnp_assign_resources); EXPORT_SYMBOL(pnp_manual_config_dev); +EXPORT_SYMBOL(pnp_auto_config_dev); EXPORT_SYMBOL(pnp_activate_dev); EXPORT_SYMBOL(pnp_disable_dev); EXPORT_SYMBOL(pnp_resource_change); - - -/* format is: pnp_max_moves=num */ - -static int __init pnp_setup_max_moves(char *str) -{ - get_option(&str,&pnp_max_moves); - return 1; -} - -__setup("pnp_max_moves=", pnp_setup_max_moves); +EXPORT_SYMBOL(pnp_init_resources); diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index dcb4570cd657..883f845a8d11 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -30,7 +30,7 @@ static void quirk_awe32_resources(struct pnp_dev *dev) { struct pnp_port *port, *port2, *port3; - struct pnp_resources *res = dev->possible->dep; + struct pnp_option *res = dev->dependent; /* * Unfortunately the isapnp_add_port_resource is too tightly bound @@ -38,7 +38,7 @@ static void quirk_awe32_resources(struct pnp_dev *dev) * two extra ports (at offset 0x400 and 0x800 from the one given) by * hand. */ - for ( ; res ; res = res->dep ) { + for ( ; res ; res = res->next ) { port2 = pnp_alloc(sizeof(struct pnp_port)); if (!port2) return; @@ -62,9 +62,9 @@ static void quirk_awe32_resources(struct pnp_dev *dev) static void quirk_cmi8330_resources(struct pnp_dev *dev) { - struct pnp_resources *res = dev->possible->dep; + struct pnp_option *res = dev->dependent; - for ( ; res ; res = res->dep ) { + for ( ; res ; res = res->next ) { struct pnp_irq *irq; struct pnp_dma *dma; @@ -82,7 +82,7 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev) static void quirk_sb16audio_resources(struct pnp_dev *dev) { struct pnp_port *port; - struct pnp_resources *res = dev->possible->dep; + struct pnp_option *res = dev->dependent; int changed = 0; /* @@ -91,7 +91,7 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) * auto-configured. */ - for( ; res ; res = res->dep ) { + for( ; res ; res = res->next ) { port = res->port; if(!port) continue; @@ -118,11 +118,11 @@ static void quirk_opl3sax_resources(struct pnp_dev *dev) * doesn't allow a DMA channel of 0, afflicted card is an * OPL3Sax where x=4. */ - struct pnp_resources *res; + struct pnp_option *res; int max; - res = dev->possible; + res = dev->dependent; max = 0; - for (res = res->dep; res; res = res->dep) { + for (; res; res = res->next) { if (res->dma->map > max) max = res->dma->map; } diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index 7e738da9e6ee..e462c34d3306 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -10,18 +10,19 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include #include "base.h" -int pnp_allow_dma0 = -1; /* allow dma 0 during auto activation: -1=off (:default), 0=off (set by user), 1=on */ +int pnp_allow_dma0 = -1; /* allow dma 0 during auto activation: + * -1=off (:default), 0=off (set by user), 1=on */ int pnp_skip_pci_scan; /* skip PCI resource scanning */ int pnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */ int pnp_reserve_dma[8] = { [0 ... 7] = -1 }; /* reserve (don't use) some DMA */ @@ -30,88 +31,75 @@ int pnp_reserve_mem[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some memor /* - * possible resource registration + * option registration */ -struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) +static struct pnp_option * pnp_build_option(int priority) { - struct pnp_resources *res, *ptr, *ptra; + struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option)); - res = pnp_alloc(sizeof(struct pnp_resources)); - if (!res) + /* check if pnp_alloc ran out of memory */ + if (!option) return NULL; - ptr = dev->possible; - if (ptr) { /* add to another list */ - ptra = ptr->dep; - while (ptra && ptra->dep) - ptra = ptra->dep; - if (!ptra) - ptr->dep = res; - else - ptra->dep = res; - } else - dev->possible = res; - if (dependent) { - res->priority = dependent & 0xff; - if (res->priority > PNP_RES_PRIORITY_FUNCTIONAL) - res->priority = PNP_RES_PRIORITY_INVALID; - } else - res->priority = PNP_RES_PRIORITY_PREFERRED; - return res; + + option->priority = priority & 0xff; + /* make sure the priority is valid */ + if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL) + option->priority = PNP_RES_PRIORITY_INVALID; + + return option; } -struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum) +struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev) { - int i; - struct pnp_resources *res; + struct pnp_option *option; if (!dev) return NULL; - res = dev->possible; - if (!res) - return NULL; - for (i = 0; i < depnum; i++) - { - if (res->dep) - res = res->dep; - else - return NULL; - } - return res; + + option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED); + + /* this should never happen but if it does we'll try to continue */ + if (dev->independent) + pnp_err("independent resource already registered"); + dev->independent = option; + return option; } -int pnp_get_max_depnum(struct pnp_dev *dev) +struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority) { - int num = 0; - struct pnp_resources *res; + struct pnp_option *option; if (!dev) - return -EINVAL; - res = dev->possible; - if (!res) - return -EINVAL; - while (res->dep){ - res = res->dep; - num++; - } - return num; + return NULL; + + option = pnp_build_option(priority); + + if (dev->dependent) { + struct pnp_option *parent = dev->dependent; + while (parent->next) + parent = parent->next; + parent->next = option; + } else + dev->dependent = option; + return option; } -int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) +int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) { int i; - struct pnp_resources *res; struct pnp_irq *ptr; - res = pnp_find_resources(dev,depnum); - if (!res) + if (!option) return -EINVAL; if (!data) return -EINVAL; - ptr = res->irq; + + ptr = option->irq; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->irq = data; + option->irq = data; + #ifdef CONFIG_PCI for (i=0; i<16; i++) if (data->map & (1<dma; + + ptr = option->dma; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->dma = data; + option->dma = data; + return 0; } -int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data) +int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) { - struct pnp_resources *res; struct pnp_port *ptr; - res = pnp_find_resources(dev,depnum); - if (!res) + if (!option) return -EINVAL; if (!data) return -EINVAL; - ptr = res->port; + + ptr = option->port; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->port = data; + option->port = data; + return 0; } -int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data) +int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) { - struct pnp_resources *res; struct pnp_mem *ptr; - res = pnp_find_resources(dev,depnum); - if (!res) + if (!option) return -EINVAL; if (!data) return -EINVAL; - ptr = res->mem; + + ptr = option->mem; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->mem = data; + option->mem = data; return 0; } @@ -221,18 +208,18 @@ static void pnp_free_mem(struct pnp_mem *mem) } } -void pnp_free_resources(struct pnp_resources *resources) +void pnp_free_option(struct pnp_option *option) { - struct pnp_resources *next; - - while (resources) { - next = resources->dep; - pnp_free_port(resources->port); - pnp_free_irq(resources->irq); - pnp_free_dma(resources->dma); - pnp_free_mem(resources->mem); - kfree(resources); - resources = next; + struct pnp_option *next; + + while (option) { + next = option->next; + pnp_free_port(option->port); + pnp_free_irq(option->irq); + pnp_free_dma(option->dma); + pnp_free_mem(option->mem); + kfree(option); + option = next; } } @@ -253,50 +240,23 @@ void pnp_free_resources(struct pnp_resources *resources) (*(enda) >= *(startb) && *(enda) <= *(endb)) || \ (*(starta) < *(startb) && *(enda) > *(endb))) -struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - unsigned long *port, *end, *tport, *tend; - struct pnp_dev *tdev; - port = &dev->res.port_resource[idx].start; - end = &dev->res.port_resource[idx].end; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.port_resource[idx].start == 0) - return NULL; - - /* check for cold conflicts */ - pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) - continue; - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { - if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { - tport = &tdev->res.port_resource[tmp].start; - tend = &tdev->res.port_resource[tmp].end; - if (ranged_conflict(port,end,tport,tend)) - return tdev; - } - } - } - return NULL; -} - int pnp_check_port(struct pnp_dev * dev, int idx) { int tmp; + struct pnp_dev *tdev; unsigned long *port, *end, *tport, *tend; port = &dev->res.port_resource[idx].start; end = &dev->res.port_resource[idx].end; /* if the resource doesn't exist, don't complain about it */ if (dev->res.port_resource[idx].start == 0) - return 0; + return 1; - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { if (check_region(*port, length(port,end))) - return CONFLICT_TYPE_IN_USE; + return 0; } /* check if the resource is reserved */ @@ -304,7 +264,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx) int rport = pnp_reserve_io[tmp << 1]; int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1; if (ranged_conflict(port,end,&rport,&rend)) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ @@ -313,61 +273,44 @@ int pnp_check_port(struct pnp_dev * dev, int idx) tport = &dev->res.port_resource[tmp].start; tend = &dev->res.port_resource[tmp].end; if (ranged_conflict(port,end,tport,tend)) - return CONFLICT_TYPE_INTERNAL; + return 0; } } - /* check for warm conflicts */ - if (pnp_check_port_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - - return 0; -} - -struct pnp_dev * pnp_check_mem_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - unsigned long *addr, *end, *taddr, *tend; - struct pnp_dev *tdev; - addr = &dev->res.mem_resource[idx].start; - end = &dev->res.mem_resource[idx].end; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.mem_resource[idx].start == 0) - return NULL; - - /* check for cold conflicts */ + /* check for conflicts with other pnp devices */ pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) + if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { - if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { - taddr = &tdev->res.mem_resource[tmp].start; - tend = &tdev->res.mem_resource[tmp].end; - if (ranged_conflict(addr,end,taddr,tend)) - return tdev; + for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { + if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { + tport = &tdev->res.port_resource[tmp].start; + tend = &tdev->res.port_resource[tmp].end; + if (ranged_conflict(port,end,tport,tend)) + return 0; } } } - return NULL; + + return 1; } int pnp_check_mem(struct pnp_dev * dev, int idx) { int tmp; + struct pnp_dev *tdev; unsigned long *addr, *end, *taddr, *tend; addr = &dev->res.mem_resource[idx].start; end = &dev->res.mem_resource[idx].end; /* if the resource doesn't exist, don't complain about it */ if (dev->res.mem_resource[idx].start == 0) - return 0; + return 1; - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { if (__check_region(&iomem_resource, *addr, length(addr,end))) - return CONFLICT_TYPE_IN_USE; + return 0; } /* check if the resource is reserved */ @@ -375,7 +318,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx) int raddr = pnp_reserve_mem[tmp << 1]; int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1; if (ranged_conflict(addr,end,&raddr,&rend)) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ @@ -384,40 +327,25 @@ int pnp_check_mem(struct pnp_dev * dev, int idx) taddr = &dev->res.mem_resource[tmp].start; tend = &dev->res.mem_resource[tmp].end; if (ranged_conflict(addr,end,taddr,tend)) - return CONFLICT_TYPE_INTERNAL; + return 0; } } - /* check for warm conflicts */ - if (pnp_check_mem_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - - return 0; -} - -struct pnp_dev * pnp_check_irq_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - struct pnp_dev * tdev; - unsigned long * irq = &dev->res.irq_resource[idx].start; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.irq_resource[idx].start == -1) - return NULL; - - /* check for cold conflicts */ + /* check for conflicts with other pnp devices */ pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) + if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { - if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { - if ((tdev->res.irq_resource[tmp].start == *irq)) - return tdev; + for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { + if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { + taddr = &tdev->res.mem_resource[tmp].start; + tend = &tdev->res.mem_resource[tmp].end; + if (ranged_conflict(addr,end,taddr,tend)) + return 0; } } } - return NULL; + + return 1; } static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs) @@ -428,27 +356,28 @@ static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs) int pnp_check_irq(struct pnp_dev * dev, int idx) { int tmp; + struct pnp_dev *tdev; unsigned long * irq = &dev->res.irq_resource[idx].start; /* if the resource doesn't exist, don't complain about it */ if (dev->res.irq_resource[idx].start == -1) - return 0; + return 1; /* check if the resource is valid */ if (*irq < 0 || *irq > 15) - return CONFLICT_TYPE_INVALID; + return 0; /* check if the resource is reserved */ for (tmp = 0; tmp < 16; tmp++) { if (pnp_reserve_irq[tmp] == *irq) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) { if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { if (dev->res.irq_resource[tmp].start == *irq) - return CONFLICT_TYPE_INTERNAL; + return 0; } } @@ -458,233 +387,94 @@ int pnp_check_irq(struct pnp_dev * dev, int idx) struct pci_dev * pci = NULL; while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { if (pci->irq == *irq) - return CONFLICT_TYPE_PCI; + return 0; } } #endif - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { if (request_irq(*irq, pnp_test_handler, SA_INTERRUPT, "pnp", NULL)) - return CONFLICT_TYPE_IN_USE; + return 0; free_irq(*irq, NULL); } - /* check for warm conflicts */ - if (pnp_check_irq_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - - return 0; -} - - -struct pnp_dev * pnp_check_dma_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - struct pnp_dev * tdev; - unsigned long * dma = &dev->res.dma_resource[idx].start; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.dma_resource[idx].start == -1) - return NULL; - - /* check for cold conflicts */ + /* check for conflicts with other pnp devices */ pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) + if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { - if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { - if ((tdev->res.dma_resource[tmp].start == *dma)) - return tdev; + for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { + if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { + if ((tdev->res.irq_resource[tmp].start == *irq)) + return 0; } } } - return NULL; + + return 1; } int pnp_check_dma(struct pnp_dev * dev, int idx) { int tmp, mindma = 1; + struct pnp_dev *tdev; unsigned long * dma = &dev->res.dma_resource[idx].start; /* if the resource doesn't exist, don't complain about it */ if (dev->res.dma_resource[idx].start == -1) - return 0; + return 1; /* check if the resource is valid */ if (pnp_allow_dma0 == 1) mindma = 0; if (*dma < mindma || *dma == 4 || *dma > 7) - return CONFLICT_TYPE_INVALID; + return 0; /* check if the resource is reserved */ for (tmp = 0; tmp < 8; tmp++) { if (pnp_reserve_dma[tmp] == *dma) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) { if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { if (dev->res.dma_resource[tmp].start == *dma) - return CONFLICT_TYPE_INTERNAL; + return 0; } } - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { if (request_dma(*dma, "pnp")) - return CONFLICT_TYPE_IN_USE; + return 0; free_dma(*dma); } - /* check for warm conflicts */ - if (pnp_check_dma_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - return 0; -} - - -/** - * pnp_init_resource_table - Resets a resource table to default values. - * @table: pointer to the desired resource table - * - */ - -void pnp_init_resource_table(struct pnp_resource_table *table) -{ - int idx; - for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - table->irq_resource[idx].name = NULL; - table->irq_resource[idx].start = -1; - table->irq_resource[idx].end = -1; - table->irq_resource[idx].flags = IORESOURCE_AUTO; - } - for (idx = 0; idx < PNP_MAX_DMA; idx++) { - table->dma_resource[idx].name = NULL; - table->dma_resource[idx].start = -1; - table->dma_resource[idx].end = -1; - table->dma_resource[idx].flags = IORESOURCE_AUTO; - } - for (idx = 0; idx < PNP_MAX_PORT; idx++) { - table->port_resource[idx].name = NULL; - table->port_resource[idx].start = 0; - table->port_resource[idx].end = 0; - table->port_resource[idx].flags = IORESOURCE_AUTO; - } - for (idx = 0; idx < PNP_MAX_MEM; idx++) { - table->mem_resource[idx].name = NULL; - table->mem_resource[idx].start = 0; - table->mem_resource[idx].end = 0; - table->mem_resource[idx].flags = IORESOURCE_AUTO; - } -} - - -/** - * pnp_generate_rule - Creates a rule table structure based on depnum and device. - * @dev: pointer to the desired device - * @depnum: dependent function, if not valid will return an error - * @rule: pointer to a rule structure to record data to - * - */ - -int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule) -{ - int nport = 0, nirq = 0, ndma = 0, nmem = 0; - struct pnp_resources * res; - struct pnp_port * port; - struct pnp_mem * mem; - struct pnp_irq * irq; - struct pnp_dma * dma; - - if (depnum < 0 || !rule) - return -EINVAL; - - /* independent */ - res = pnp_find_resources(dev, 0); - if (!res) - return -ENODEV; - port = res->port; - mem = res->mem; - irq = res->irq; - dma = res->dma; - while (port){ - rule->port[nport] = port; - nport++; - port = port->next; - } - while (mem){ - rule->mem[nmem] = mem; - nmem++; - mem = mem->next; - } - while (irq){ - rule->irq[nirq] = irq; - nirq++; - irq = irq->next; - } - while (dma){ - rule->dma[ndma] = dma; - ndma++; - dma = dma->next; - } - - /* dependent */ - if (depnum == 0) - return 1; - res = pnp_find_resources(dev, depnum); - if (!res) - return -ENODEV; - port = res->port; - mem = res->mem; - irq = res->irq; - dma = res->dma; - while (port){ - rule->port[nport] = port; - nport++; - port = port->next; - } - while (mem){ - rule->mem[nmem] = mem; - nmem++; - mem = mem->next; - } - - while (irq){ - rule->irq[nirq] = irq; - nirq++; - irq = irq->next; - } - while (dma){ - rule->dma[ndma] = dma; - ndma++; - dma = dma->next; + /* check for conflicts with other pnp devices */ + pnp_for_each_dev(tdev) { + if (tdev == dev) + continue; + for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { + if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { + if ((tdev->res.dma_resource[tmp].start == *dma)) + return 0; + } + } } - /* clear the remaining values */ - for (; nport < PNP_MAX_PORT; nport++) - rule->port[nport] = NULL; - for (; nmem < PNP_MAX_MEM; nmem++) - rule->mem[nmem] = NULL; - for (; nirq < PNP_MAX_IRQ; nirq++) - rule->irq[nirq] = NULL; - for (; ndma < PNP_MAX_DMA; ndma++) - rule->dma[ndma] = NULL; return 1; } -EXPORT_SYMBOL(pnp_build_resource); -EXPORT_SYMBOL(pnp_find_resources); -EXPORT_SYMBOL(pnp_get_max_depnum); -EXPORT_SYMBOL(pnp_add_irq_resource); -EXPORT_SYMBOL(pnp_add_dma_resource); -EXPORT_SYMBOL(pnp_add_port_resource); -EXPORT_SYMBOL(pnp_add_mem_resource); -EXPORT_SYMBOL(pnp_init_resource_table); -EXPORT_SYMBOL(pnp_generate_rule); +EXPORT_SYMBOL(pnp_register_dependent_resource); +EXPORT_SYMBOL(pnp_register_independent_resource); +EXPORT_SYMBOL(pnp_register_irq_resource); +EXPORT_SYMBOL(pnp_register_dma_resource); +EXPORT_SYMBOL(pnp_register_port_resource); +EXPORT_SYMBOL(pnp_register_mem_resource); /* format is: allowdma0 */ diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c index c54cf87fb8cc..0b285c152e04 100644 --- a/drivers/pnp/support.c +++ b/drivers/pnp/support.c @@ -1,7 +1,7 @@ /* * support.c - provides standard pnp functions for the use of pnp protocol drivers, * - * Copyright 2002 Adam Belay + * Copyright 2003 Adam Belay * * Resource parsing functions are based on those in the linux pnpbios driver. * Copyright Christian Schmidt, Tom Lees, David Hinds, Alan Cox, Thomas Hood, @@ -10,6 +10,7 @@ #include #include +#include #ifdef CONFIG_PNP_DEBUG #define DEBUG @@ -122,7 +123,7 @@ unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * e return NULL; /* Blank the resource table values */ - pnp_init_resource_table(res); + pnp_init_resources(res); while ((char *)p < (char *)end) { @@ -250,7 +251,7 @@ unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * e * Possible resource reading functions * */ -static void possible_mem(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_mem(unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem * mem; mem = pnp_alloc(sizeof(struct pnp_mem)); @@ -261,11 +262,11 @@ static void possible_mem(unsigned char *p, int size, int depnum, struct pnp_dev mem->align = (p[7] << 8) | p[6]; mem->size = ((p[9] << 8) | p[8]) << 8; mem->flags = p[1]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); return; } -static void possible_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_mem32(unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem * mem; mem = pnp_alloc(sizeof(struct pnp_mem)); @@ -276,11 +277,11 @@ static void possible_mem32(unsigned char *p, int size, int depnum, struct pnp_de mem->align = (p[13] << 24) | (p[12] << 16) | (p[11] << 8) | p[10]; mem->size = (p[17] << 24) | (p[16] << 16) | (p[15] << 8) | p[14]; mem->flags = p[1]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); return; } -static void possible_fixed_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_fixed_mem32(unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem * mem; mem = pnp_alloc(sizeof(struct pnp_mem)); @@ -290,11 +291,11 @@ static void possible_fixed_mem32(unsigned char *p, int size, int depnum, struct mem->size = (p[9] << 24) | (p[8] << 16) | (p[7] << 8) | p[6]; mem->align = 0; mem->flags = p[1]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); return; } -static void possible_irq(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_irq(unsigned char *p, int size, struct pnp_option *option) { struct pnp_irq * irq; irq = pnp_alloc(sizeof(struct pnp_irq)); @@ -303,11 +304,13 @@ static void possible_irq(unsigned char *p, int size, int depnum, struct pnp_dev irq->map = (p[2] << 8) | p[1]; if (size > 2) irq->flags = p[3]; - pnp_add_irq_resource(dev,depnum,irq); + else + irq->flags = IORESOURCE_IRQ_HIGHEDGE; + pnp_register_irq_resource(option,irq); return; } -static void possible_dma(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_dma(unsigned char *p, int size, struct pnp_option *option) { struct pnp_dma * dma; dma = pnp_alloc(sizeof(struct pnp_dma)); @@ -315,11 +318,11 @@ static void possible_dma(unsigned char *p, int size, int depnum, struct pnp_dev return; dma->map = p[1]; dma->flags = p[2]; - pnp_add_dma_resource(dev,depnum,dma); + pnp_register_dma_resource(option,dma); return; } -static void possible_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_port(unsigned char *p, int size, struct pnp_option *option) { struct pnp_port * port; port = pnp_alloc(sizeof(struct pnp_port)); @@ -330,11 +333,11 @@ static void possible_port(unsigned char *p, int size, int depnum, struct pnp_dev port->align = p[6]; port->size = p[7]; port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } -static void possible_fixed_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_fixed_port(unsigned char *p, int size, struct pnp_option *option) { struct pnp_port * port; port = pnp_alloc(sizeof(struct pnp_port)); @@ -344,7 +347,7 @@ static void possible_fixed_port(unsigned char *p, int size, int depnum, struct p port->size = p[3]; port->align = 0; port->flags = PNP_PORT_FLAG_FIXED; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } @@ -358,12 +361,14 @@ static void possible_fixed_port(unsigned char *p, int size, int depnum, struct p unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev *dev) { - int len, depnum = 0, dependent = 0; + int len, priority = 0; + struct pnp_option *option; if (!p) return NULL; - if (pnp_build_resource(dev, 0) == NULL) + option = pnp_register_independent_option(dev); + if (!option) return NULL; while ((char *)p < (char *)end) { @@ -375,21 +380,21 @@ unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * { if (len != 9) goto lrg_err; - possible_mem(p,len,depnum,dev); + possible_mem(p,len,option); break; } case LARGE_TAG_MEM32: { if (len != 17) goto lrg_err; - possible_mem32(p,len,depnum,dev); + possible_mem32(p,len,option); break; } case LARGE_TAG_FIXEDMEM32: { if (len != 9) goto lrg_err; - possible_fixed_mem32(p,len,depnum,dev); + possible_fixed_mem32(p,len,option); break; } default: /* an unkown tag */ @@ -410,46 +415,46 @@ unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * { if (len < 2 || len > 3) goto sm_err; - possible_irq(p,len,depnum,dev); + possible_irq(p,len,option); break; } case SMALL_TAG_DMA: { if (len != 2) goto sm_err; - possible_dma(p,len,depnum,dev); + possible_dma(p,len,option); break; } case SMALL_TAG_STARTDEP: { if (len > 1) goto sm_err; - dependent = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; + priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; if (len > 0) - dependent = 0x100 | p[1]; - pnp_build_resource(dev,dependent); - depnum = pnp_get_max_depnum(dev); + priority = 0x100 | p[1]; + option = pnp_register_dependent_option(dev, priority); + if (!option) + return NULL; break; } case SMALL_TAG_ENDDEP: { if (len != 0) goto sm_err; - depnum = 0; break; } case SMALL_TAG_PORT: { if (len != 7) goto sm_err; - possible_port(p,len,depnum,dev); + possible_port(p,len,option); break; } case SMALL_TAG_FIXEDPORT: { if (len != 3) goto sm_err; - possible_fixed_port(p,len,depnum,dev); + possible_fixed_port(p,len,option); break; } case SMALL_TAG_END: diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index f44dba00d35b..d21396e514e6 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c @@ -315,19 +315,6 @@ static const struct pnp_device_id pnp_dev_table[] = { MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -static inline void avoid_irq_share(struct pnp_dev *dev) -{ - unsigned int map = 0x1FF8; - struct pnp_irq *irq; - struct pnp_resources *res = dev->possible; - - serial8250_get_irq_map(&map); - - for ( ; res; res = res->dep) - for (irq = res->irq; irq; irq = irq->next) - irq->map = map; -} - static char *modem_names[] __devinitdata = { "MODEM", "Modem", "modem", "FAX", "Fax", "fax", "56K", "56k", "K56", "33.6", "28.8", "14.4", @@ -346,6 +333,29 @@ static int __devinit check_name(char *name) return 0; } +static int __devinit check_resources(struct pnp_option *option) +{ + struct pnp_option *tmp; + if (!option) + return 0; + + for (tmp = option; tmp; tmp = tmp->next) { + struct pnp_port *port; + for (port = tmp->port; port; port = port->next) + if ((port->size == 8) && + ((port->min == 0x2f8) || + (port->min == 0x3f8) || + (port->min == 0x2e8) || +#ifdef CONFIG_X86_PC9800 + (port->min == 0x8b0) || +#endif + (port->min == 0x3e8))) + return 1; + } + + return 0; +} + /* * Given a complete unknown PnP device, try to use some heuristics to * detect modems. Currently use such heuristic set: @@ -357,30 +367,16 @@ static int __devinit check_name(char *name) * PnP modems, alternatively we must hardcode all modems in pnp_devices[] * table. */ -static int serial_pnp_guess_board(struct pnp_dev *dev, int *flags) +static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags) { - struct pnp_resources *res = dev->possible; - struct pnp_resources *resa; - if (!(check_name(dev->dev.name) || (dev->card && check_name(dev->card->dev.name)))) return -ENODEV; - if (!res) - return -ENODEV; + if (check_resources(dev->independent)) + return 0; - for (resa = res->dep; resa; resa = resa->dep) { - struct pnp_port *port; - for (port = res->port; port; port = port->next) - if ((port->size == 8) && - ((port->min == 0x2f8) || - (port->min == 0x3f8) || - (port->min == 0x2e8) || -#ifdef CONFIG_X86_PC9800 - (port->min == 0x8b0) || -#endif - (port->min == 0x3e8))) - return 0; - } + if (check_resources(dev->dependent)) + return 0; return -ENODEV; } @@ -395,8 +391,6 @@ serial_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id) if (ret < 0) return ret; } - if (flags & SPCI_FL_NO_SHIRQ) - avoid_irq_share(dev); memset(&serial_req, 0, sizeof(serial_req)); serial_req.irq = pnp_irq(dev,0); serial_req.port = pnp_port_start(dev, 0); diff --git a/include/linux/pnp.h b/include/linux/pnp.h index d0249ab40676..348bb52a716e 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -102,22 +102,13 @@ struct pnp_mem { #define PNP_RES_PRIORITY_FUNCTIONAL 2 #define PNP_RES_PRIORITY_INVALID 65535 -struct pnp_resources { +struct pnp_option { unsigned short priority; /* priority */ struct pnp_port *port; /* first port */ struct pnp_irq *irq; /* first IRQ */ struct pnp_dma *dma; /* first DMA */ struct pnp_mem *mem; /* first memory resource */ - struct pnp_dev *dev; /* parent */ - struct pnp_resources *dep; /* dependent resources */ -}; - -struct pnp_rule_table { - int depnum; - struct pnp_port *port[PNP_MAX_PORT]; - struct pnp_irq *irq[PNP_MAX_IRQ]; - struct pnp_dma *dma[PNP_MAX_DMA]; - struct pnp_mem *mem[PNP_MAX_MEM]; + struct pnp_option *next; /* used to chain dependent resources */ }; struct pnp_resource_table { @@ -187,8 +178,6 @@ static inline void pnp_set_card_drvdata (struct pnp_card_link *pcard, void *data struct pnp_dev { struct device dev; /* Driver Model device interface */ unsigned char number; /* used as an index, must be unique */ - int active; - int capabilities; int status; struct list_head global_list; /* node in global list of devices */ @@ -201,11 +190,13 @@ struct pnp_dev { struct pnp_driver * driver; struct pnp_card_link * card_link; - struct pnp_id * id; /* supported EISA IDs*/ - struct pnp_resource_table res; /* contains the currently chosen resources */ - struct pnp_resources * possible; /* a list of possible resources */ - struct pnp_rule_table * rule; /* the current possible resource set */ - int config_mode; /* flags that determine how the device's resources should be configured */ + struct pnp_id * id; /* supported EISA IDs*/ + + int active; + int capabilities; + struct pnp_option * independent; + struct pnp_option * dependent; + struct pnp_resource_table res; void * protocol_data; /* Used to store protocol specific data */ unsigned short regs; /* ISAPnP: supported registers */ @@ -252,11 +243,9 @@ struct pnp_fixup { void (*quirk_function)(struct pnp_dev *dev); /* fixup function */ }; -/* config modes */ -#define PNP_CONFIG_AUTO 0x0001 /* Use the Resource Configuration Engine to determine resource settings */ -#define PNP_CONFIG_MANUAL 0x0002 /* the config has been manually specified */ -#define PNP_CONFIG_FORCE 0x0004 /* disables validity checking */ -#define PNP_CONFIG_INVALID 0x0008 /* If this flag is set, the pnp layer will refuse to activate the device */ +/* config parameters */ +#define PNP_CONFIG_NORMAL 0x0001 +#define PNP_CONFIG_FORCE 0x0002 /* disables validity checking */ /* capabilities */ #define PNP_READ 0x0001 @@ -271,7 +260,7 @@ struct pnp_fixup { ((dev)->capabilities & PNP_WRITE)) #define pnp_can_disable(dev) (((dev)->protocol) && ((dev)->protocol->disable) && \ ((dev)->capabilities & PNP_DISABLE)) -#define pnp_can_configure(dev) ((!(dev)->active) && ((dev)->config_mode & PNP_CONFIG_AUTO) && \ +#define pnp_can_configure(dev) ((!(dev)->active) && \ ((dev)->capabilities & PNP_CONFIGURABLE)) #ifdef CONFIG_ISAPNP @@ -383,7 +372,7 @@ struct pnp_protocol { #if defined(CONFIG_PNP) -/* core */ +/* device management */ int pnp_register_protocol(struct pnp_protocol *protocol); void pnp_unregister_protocol(struct pnp_protocol *protocol); int pnp_add_device(struct pnp_dev *dev); @@ -392,7 +381,7 @@ int pnp_device_attach(struct pnp_dev *pnp_dev); void pnp_device_detach(struct pnp_dev *pnp_dev); extern struct list_head pnp_global; -/* card */ +/* multidevice card support */ int pnp_add_card(struct pnp_card *card); void pnp_remove_card(struct pnp_card *card); int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); @@ -404,41 +393,35 @@ int pnp_register_card_driver(struct pnp_card_driver * drv); void pnp_unregister_card_driver(struct pnp_card_driver * drv); extern struct list_head pnp_cards; -/* resource */ -struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent); -struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum); -int pnp_get_max_depnum(struct pnp_dev *dev); -int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data); -int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data); -int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data); -int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data); -void pnp_init_resource_table(struct pnp_resource_table *table); -int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule); - -/* manager */ +/* resource management */ +struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev); +struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority); +int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data); +int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data); +int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data); +int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data); +void pnp_init_resources(struct pnp_resource_table *table); +int pnp_assign_resources(struct pnp_dev *dev, int depnum); +int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode); +int pnp_auto_config_dev(struct pnp_dev *dev); +int pnp_validate_config(struct pnp_dev *dev); int pnp_activate_dev(struct pnp_dev *dev); int pnp_disable_dev(struct pnp_dev *dev); void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size); -int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode); -int pnp_auto_config_dev(struct pnp_dev *dev); - -/* driver */ -int compare_pnp_id(struct pnp_id * pos, const char * id); -int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev); -int pnp_register_driver(struct pnp_driver *drv); -void pnp_unregister_driver(struct pnp_driver *drv); -/* support */ +/* protocol helpers */ int pnp_is_active(struct pnp_dev * dev); unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res); unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev * dev); unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res); +int compare_pnp_id(struct pnp_id * pos, const char * id); +int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev); +int pnp_register_driver(struct pnp_driver *drv); +void pnp_unregister_driver(struct pnp_driver *drv); #else -/* just in case anyone decides to call these without PnP Support Enabled */ - -/* core */ +/* device management */ static inline int pnp_register_protocol(struct pnp_protocol *protocol) { return -ENODEV; } static inline void pnp_unregister_protocol(struct pnp_protocol *protocol) { } static inline int pnp_init_device(struct pnp_dev *dev) { return -ENODEV; } @@ -447,7 +430,7 @@ static inline void pnp_remove_device(struct pnp_dev *dev) { } static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; } static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { ; } -/* card */ +/* multidevice card support */ static inline int pnp_add_card(struct pnp_card *card) { return -ENODEV; } static inline void pnp_remove_card(struct pnp_card *card) { ; } static inline int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev) { return -ENODEV; } @@ -458,35 +441,31 @@ static inline void pnp_release_card_device(struct pnp_dev * dev) { ; } static inline int pnp_register_card_driver(struct pnp_card_driver * drv) { return -ENODEV; } static inline void pnp_unregister_card_driver(struct pnp_card_driver * drv) { ; } -/* resource */ -static inline struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) { return NULL; } -static inline struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum) { return NULL; } -static inline int pnp_get_max_depnum(struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline void pnp_init_resource_table(struct pnp_resource_table *table) { ; } -static inline int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule) { return -ENODEV; } - -/* manager */ -static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; } -static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { ; } +/* resource management */ +static inline struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev) { return NULL; } +static inline struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority) { return NULL; } +static inline int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) { return -ENODEV; } +static inline int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data) { return -ENODEV; } +static inline int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) { return -ENODEV; } +static inline int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) { return -ENODEV; } +static inline void pnp_init_resources(struct pnp_resource_table *table) { } +static inline int pnp_assign_resources(struct pnp_dev *dev, int depnum) { return -ENODEV; } static inline int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode) { return -ENODEV; } static inline int pnp_auto_config_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_validate_config(struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { } -/* driver */ -static inline int compare_pnp_id(struct list_head * id_list, const char * id) { return -ENODEV; } -static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; } -static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; } - -/* support */ -static inline int pnp_is_active(struct pnp_dev * dev) { return -ENODEV; } +/* protocol helpers */ +static inline int pnp_is_active(struct pnp_dev * dev) { return 0; } static inline unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res) { return NULL; } static inline unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev * dev) { return NULL; } static inline unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res) { return NULL; } +static inline int compare_pnp_id(struct pnp_id * pos, const char * id) { return -ENODEV; } +static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; } +static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; } #endif /* CONFIG_PNP */ -- cgit v1.2.3 From a95557d5d1036549c00bbb9b277cb63a08619617 Mon Sep 17 00:00:00 2001 From: Manuel Estrada Sainz Date: Wed, 18 Jun 2003 19:34:11 -0700 Subject: [PATCH] DRIVER: request_firmware() hotplug interface --- drivers/base/Kconfig.lib | 11 + drivers/base/Makefile | 1 + drivers/base/firmware_class.c | 503 ++++++++++++++++++++++++++++++++++++++++++ include/linux/firmware.h | 20 ++ lib/Kconfig | 2 + 5 files changed, 537 insertions(+) create mode 100644 drivers/base/Kconfig.lib create mode 100644 drivers/base/firmware_class.c create mode 100644 include/linux/firmware.h (limited to 'include/linux') diff --git a/drivers/base/Kconfig.lib b/drivers/base/Kconfig.lib new file mode 100644 index 000000000000..ef756994e4f8 --- /dev/null +++ b/drivers/base/Kconfig.lib @@ -0,0 +1,11 @@ +# +# To be sourced from lib/Kconfig +# + +config FW_LOADER + tristate "Hotplug firmware loading support" + ---help--- + This option is provided for the case where no in-kernel-tree modules + require hotplug firmware loading support, but a module built outside + the kernel tree does. + diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 800228c16081..334fcc6c6ee6 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -3,4 +3,5 @@ obj-y := core.o sys.o interface.o power.o bus.o \ driver.o class.o platform.o \ cpu.o firmware.o init.o map.o +obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o memblk.o diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c new file mode 100644 index 000000000000..15c8ab792599 --- /dev/null +++ b/drivers/base/firmware_class.c @@ -0,0 +1,503 @@ +/* + * firmware_class.c - Multi purpose firmware loading support + * + * Copyright (c) 2003 Manuel Estrada Sainz + * + * Please see Documentation/firmware_class/ for more information. + * + */ + +#include +#include +#include +#include +#include + +#include +#include "base.h" + +MODULE_AUTHOR("Manuel Estrada Sainz "); +MODULE_DESCRIPTION("Multi purpose firmware loading support"); +MODULE_LICENSE("GPL"); + +static int loading_timeout = 10; /* In seconds */ + +struct firmware_priv { + char fw_id[FIRMWARE_NAME_MAX]; + struct completion completion; + struct bin_attribute attr_data; + struct firmware *fw; + int loading; + int abort; + int alloc_size; + struct timer_list timeout; +}; + +static ssize_t +firmware_timeout_show(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", loading_timeout); +} + +/** + * firmware_timeout_store: + * Description: + * Sets the number of seconds to wait for the firmware. Once + * this expires an error will be return to the driver and no + * firmware will be provided. + * + * Note: zero means 'wait for ever' + * + **/ +static ssize_t +firmware_timeout_store(struct class *class, const char *buf, size_t count) +{ + loading_timeout = simple_strtol(buf, NULL, 10); + return count; +} + +CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); + +static void fw_class_dev_release(struct class_device *class_dev); +int firmware_class_hotplug(struct class_device *dev, char **envp, + int num_envp, char *buffer, int buffer_size); + +struct class firmware_class = { + .name = "firmware", + .hotplug = firmware_class_hotplug, + .release = fw_class_dev_release, +}; + +int +firmware_class_hotplug(struct class_device *class_dev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + int i = 0; + char *scratch = buffer; + + if (buffer_size < (FIRMWARE_NAME_MAX + 10)) + return -ENOMEM; + if (num_envp < 1) + return -ENOMEM; + + envp[i++] = scratch; + scratch += sprintf(scratch, "FIRMWARE=%s", fw_priv->fw_id) + 1; + return 0; +} + +static ssize_t +firmware_loading_show(struct class_device *class_dev, char *buf) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + return sprintf(buf, "%d\n", fw_priv->loading); +} + +/** + * firmware_loading_store: - loading control file + * Description: + * The relevant values are: + * + * 1: Start a load, discarding any previous partial load. + * 0: Conclude the load and handle the data to the driver code. + * -1: Conclude the load with an error and discard any written data. + **/ +static ssize_t +firmware_loading_store(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + int prev_loading = fw_priv->loading; + + fw_priv->loading = simple_strtol(buf, NULL, 10); + + switch (fw_priv->loading) { + case -1: + fw_priv->abort = 1; + wmb(); + complete(&fw_priv->completion); + break; + case 1: + kfree(fw_priv->fw->data); + fw_priv->fw->data = NULL; + fw_priv->fw->size = 0; + fw_priv->alloc_size = 0; + break; + case 0: + if (prev_loading == 1) + complete(&fw_priv->completion); + break; + } + + return count; +} + +CLASS_DEVICE_ATTR(loading, 0644, + firmware_loading_show, firmware_loading_store); + +static ssize_t +firmware_data_read(struct kobject *kobj, + char *buffer, loff_t offset, size_t count) +{ + struct class_device *class_dev = to_class_dev(kobj); + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + struct firmware *fw = fw_priv->fw; + + if (offset > fw->size) + return 0; + if (offset + count > fw->size) + count = fw->size - offset; + + memcpy(buffer, fw->data + offset, count); + return count; +} +static int +fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) +{ + u8 *new_data; + + if (min_size <= fw_priv->alloc_size) + return 0; + + new_data = kmalloc(fw_priv->alloc_size + PAGE_SIZE, GFP_KERNEL); + if (!new_data) { + printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__); + /* Make sure that we don't keep incomplete data */ + fw_priv->abort = 1; + return -ENOMEM; + } + fw_priv->alloc_size += PAGE_SIZE; + if (fw_priv->fw->data) { + memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size); + kfree(fw_priv->fw->data); + } + fw_priv->fw->data = new_data; + BUG_ON(min_size > fw_priv->alloc_size); + return 0; +} + +/** + * firmware_data_write: + * + * Description: + * + * Data written to the 'data' attribute will be later handled to + * the driver as a firmware image. + **/ +static ssize_t +firmware_data_write(struct kobject *kobj, + char *buffer, loff_t offset, size_t count) +{ + struct class_device *class_dev = to_class_dev(kobj); + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + struct firmware *fw = fw_priv->fw; + int retval; + + retval = fw_realloc_buffer(fw_priv, offset + count); + if (retval) + return retval; + + memcpy(fw->data + offset, buffer, count); + + fw->size = max_t(size_t, offset + count, fw->size); + + return count; +} +static struct bin_attribute firmware_attr_data_tmpl = { + .attr = {.name = "data", .mode = 0644}, + .size = 0, + .read = firmware_data_read, + .write = firmware_data_write, +}; + +static void +fw_class_dev_release(struct class_device *class_dev) +{ + kfree(class_dev); +} + +static void +firmware_class_timeout(u_long data) +{ + struct firmware_priv *fw_priv = (struct firmware_priv *) data; + fw_priv->abort = 1; + wmb(); + complete(&fw_priv->completion); +} +static inline void +fw_setup_class_device_id(struct class_device *class_dev, struct device *dev) +{ +#warning we should watch out for name collisions + strncpy(class_dev->class_id, dev->bus_id, BUS_ID_SIZE); + class_dev->class_id[BUS_ID_SIZE - 1] = '\0'; +} +static int +fw_setup_class_device(struct class_device **class_dev_p, + const char *fw_name, struct device *device) +{ + int retval = 0; + struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv), + GFP_KERNEL); + struct class_device *class_dev = kmalloc(sizeof (struct class_device), + GFP_KERNEL); + + if (!fw_priv || !class_dev) { + retval = -ENOMEM; + goto error_kfree; + } + memset(fw_priv, 0, sizeof (*fw_priv)); + memset(class_dev, 0, sizeof (*class_dev)); + + init_completion(&fw_priv->completion); + memcpy(&fw_priv->attr_data, &firmware_attr_data_tmpl, + sizeof (firmware_attr_data_tmpl)); + + strncpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX); + fw_priv->fw_id[FIRMWARE_NAME_MAX - 1] = '\0'; + + fw_setup_class_device_id(class_dev, device); + class_dev->dev = device; + + fw_priv->timeout.function = firmware_class_timeout; + fw_priv->timeout.data = (u_long) fw_priv; + init_timer(&fw_priv->timeout); + + class_dev->class = &firmware_class; + class_set_devdata(class_dev, fw_priv); + retval = class_device_register(class_dev); + if (retval) { + printk(KERN_ERR "%s: class_device_register failed\n", + __FUNCTION__); + goto error_kfree; + } + + retval = sysfs_create_bin_file(&class_dev->kobj, &fw_priv->attr_data); + if (retval) { + printk(KERN_ERR "%s: sysfs_create_bin_file failed\n", + __FUNCTION__); + goto error_unreg_class_dev; + } + + retval = class_device_create_file(class_dev, + &class_device_attr_loading); + if (retval) { + printk(KERN_ERR "%s: class_device_create_file failed\n", + __FUNCTION__); + goto error_remove_data; + } + + fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL); + if (!fw_priv->fw) { + printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n", + __FUNCTION__); + retval = -ENOMEM; + goto error_remove_loading; + } + memset(fw_priv->fw, 0, sizeof (*fw_priv->fw)); + + goto out; + +error_remove_loading: + class_device_remove_file(class_dev, &class_device_attr_loading); +error_remove_data: + sysfs_remove_bin_file(&class_dev->kobj, &fw_priv->attr_data); +error_unreg_class_dev: + class_device_unregister(class_dev); +error_kfree: + kfree(fw_priv); + kfree(class_dev); + *class_dev_p = NULL; +out: + *class_dev_p = class_dev; + return retval; +} +static void +fw_remove_class_device(struct class_device *class_dev) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + + class_device_remove_file(class_dev, &class_device_attr_loading); + sysfs_remove_bin_file(&class_dev->kobj, &fw_priv->attr_data); + class_device_unregister(class_dev); +} + +/** + * request_firmware: - request firmware to hotplug and wait for it + * Description: + * @firmware will be used to return a firmware image by the name + * of @name for device @device. + * + * Should be called from user context where sleeping is allowed. + * + * @name will be use as $FIRMWARE in the hotplug environment and + * should be distinctive enough not to be confused with any other + * firmware image for this or any other device. + **/ +int +request_firmware(const struct firmware **firmware, const char *name, + struct device *device) +{ + struct class_device *class_dev; + struct firmware_priv *fw_priv; + int retval; + + if (!firmware) + return -EINVAL; + + *firmware = NULL; + + retval = fw_setup_class_device(&class_dev, name, device); + if (retval) + goto out; + + fw_priv = class_get_devdata(class_dev); + + if (loading_timeout) { + fw_priv->timeout.expires = jiffies + loading_timeout * HZ; + add_timer(&fw_priv->timeout); + } + + wait_for_completion(&fw_priv->completion); + + del_timer(&fw_priv->timeout); + fw_remove_class_device(class_dev); + + if (fw_priv->fw->size && !fw_priv->abort) { + *firmware = fw_priv->fw; + } else { + retval = -ENOENT; + kfree(fw_priv->fw->data); + kfree(fw_priv->fw); + } + kfree(fw_priv); +out: + return retval; +} + +/** + * release_firmware: - release the resource associated with a firmware image + **/ +void +release_firmware(const struct firmware *fw) +{ + if (fw) { + kfree(fw->data); + kfree(fw); + } +} + +/** + * register_firmware: - provide a firmware image for later usage + * + * Description: + * Make sure that @data will be available by requesting firmware @name. + * + * Note: This will not be possible until some kind of persistence + * is available. + **/ +void +register_firmware(const char *name, const u8 *data, size_t size) +{ + /* This is meaningless without firmware caching, so until we + * decide if firmware caching is reasonable just leave it as a + * noop */ +} + +/* Async support */ +struct firmware_work { + struct work_struct work; + struct module *module; + const char *name; + struct device *device; + void *context; + void (*cont)(const struct firmware *fw, void *context); +}; + +static void +request_firmware_work_func(void *arg) +{ + struct firmware_work *fw_work = arg; + const struct firmware *fw; + if (!arg) + return; + request_firmware(&fw, fw_work->name, fw_work->device); + fw_work->cont(fw, fw_work->context); + release_firmware(fw); + module_put(fw_work->module); + kfree(fw_work); +} + +/** + * request_firmware_nowait: + * + * Description: + * Asynchronous variant of request_firmware() for contexts where + * it is not possible to sleep. + * + * @cont will be called asynchronously when the firmware request is over. + * + * @context will be passed over to @cont. + * + * @fw may be %NULL if firmware request fails. + * + **/ +int +request_firmware_nowait( + struct module *module, + const char *name, struct device *device, void *context, + void (*cont)(const struct firmware *fw, void *context)) +{ + struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work), + GFP_ATOMIC); + if (!fw_work) + return -ENOMEM; + if (!try_module_get(module)) { + kfree(fw_work); + return -EFAULT; + } + + *fw_work = (struct firmware_work) { + .module = module, + .name = name, + .device = device, + .context = context, + .cont = cont, + }; + INIT_WORK(&fw_work->work, request_firmware_work_func, fw_work); + + schedule_work(&fw_work->work); + return 0; +} + +static int __init +firmware_class_init(void) +{ + int error; + error = class_register(&firmware_class); + if (error) { + printk(KERN_ERR "%s: class_register failed\n", __FUNCTION__); + } + error = class_create_file(&firmware_class, &class_attr_timeout); + if (error) { + printk(KERN_ERR "%s: class_create_file failed\n", + __FUNCTION__); + class_unregister(&firmware_class); + } + return error; + +} +static void __exit +firmware_class_exit(void) +{ + class_remove_file(&firmware_class, &class_attr_timeout); + class_unregister(&firmware_class); +} + +module_init(firmware_class_init); +module_exit(firmware_class_exit); + +EXPORT_SYMBOL(release_firmware); +EXPORT_SYMBOL(request_firmware); +EXPORT_SYMBOL(request_firmware_nowait); +EXPORT_SYMBOL(register_firmware); +EXPORT_SYMBOL(firmware_class); diff --git a/include/linux/firmware.h b/include/linux/firmware.h new file mode 100644 index 000000000000..0378527ce4b6 --- /dev/null +++ b/include/linux/firmware.h @@ -0,0 +1,20 @@ +#ifndef _LINUX_FIRMWARE_H +#define _LINUX_FIRMWARE_H +#include +#include +#define FIRMWARE_NAME_MAX 30 +struct firmware { + size_t size; + u8 *data; +}; +int request_firmware(const struct firmware **fw, const char *name, + struct device *device); +int request_firmware_nowait( + struct module *module, + const char *name, struct device *device, void *context, + void (*cont)(const struct firmware *fw, void *context)); +/* Maybe 'device' should be 'struct device *' */ + +void release_firmware(const struct firmware *fw); +void register_firmware(const char *name, const u8 *data, size_t size); +#endif diff --git a/lib/Kconfig b/lib/Kconfig index 1203bd92136c..a7c8214bf32e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -26,5 +26,7 @@ config ZLIB_DEFLATE (PPP_DEFLATE=m || JFFS2_FS=m || CRYPTO_DEFLATE=m) default y if PPP_DEFLATE=y || JFFS2_FS=y || CRYPTO_DEFLATE=y +source "drivers/base/Kconfig.lib" + endmenu -- cgit v1.2.3 From 58aae7d9937f5b0a815bc6117a3c592ebc209a7d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 18 Jun 2003 19:44:14 -0700 Subject: DRIVER: firmware class build cleanups Made variables static that were global, and cleaned up some sparse warnings. --- drivers/base/firmware_class.c | 13 +++++++------ include/linux/firmware.h | 1 - 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 15c8ab792599..705c4c00b69c 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -56,13 +56,13 @@ firmware_timeout_store(struct class *class, const char *buf, size_t count) return count; } -CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); +static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); static void fw_class_dev_release(struct class_device *class_dev); int firmware_class_hotplug(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size); -struct class firmware_class = { +static struct class firmware_class = { .name = "firmware", .hotplug = firmware_class_hotplug, .release = fw_class_dev_release, @@ -132,8 +132,8 @@ firmware_loading_store(struct class_device *class_dev, return count; } -CLASS_DEVICE_ATTR(loading, 0644, - firmware_loading_show, firmware_loading_store); +static CLASS_DEVICE_ATTR(loading, 0644, + firmware_loading_show, firmware_loading_store); static ssize_t firmware_data_read(struct kobject *kobj, @@ -224,10 +224,11 @@ firmware_class_timeout(u_long data) wmb(); complete(&fw_priv->completion); } + static inline void fw_setup_class_device_id(struct class_device *class_dev, struct device *dev) { -#warning we should watch out for name collisions + /* XXX warning we should watch out for name collisions */ strncpy(class_dev->class_id, dev->bus_id, BUS_ID_SIZE); class_dev->class_id[BUS_ID_SIZE - 1] = '\0'; } @@ -252,7 +253,7 @@ fw_setup_class_device(struct class_device **class_dev_p, memcpy(&fw_priv->attr_data, &firmware_attr_data_tmpl, sizeof (firmware_attr_data_tmpl)); - strncpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX); + strncpy(&fw_priv->fw_id[0], fw_name, FIRMWARE_NAME_MAX); fw_priv->fw_id[FIRMWARE_NAME_MAX - 1] = '\0'; fw_setup_class_device_id(class_dev, device); diff --git a/include/linux/firmware.h b/include/linux/firmware.h index 0378527ce4b6..93dd77eb7869 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h @@ -13,7 +13,6 @@ int request_firmware_nowait( struct module *module, const char *name, struct device *device, void *context, void (*cont)(const struct firmware *fw, void *context)); -/* Maybe 'device' should be 'struct device *' */ void release_firmware(const struct firmware *fw); void register_firmware(const char *name, const u8 *data, size_t size); -- cgit v1.2.3 From 28a7c0306e3060a1a9da3745397ace780aa1496f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 18 Jun 2003 22:38:19 -0700 Subject: [NET]: Add prefetch to skb_queue_walk. --- include/linux/skbuff.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 3398f0a283db..9e9516b331a3 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1154,9 +1154,9 @@ static inline void kunmap_skb_frag(void *vaddr) } #define skb_queue_walk(queue, skb) \ - for (skb = (queue)->next; \ + for (skb = (queue)->next, prefetch(skb->next); \ (skb != (struct sk_buff *)(queue)); \ - skb = skb->next) + skb = skb->next, prefetch(skb->next)) extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, -- cgit v1.2.3 From 9c4d893855a6e27e43f49bd16b7b87cdd187ddad Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 18 Jun 2003 22:41:06 -0700 Subject: [NET]: Use unlikely and BUG_ON in SKB assertions. --- include/linux/skbuff.h | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 9e9516b331a3..57af37850a4e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -803,12 +803,9 @@ static inline void skb_fill_page_desc(struct sk_buff *skb, int i, struct page *p skb_shinfo(skb)->nr_frags = i+1; } -#define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) \ - BUG(); } while (0) -#define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) \ - BUG(); } while (0) -#define SKB_LINEAR_ASSERT(skb) do { if (skb_is_nonlinear(skb)) \ - BUG(); } while (0) +#define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags) +#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_shinfo(skb)->frag_list) +#define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb)) /* * Add data to an sk_buff @@ -837,7 +834,7 @@ static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) SKB_LINEAR_ASSERT(skb); skb->tail += len; skb->len += len; - if (skb->tail>skb->end) + if (unlikely(skb->tail>skb->end)) skb_over_panic(skb, len, current_text_addr()); return tmp; } @@ -862,7 +859,7 @@ static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len) { skb->data -= len; skb->len += len; - if (skb->datahead) + if (unlikely(skb->datahead)) skb_under_panic(skb, len, current_text_addr()); return skb->data; } @@ -870,8 +867,7 @@ static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len) static inline char *__skb_pull(struct sk_buff *skb, unsigned int len) { skb->len -= len; - if (skb->len < skb->data_len) - BUG(); + BUG_ON(skb->len < skb->data_len); return skb->data += len; } @@ -1137,8 +1133,7 @@ static inline int __deprecated skb_linearize(struct sk_buff *skb, int gfp) static inline void *kmap_skb_frag(const skb_frag_t *frag) { #ifdef CONFIG_HIGHMEM - if (in_irq()) - BUG(); + BUG_ON(in_irq()); local_bh_disable(); #endif -- cgit v1.2.3 From 60af0ada76ea8f4f8c6bb4a4ac855153525ac9b9 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Wed, 18 Jun 2003 22:42:20 -0700 Subject: [NET]: Let arptables see bridged arp traffic. --- include/linux/netfilter_arp.h | 3 +- net/bridge/br_netfilter.c | 51 +++++++++++++++++---------- net/ipv4/netfilter/arptable_filter.c | 67 ++++++++++++++++++++++++------------ 3 files changed, 80 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_arp.h b/include/linux/netfilter_arp.h index 4f460b3b0cba..a3f8977f7f12 100644 --- a/include/linux/netfilter_arp.h +++ b/include/linux/netfilter_arp.h @@ -14,6 +14,7 @@ /* ARP Hooks */ #define NF_ARP_IN 0 #define NF_ARP_OUT 1 -#define NF_ARP_NUMHOOKS 2 +#define NF_ARP_FORWARD 2 +#define NF_ARP_NUMHOOKS 3 #endif /* __LINUX_ARP_NETFILTER_H */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 607a63581988..f2a9517511e1 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -304,31 +305,36 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb, return NF_ACCEPT; } - /* PF_BRIDGE/FORWARD *************************************************/ static int br_nf_forward_finish(struct sk_buff *skb) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; + struct net_device *in; #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug ^= (1 << NF_BR_FORWARD); #endif - if (nf_bridge->mask & BRNF_PKT_TYPE) { - skb->pkt_type = PACKET_OTHERHOST; - nf_bridge->mask ^= BRNF_PKT_TYPE; + if (skb->protocol == __constant_htons(ETH_P_IP)) { + in = nf_bridge->physindev; + if (nf_bridge->mask & BRNF_PKT_TYPE) { + skb->pkt_type = PACKET_OTHERHOST; + nf_bridge->mask ^= BRNF_PKT_TYPE; + } + } else { + in = *((struct net_device **)(skb->cb)); } - NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, nf_bridge->physindev, + NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in, skb->dev, br_forward_finish, 1); - return 0; } -/* This is the 'purely bridged' case. We pass the packet to +/* This is the 'purely bridged' case. For IP, we pass the packet to * netfilter with indev and outdev set to the bridge device, * but we are still able to filter on the 'real' indev/outdev - * because of the ipt_physdev.c module. + * because of the ipt_physdev.c module. For ARP, indev and outdev are the + * bridge ports. */ static unsigned int br_nf_forward(unsigned int hook, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, @@ -337,24 +343,33 @@ static unsigned int br_nf_forward(unsigned int hook, struct sk_buff **pskb, struct sk_buff *skb = *pskb; struct nf_bridge_info *nf_bridge; - if (skb->protocol != __constant_htons(ETH_P_IP)) + if (skb->protocol != __constant_htons(ETH_P_IP) && + skb->protocol != __constant_htons(ETH_P_ARP)) return NF_ACCEPT; #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug ^= (1 << NF_BR_FORWARD); #endif + if (skb->protocol == __constant_htons(ETH_P_IP)) { + nf_bridge = skb->nf_bridge; + if (skb->pkt_type == PACKET_OTHERHOST) { + skb->pkt_type = PACKET_HOST; + nf_bridge->mask |= BRNF_PKT_TYPE; + } - nf_bridge = skb->nf_bridge; - if (skb->pkt_type == PACKET_OTHERHOST) { - skb->pkt_type = PACKET_HOST; - nf_bridge->mask |= BRNF_PKT_TYPE; - } + /* The physdev module checks on this */ + nf_bridge->mask |= BRNF_BRIDGED; + nf_bridge->physoutdev = skb->dev; - nf_bridge->mask |= BRNF_BRIDGED; /* The physdev module checks on this */ - nf_bridge->physoutdev = skb->dev; + NF_HOOK(PF_INET, NF_IP_FORWARD, skb, bridge_parent(in), + bridge_parent(out), br_nf_forward_finish); + } else { + struct net_device **d = (struct net_device **)(skb->cb); - NF_HOOK(PF_INET, NF_IP_FORWARD, skb, bridge_parent(nf_bridge->physindev), - bridge_parent(skb->dev), br_nf_forward_finish); + *d = (struct net_device *)in; + NF_HOOK(NF_ARP, NF_ARP_FORWARD, skb, (struct net_device *)in, + (struct net_device *)out, br_nf_forward_finish); + } return NF_STOLEN; } diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 3387279f6908..2404ad53a71f 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -8,7 +8,8 @@ #include #include -#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT)) +#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \ + (1 << NF_ARP_FORWARD)) /* Standard entry. */ struct arpt_standard @@ -32,15 +33,17 @@ struct arpt_error static struct { struct arpt_replace repl; - struct arpt_standard entries[2]; + struct arpt_standard entries[3]; struct arpt_error term; } initial_table __initdata -= { { "filter", FILTER_VALID_HOOKS, 3, - sizeof(struct arpt_standard) * 2 + sizeof(struct arpt_error), += { { "filter", FILTER_VALID_HOOKS, 4, + sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error), { [NF_ARP_IN] = 0, - [NF_ARP_OUT] = sizeof(struct arpt_standard) }, + [NF_ARP_OUT] = sizeof(struct arpt_standard), + [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), }, { [NF_ARP_IN] = 0, - [NF_ARP_OUT] = sizeof(struct arpt_standard), }, + [NF_ARP_OUT] = sizeof(struct arpt_standard), + [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), }, 0, NULL, { } }, { /* ARP_IN */ @@ -65,6 +68,27 @@ static struct -NF_ACCEPT - 1 } }, /* ARP_OUT */ + { + { + { + { 0 }, { 0 }, { 0 }, { 0 }, + 0, 0, + { { 0, }, { 0, } }, + { { 0, }, { 0, } }, + 0, 0, + 0, 0, + 0, 0, + "", "", { 0 }, { 0 }, + 0, 0 + }, + sizeof(struct arpt_entry), + sizeof(struct arpt_standard), + 0, + { 0, 0 }, { } }, + { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } }, + -NF_ACCEPT - 1 } + }, + /* ARP_FORWARD */ { { { @@ -142,35 +166,34 @@ static struct nf_hook_ops arpt_ops[] = { .owner = THIS_MODULE, .pf = NF_ARP, .hooknum = NF_ARP_OUT, - } + }, + { + .hook = arpt_hook, + .owner = THIS_MODULE, + .pf = NF_ARP, + .hooknum = NF_ARP_FORWARD, + }, }; static int __init init(void) { - int ret; + int ret, i; /* Register table */ ret = arpt_register_table(&packet_filter); if (ret < 0) return ret; - /* Register hooks */ - ret = nf_register_hook(&arpt_ops[0]); - if (ret < 0) - goto cleanup_table; - - ret = nf_register_hook(&arpt_ops[1]); - if (ret < 0) - goto cleanup_hook0; - + for (i = 0; i < ARRAY_SIZE(arpt_ops); i++) + if ((ret = nf_register_hook(&arpt_ops[i])) < 0) + goto cleanup_hooks; return ret; -cleanup_hook0: - nf_unregister_hook(&arpt_ops[0]); +cleanup_hooks: + while (--i >= 0) + nf_unregister_hook(&arpt_ops[i]); -cleanup_table: arpt_unregister_table(&packet_filter); - return ret; } @@ -178,7 +201,7 @@ static void __exit fini(void) { unsigned int i; - for (i = 0; i < sizeof(arpt_ops)/sizeof(struct nf_hook_ops); i++) + for (i = 0; i < ARRAY_SIZE(arpt_ops); i++) nf_unregister_hook(&arpt_ops[i]); arpt_unregister_table(&packet_filter); -- cgit v1.2.3 From 01c541b57be31c5b700845824611b242c5129ccb Mon Sep 17 00:00:00 2001 From: David Mosberger Date: Wed, 18 Jun 2003 23:34:45 -0700 Subject: [PATCH] Add 2 HP PCI ids Trivial addition needed for the hp Itanium machines. --- include/linux/pci_ids.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 9b51d57947f1..5b53ae25dfbe 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -602,6 +602,8 @@ #define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 #define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A #define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B +#define PCI_DEVICE_ID_HP_REO_SBA 0x10f0 +#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1 #define PCI_DEVICE_ID_HP_VISUALIZE_FXE 0x108b #define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223 #define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226 -- cgit v1.2.3 From 3ed5a695e18ded723765e6a85dad11fb3b539ab2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 Jun 2003 00:25:36 -0700 Subject: [NET]: Size hh_cache->hh_data more appropriately. --- drivers/net/myri_sbus.c | 11 ++++++++--- drivers/net/plip.c | 5 ++++- include/linux/netdevice.h | 8 +++++++- net/ethernet/eth.c | 8 ++++++-- net/ipv4/ip_output.c | 5 ++++- net/ipv4/netfilter/ipt_MIRROR.c | 5 ++++- net/ipv6/ip6_output.c | 5 ++++- 7 files changed, 37 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 7f4e64360f15..fdcad85b7cc6 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -766,10 +766,14 @@ static int myri_rebuild_header(struct sk_buff *skb) int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; - unsigned char *pad = (unsigned char *) hh->hh_data; - struct ethhdr *eth = (struct ethhdr *) (pad + MYRI_PAD_LEN); + unsigned char *pad; + struct ethhdr *eth; struct net_device *dev = neigh->dev; + pad = ((unsigned char *) hh->hh_data) + + HH_DATA_OFF(sizeof(*eth) + MYRI_PAD_LEN); + eth = (struct ethhdr *) (pad + MYRI_PAD_LEN); + if (type == __constant_htons(ETH_P_802_3)) return -1; @@ -788,7 +792,8 @@ int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) /* Called by Address Resolution module to notify changes in address. */ void myri_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) { - memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len); + memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), + haddr, dev->addr_len); } static int myri_change_mtu(struct net_device *dev, int new_mtu) diff --git a/drivers/net/plip.c b/drivers/net/plip.c index ae3c088214fd..620b5c4223e5 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -1078,7 +1078,10 @@ int plip_hard_header_cache(struct neighbour *neigh, if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0) { - struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2); + struct ethhdr *eth; + + eth = (struct ethhdr*)(((u8*)hh->hh_data) + + HH_DATA_OFF(sizeof(*eth))); plip_rewrite_address (neigh->dev, eth); } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7bed3d24a2ea..fba9b5ddec1e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -195,8 +195,14 @@ struct hh_cache int hh_len; /* length of header */ int (*hh_output)(struct sk_buff *skb); rwlock_t hh_lock; + /* cached hardware header; allow for machine alignment needs. */ - unsigned long hh_data[16/sizeof(unsigned long)]; +#define HH_DATA_MOD 16 +#define HH_DATA_OFF(__len) \ + (HH_DATA_MOD - ((__len) & (HH_DATA_MOD - 1))) +#define HH_DATA_ALIGN(__len) \ + (((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1)) + unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER)]; }; /* These flag bits are private to the generic network queueing diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 80e2b0379858..bf49e394665f 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -216,9 +216,12 @@ int eth_header_parse(struct sk_buff *skb, unsigned char *haddr) int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; - struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2); + struct ethhdr *eth; struct net_device *dev = neigh->dev; + eth = (struct ethhdr*) + (((u8*)hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); + if (type == __constant_htons(ETH_P_802_3)) return -1; @@ -235,5 +238,6 @@ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) { - memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len); + memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), + haddr, dev->addr_len); } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 765c13b96d64..7a736073666e 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -193,8 +193,11 @@ static inline int ip_finish_output2(struct sk_buff *skb) #endif /*CONFIG_NETFILTER_DEBUG*/ if (hh) { + int hh_alen; + read_lock_bh(&hh->hh_lock); - memcpy(skb->data - 16, hh->hh_data, 16); + hh_alen = HH_DATA_ALIGN(hh->hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); read_unlock_bh(&hh->hh_lock); skb_push(skb, hh->hh_len); return hh->hh_output(skb); diff --git a/net/ipv4/netfilter/ipt_MIRROR.c b/net/ipv4/netfilter/ipt_MIRROR.c index fcd424bd73b8..3f8faff13dc4 100644 --- a/net/ipv4/netfilter/ipt_MIRROR.c +++ b/net/ipv4/netfilter/ipt_MIRROR.c @@ -90,8 +90,11 @@ static void ip_direct_send(struct sk_buff *skb) struct hh_cache *hh = dst->hh; if (hh) { + int hh_alen; + read_lock_bh(&hh->hh_lock); - memcpy(skb->data - 16, hh->hh_data, 16); + hh_alen = HH_DATA_ALIGN(hh->hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); read_unlock_bh(&hh->hh_lock); skb_push(skb, hh->hh_len); hh->hh_output(skb); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9b17cafeab36..0eb4d60f9dac 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -76,8 +76,11 @@ static inline int ip6_output_finish(struct sk_buff *skb) struct hh_cache *hh = dst->hh; if (hh) { + int hh_alen; + read_lock_bh(&hh->hh_lock); - memcpy(skb->data - 16, hh->hh_data, 16); + hh_alen = HH_DATA_ALIGN(hh->hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); read_unlock_bh(&hh->hh_lock); skb_push(skb, hh->hh_len); return hh->hh_output(skb); -- cgit v1.2.3 From 4e359ed50454607415a8ab39ca0a0c7318890aa2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 19 Jun 2003 01:03:04 -0700 Subject: PCI: add locking to the pci device lists. This also creates two new functions, pci_get_device() and pci_get_subsys() which should be used from now on instead of pci_find_device() and pci_find_subsys(). Thanks to Chris Wright and Andrew Morton for help in reviewing these changes. --- drivers/pci/hotplug.c | 34 ++++++++---- drivers/pci/pci.h | 3 + drivers/pci/proc.c | 43 +++++++------- drivers/pci/search.c | 151 ++++++++++++++++++++++++++++++++++++++++++++------ include/linux/pci.h | 11 ++++ 5 files changed, 196 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index e943e451acb7..81e4020be4b9 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -173,6 +173,24 @@ int pci_visit_dev (struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, } EXPORT_SYMBOL(pci_visit_dev); +static void pci_destroy_dev(struct pci_dev *dev) +{ + pci_proc_detach_device(dev); + device_unregister(&dev->dev); + + /* Remove the device from the device lists, and prevent any further + * list accesses from this device */ + spin_lock(&pci_bus_lock); + list_del(&dev->bus_list); + list_del(&dev->global_list); + dev->bus_list.next = dev->bus_list.prev = NULL; + dev->global_list.next = dev->global_list.prev = NULL; + spin_unlock(&pci_bus_lock); + + pci_free_resources(dev); + pci_put_dev(dev); +} + /** * pci_remove_device_safe - remove an unused hotplug device * @dev: the device to remove @@ -186,11 +204,7 @@ int pci_remove_device_safe(struct pci_dev *dev) { if (pci_dev_driver(dev)) return -EBUSY; - device_unregister(&dev->dev); - list_del(&dev->bus_list); - list_del(&dev->global_list); - pci_free_resources(dev); - pci_proc_detach_device(dev); + pci_destroy_dev(dev); return 0; } EXPORT_SYMBOL(pci_remove_device_safe); @@ -237,17 +251,15 @@ void pci_remove_bus_device(struct pci_dev *dev) pci_remove_behind_bridge(dev); pci_proc_detach_bus(b); + spin_lock(&pci_bus_lock); list_del(&b->node); + spin_unlock(&pci_bus_lock); + kfree(b); dev->subordinate = NULL; } - device_unregister(&dev->dev); - list_del(&dev->bus_list); - list_del(&dev->global_list); - pci_free_resources(dev); - pci_proc_detach_device(dev); - pci_put_dev(dev); + pci_destroy_dev(dev); } /** diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 69b2fff6f655..3288e401d914 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -58,3 +58,6 @@ struct pci_visit { extern int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent); + +/* Lock for read/write access to pci device and bus lists */ +extern spinlock_t pci_bus_lock; diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index bb1240f2880a..4bc22bd29cce 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -308,39 +308,45 @@ static struct file_operations proc_bus_pci_operations = { /* iterator */ static void *pci_seq_start(struct seq_file *m, loff_t *pos) { - struct list_head *p = &pci_devices; + struct pci_dev *dev = NULL; loff_t n = *pos; - /* XXX: surely we need some locking for traversing the list? */ + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); while (n--) { - p = p->next; - if (p == &pci_devices) - return NULL; + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + if (dev == NULL) + goto exit; } - return p; +exit: + return dev; } + static void *pci_seq_next(struct seq_file *m, void *v, loff_t *pos) { - struct list_head *p = v; + struct pci_dev *dev = v; + (*pos)++; - return p->next != &pci_devices ? (void *)p->next : NULL; + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + return dev; } + static void pci_seq_stop(struct seq_file *m, void *v) { - /* release whatever locks we need */ + if (v) { + struct pci_dev *dev = v; + pci_put_dev(dev); + } } static int show_device(struct seq_file *m, void *v) { - struct list_head *p = v; - const struct pci_dev *dev; + const struct pci_dev *dev = v; const struct pci_driver *drv; int i; - if (p == &pci_devices) + if (dev == NULL) return 0; - dev = pci_dev_g(p); drv = pci_dev_driver(dev); seq_printf(m, "%02x%02x\t%04x%04x\t%x", dev->bus->number, @@ -455,19 +461,18 @@ int pci_proc_detach_bus(struct pci_bus* bus) */ static int show_dev_config(struct seq_file *m, void *v) { - struct list_head *p = v; - struct pci_dev *dev; + struct pci_dev *dev = v; + struct pci_dev *first_dev; struct pci_driver *drv; u32 class_rev; unsigned char latency, min_gnt, max_lat, *class; int reg; - if (p == &pci_devices) { + first_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); + if (dev == first_dev) seq_puts(m, "PCI devices found:\n"); - return 0; - } + pci_put_dev(first_dev); - dev = pci_dev_g(p); drv = pci_dev_driver(dev); pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index c7b30f9b8a52..604073295ec4 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -1,6 +1,17 @@ +/* + * PCI searching functions. + * + * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, + * David Mosberger-Tang + * Copyright 1997 -- 2000 Martin Mares + * Copyright 2003 -- Greg Kroah-Hartman + */ + #include #include +spinlock_t pci_bus_lock = SPIN_LOCK_UNLOCKED; + static struct pci_bus * pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) { @@ -52,11 +63,15 @@ pci_find_bus(unsigned char busnr) struct pci_bus * pci_find_next_bus(const struct pci_bus *from) { - struct list_head *n = from ? from->node.next : pci_root_buses.next; + struct list_head *n; struct pci_bus *b = NULL; + WARN_ON(irqs_disabled()); + spin_lock(&pci_bus_lock); + n = from ? from->node.next : pci_root_buses.next; if (n != &pci_root_buses) b = pci_bus_b(n); + spin_unlock(&pci_bus_lock); return b; } @@ -97,24 +112,36 @@ pci_find_slot(unsigned int bus, unsigned int devfn) * device structure is returned. Otherwise, %NULL is returned. * A new search is initiated by passing %NULL to the @from argument. * Otherwise if @from is not %NULL, searches continue from next device on the global list. + * + * NOTE: Do not use this function anymore, use pci_get_subsys() instead, as + * the pci device returned by this function can disappear at any moment in + * time. */ struct pci_dev * pci_find_subsys(unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from) { - struct list_head *n = from ? from->global_list.next : pci_devices.next; + struct list_head *n; + struct pci_dev *dev; + + WARN_ON(irqs_disabled()); + spin_lock(&pci_bus_lock); + n = from ? from->global_list.next : pci_devices.next; - while (n != &pci_devices) { - struct pci_dev *dev = pci_dev_g(n); + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && (device == PCI_ANY_ID || dev->device == device) && (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) && (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device)) - return dev; + goto exit; n = n->next; } - return NULL; + dev = NULL; +exit: + spin_unlock(&pci_bus_lock); + return dev; } /** @@ -128,6 +155,10 @@ pci_find_subsys(unsigned int vendor, unsigned int device, * returned. Otherwise, %NULL is returned. * A new search is initiated by passing %NULL to the @from argument. * Otherwise if @from is not %NULL, searches continue from next device on the global list. + * + * NOTE: Do not use this function anymore, use pci_get_device() instead, as + * the pci device returned by this function can disappear at any moment in + * time. */ struct pci_dev * pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) @@ -135,6 +166,77 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev * return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); } +/** + * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids + * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices. If a PCI device is + * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its + * device structure is returned, and the reference count to the device is + * incremented. Otherwise, %NULL is returned. A new search is initiated by + * passing %NULL to the @from argument. Otherwise if @from is not %NULL, + * searches continue from next device on the global list. + * The reference count for @from is always decremented if it is not %NULL. + */ +struct pci_dev * +pci_get_subsys(unsigned int vendor, unsigned int device, + unsigned int ss_vendor, unsigned int ss_device, + struct pci_dev *from) +{ + struct list_head *n; + struct pci_dev *dev; + + WARN_ON(irqs_disabled()); + spin_lock(&pci_bus_lock); + n = from ? from->global_list.next : pci_devices.next; + + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); + if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && + (device == PCI_ANY_ID || dev->device == device) && + (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) && + (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device)) + goto exit; + n = n->next; + } + dev = NULL; +exit: + pci_put_dev(from); + dev = pci_get_dev(dev); + spin_unlock(&pci_bus_lock); + return dev; +} + +/** + * pci_get_device - begin or continue searching for a PCI device by vendor/device id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices. If a PCI device is + * found with a matching @vendor and @device, a pointer to its device structure is + * returned. Otherwise, %NULL is returned. + * A new search is initiated by passing %NULL to the @from argument. + * Otherwise if @from is not %NULL, searches continue from next device on the global list. + * + * Iterates through the list of known PCI devices. If a PCI device is + * found with a matching @vendor and @device, the reference count to the + * device is incremented and a pointer to its device structure is returned. + * Otherwise, %NULL is returned. A new search is initiated by passing %NULL + * to the @from argument. Otherwise if @from is not %NULL, searches continue + * from next device on the global list. The reference count for @from is + * always decremented if it is not %NULL. + */ +struct pci_dev * +pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from) +{ + return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); +} + /** * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id @@ -151,16 +253,24 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev * struct pci_dev * pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from) { - struct list_head *n = from ? from->global_list.prev : pci_devices.prev; + struct list_head *n; + struct pci_dev *dev; - while (n != &pci_devices) { - struct pci_dev *dev = pci_dev_g(n); + WARN_ON(irqs_disabled()); + spin_lock(&pci_bus_lock); + n = from ? from->global_list.prev : pci_devices.prev; + + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && (device == PCI_ANY_ID || dev->device == device)) - return dev; + goto exit; n = n->prev; } - return NULL; + dev = NULL; +exit: + spin_unlock(&pci_bus_lock); + return dev; } @@ -179,15 +289,22 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p struct pci_dev * pci_find_class(unsigned int class, const struct pci_dev *from) { - struct list_head *n = from ? from->global_list.next : pci_devices.next; + struct list_head *n; + struct pci_dev *dev; - while (n != &pci_devices) { - struct pci_dev *dev = pci_dev_g(n); + spin_lock(&pci_bus_lock); + n = from ? from->global_list.next : pci_devices.next; + + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); if (dev->class == class) - return dev; + goto exit; n = n->next; } - return NULL; + dev = NULL; +exit: + spin_unlock(&pci_bus_lock); + return dev; } EXPORT_SYMBOL(pci_find_bus); @@ -196,3 +313,5 @@ EXPORT_SYMBOL(pci_find_device); EXPORT_SYMBOL(pci_find_device_reverse); EXPORT_SYMBOL(pci_find_slot); EXPORT_SYMBOL(pci_find_subsys); +EXPORT_SYMBOL(pci_get_device); +EXPORT_SYMBOL(pci_get_subsys); diff --git a/include/linux/pci.h b/include/linux/pci.h index b5cb05a32c90..92dfe4e29368 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -566,6 +566,10 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); struct pci_bus * pci_find_next_bus(const struct pci_bus *from); +struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from); +struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, + unsigned int ss_vendor, unsigned int ss_device, + struct pci_dev *from); int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val); int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val); int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val); @@ -688,6 +692,13 @@ static inline struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from) { return NULL; } +static inline struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from) +{ return NULL; } + +static inline struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, +unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from) +{ return NULL; } + static inline void pci_set_master(struct pci_dev *dev) { } static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } static inline void pci_disable_device(struct pci_dev *dev) { } -- cgit v1.2.3 From 609230134b34af46b53fc9d9bae4a088b0f054f8 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Thu, 19 Jun 2003 02:02:39 -0700 Subject: [PATCH] PCI: pci_raw_ops patch to fix acpi on ia64 --- arch/i386/pci/common.c | 23 ++++++++++++-- arch/i386/pci/direct.c | 82 +++++++++++++++---------------------------------- arch/i386/pci/fixup.c | 6 ++-- arch/i386/pci/irq.c | 2 +- arch/i386/pci/legacy.c | 6 ++-- arch/i386/pci/numa.c | 26 +++++----------- arch/i386/pci/pcbios.c | 22 +++---------- arch/i386/pci/pci.h | 2 +- arch/ia64/pci/pci.c | 33 +++++++++++--------- drivers/acpi/osl.c | 41 ++++++++----------------- drivers/acpi/pci_root.c | 2 -- include/linux/pci.h | 7 +++++ 12 files changed, 103 insertions(+), 149 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index 6c9fa8f376f7..3e9ed569c3a8 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -23,7 +23,24 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; int pcibios_last_bus = -1; struct pci_bus *pci_root_bus = NULL; -struct pci_ops *pci_root_ops = NULL; +struct pci_raw_ops *raw_pci_ops; + +static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) +{ + return raw_pci_ops->read(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); +} + +static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) +{ + return raw_pci_ops->write(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); +} + +struct pci_ops pci_root_ops = { + .read = pci_read, + .write = pci_write, +}; /* * legacy, numa, and acpi all want to call pcibios_scan_root @@ -115,7 +132,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) printk("PCI: Probing PCI hardware (bus %02x)\n", busnum); - return pci_scan_bus(busnum, pci_root_ops, NULL); + return pci_scan_bus(busnum, &pci_root_ops, NULL); } extern u8 pci_cache_line_size; @@ -124,7 +141,7 @@ static int __init pcibios_init(void) { struct cpuinfo_x86 *c = &boot_cpu_data; - if (!pci_root_ops) { + if (!raw_pci_ops) { printk("PCI: System does not support PCI\n"); return 0; } diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c index 039448ab26b9..b61223fe8438 100644 --- a/arch/i386/pci/direct.c +++ b/arch/i386/pci/direct.c @@ -13,7 +13,7 @@ #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int __pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -41,7 +41,7 @@ static int __pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len return 0; } -static int __pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -71,19 +71,7 @@ static int __pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int le #undef PCI_CONF1_ADDRESS -static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return __pci_conf1_read(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - return __pci_conf1_write(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -struct pci_ops pci_direct_conf1 = { +struct pci_raw_ops pci_direct_conf1 = { .read = pci_conf1_read, .write = pci_conf1_write, }; @@ -95,7 +83,7 @@ struct pci_ops pci_direct_conf1 = { #define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg) -static int __pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -129,7 +117,7 @@ static int __pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len return 0; } -static int __pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -165,19 +153,7 @@ static int __pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int le #undef PCI_CONF2_ADDRESS -static int pci_conf2_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return __pci_conf2_read(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static int pci_conf2_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - return __pci_conf2_write(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static struct pci_ops pci_direct_conf2 = { +static struct pci_raw_ops pci_direct_conf2 = { .read = pci_conf2_read, .write = pci_conf2_write, }; @@ -193,38 +169,30 @@ static struct pci_ops pci_direct_conf2 = { * This should be close to trivial, but it isn't, because there are buggy * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. */ -static int __devinit pci_sanity_check(struct pci_ops *o) +static int __devinit pci_sanity_check(struct pci_raw_ops *o) { u32 x = 0; - int retval = 0; - struct pci_bus *bus; /* Fake bus and device */ - struct pci_dev *dev; + int devfn; if (pci_probe & PCI_NO_CHECKS) return 1; - bus = kmalloc(sizeof(*bus), GFP_ATOMIC); - dev = kmalloc(sizeof(*dev), GFP_ATOMIC); - if (!bus || !dev) { - printk(KERN_ERR "Out of memory in %s\n", __FUNCTION__); - goto exit; + for (devfn = 0; devfn < 0x100; devfn++) { + if (o->read(0, 0, PCI_SLOT(devfn), PCI_FUNC(devfn), + PCI_CLASS_DEVICE, 2, &x)) + continue; + if (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA) + return 1; + + if (o->read(0, 0, PCI_SLOT(devfn), PCI_FUNC(devfn), + PCI_VENDOR_ID, 2, &x)) + continue; + if (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ) + return 1; } - bus->number = 0; - dev->bus = bus; - for(dev->devfn=0; dev->devfn < 0x100; dev->devfn++) - if ((!o->read(bus, dev->devfn, PCI_CLASS_DEVICE, 2, &x) && - (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) || - (!o->read(bus, dev->devfn, PCI_VENDOR_ID, 2, &x) && - (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ))) { - retval = 1; - goto exit; - } DBG("PCI: Sanity check failed\n"); -exit: - kfree(dev); - kfree(bus); - return retval; + return 0; } static int __init pci_direct_init(void) @@ -247,9 +215,9 @@ static int __init pci_direct_init(void) local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 1\n"); if (!request_region(0xCF8, 8, "PCI conf1")) - pci_root_ops = NULL; + raw_pci_ops = NULL; else - pci_root_ops = &pci_direct_conf1; + raw_pci_ops = &pci_direct_conf1; return 0; } outl (tmp, 0xCF8); @@ -267,9 +235,9 @@ static int __init pci_direct_init(void) local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 2\n"); if (!request_region(0xCF8, 4, "PCI conf2")) - pci_root_ops = NULL; + raw_pci_ops = NULL; else - pci_root_ops = &pci_direct_conf2; + raw_pci_ops = &pci_direct_conf2; return 0; } } diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index 7f47b5a5f004..8247ee721490 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c @@ -23,9 +23,9 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) pci_read_config_byte(d, reg++, &subb); DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); if (busno) - pci_scan_bus(busno, pci_root_ops, NULL); /* Bus A */ + pci_scan_bus(busno, &pci_root_ops, NULL); /* Bus A */ if (suba < subb) - pci_scan_bus(suba+1, pci_root_ops, NULL); /* Bus B */ + pci_scan_bus(suba+1, &pci_root_ops, NULL); /* Bus B */ } pcibios_last_bus = -1; } @@ -39,7 +39,7 @@ static void __devinit pci_fixup_i450gx(struct pci_dev *d) u8 busno; pci_read_config_byte(d, 0x4a, &busno); printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno); - pci_scan_bus(busno, pci_root_ops, NULL); + pci_scan_bus(busno, &pci_root_ops, NULL); pcibios_last_bus = -1; } diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index e35674679dfe..53db10c42fea 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -107,7 +107,7 @@ static void __init pirq_peer_trick(void) * It might be a secondary bus, but in this case its parent is already * known (ascending bus order) and therefore pci_scan_bus returns immediately. */ - if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL)) + if (busmap[i] && pci_scan_bus(i, &pci_root_ops, NULL)) printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i); pcibios_last_bus = -1; } diff --git a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c index 7e7f9120df85..29fea7d6ad6c 100644 --- a/arch/i386/pci/legacy.c +++ b/arch/i386/pci/legacy.c @@ -31,14 +31,14 @@ static void __devinit pcibios_fixup_peer_bridges(void) if (pci_bus_exists(&pci_root_buses, n)) continue; bus->number = n; - bus->ops = pci_root_ops; + bus->ops = &pci_root_ops; dev->bus = bus; for (dev->devfn=0; dev->devfn<256; dev->devfn += 8) if (!pci_read_config_word(dev, PCI_VENDOR_ID, &l) && l != 0x0000 && l != 0xffff) { DBG("Found device at %02x:%02x [%04x]\n", n, dev->devfn, l); printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); - pci_scan_bus(n, pci_root_ops, NULL); + pci_scan_bus(n, &pci_root_ops, NULL); break; } } @@ -49,7 +49,7 @@ exit: static int __init pci_legacy_init(void) { - if (!pci_root_ops) { + if (!raw_pci_ops) { printk("PCI: System does not support PCI\n"); return 0; } diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c index 0a184f2c7b57..80a093f06a85 100644 --- a/arch/i386/pci/numa.c +++ b/arch/i386/pci/numa.c @@ -13,7 +13,7 @@ #define PCI_CONF1_MQ_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int __pci_conf1_mq_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int pci_conf1_mq_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -41,7 +41,7 @@ static int __pci_conf1_mq_read (int seg, int bus, int dev, int fn, int reg, int return 0; } -static int __pci_conf1_mq_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int pci_conf1_mq_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -71,19 +71,7 @@ static int __pci_conf1_mq_write (int seg, int bus, int dev, int fn, int reg, int #undef PCI_CONF1_MQ_ADDRESS -static int pci_conf1_mq_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return __pci_conf1_mq_read(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static int pci_conf1_mq_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - return __pci_conf1_mq_write(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static struct pci_ops pci_direct_conf1_mq = { +static struct pci_raw_ops pci_direct_conf1_mq = { .read = pci_conf1_mq_read, .write = pci_conf1_mq_write }; @@ -106,9 +94,9 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) pci_read_config_byte(d, reg++, &subb); DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); if (busno) - pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL); /* Bus A */ + pci_scan_bus(QUADLOCAL2BUS(quad,busno), &pci_root_ops, NULL); /* Bus A */ if (suba < subb) - pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL); /* Bus B */ + pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), &pci_root_ops, NULL); /* Bus B */ } pcibios_last_bus = -1; } @@ -121,7 +109,7 @@ static int __init pci_numa_init(void) { int quad; - pci_root_ops = &pci_direct_conf1_mq; + raw_pci_ops = &pci_direct_conf1_mq; if (pcibios_scanned++) return 0; @@ -132,7 +120,7 @@ static int __init pci_numa_init(void) printk("Scanning PCI bus %d for quad %d\n", QUADLOCAL2BUS(quad,0), quad); pci_scan_bus(QUADLOCAL2BUS(quad,0), - pci_root_ops, NULL); + &pci_root_ops, NULL); } } return 0; diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c index 1a21e2600964..06557dd705e9 100644 --- a/arch/i386/pci/pcbios.c +++ b/arch/i386/pci/pcbios.c @@ -172,7 +172,7 @@ static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short return (int) (ret & 0xff00) >> 8; } -static int __pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long result = 0; unsigned long flags; @@ -227,7 +227,7 @@ static int __pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, return (int)((result & 0xff00) >> 8); } -static int __pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long result = 0; unsigned long flags; @@ -282,24 +282,12 @@ static int __pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len return (int)((result & 0xff00) >> 8); } -static int pci_bios_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return __pci_bios_read(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static int pci_bios_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - return __pci_bios_write(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - /* * Function table for BIOS32 access */ -static struct pci_ops pci_bios_access = { +static struct pci_raw_ops pci_bios_access = { .read = pci_bios_read, .write = pci_bios_write }; @@ -308,7 +296,7 @@ static struct pci_ops pci_bios_access = { * Try to find PCI BIOS. */ -static struct pci_ops * __devinit pci_find_bios(void) +static struct pci_raw_ops * __devinit pci_find_bios(void) { union bios32 *check; unsigned char sum; @@ -484,7 +472,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq) static int __init pci_pcbios_init(void) { if ((pci_probe & PCI_PROBE_BIOS) - && ((pci_root_ops = pci_find_bios()))) { + && ((raw_pci_ops = pci_find_bios()))) { pci_probe |= PCI_BIOS_SORT; pci_bios_present = 1; } diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index 68100f53ecb5..6f3786334bf6 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h @@ -37,7 +37,7 @@ int pcibios_enable_resources(struct pci_dev *, int); extern int pcibios_last_bus; extern struct pci_bus *pci_root_bus; -extern struct pci_ops *pci_root_ops; +extern struct pci_ops pci_root_ops; /* pci-irq.c */ diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 3a5cbbef532e..58ff5b17a038 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -59,7 +59,7 @@ struct pci_fixup pcibios_fixups[1]; static int -__pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { int result = 0; u64 data = 0; @@ -75,7 +75,7 @@ __pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) } static int -__pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { if ((seg > 255) || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) return -EINVAL; @@ -83,28 +83,33 @@ __pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, dev, fn, reg), len, value); } +struct pci_raw_ops pci_sal_ops = { + .read = pci_sal_read, + .write = pci_sal_write +}; + +struct pci_raw_ops *raw_pci_ops = &pci_sal_ops; /* default to SAL */ + static int -pci_sal_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) +pci_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - return __pci_sal_read(pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), - where, size, value); + return raw_pci_ops->read(pci_domain_nr(bus), bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value); } static int -pci_sal_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) +pci_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - return __pci_sal_write(pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), - where, size, value); + return raw_pci_ops->write(pci_domain_nr(bus), bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value); } -struct pci_ops pci_sal_ops = { - .read = pci_sal_read, - .write = pci_sal_write +static struct pci_ops pci_root_ops = { + .read = pci_read, + .write = pci_write, }; -struct pci_ops *pci_root_ops = &pci_sal_ops; /* default to SAL */ - static int __init pci_acpi_init (void) { @@ -307,7 +312,7 @@ pcibios_scan_root (void *handle, int seg, int bus) info.name = name; acpi_walk_resources(handle, METHOD_NAME__CRS, add_window, &info); - return scan_root_bus(bus, pci_root_ops, controller); + return scan_root_bus(bus, &pci_root_ops, controller); out3: kfree(controller->window); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 10a02822ef56..5caecd1a7d7c 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -69,8 +69,6 @@ static int acpi_irq_irq = 0; static OSD_HANDLER acpi_irq_handler = NULL; static void *acpi_irq_context = NULL; -extern struct pci_ops *pci_root_ops; - acpi_status acpi_os_initialize(void) { @@ -79,7 +77,7 @@ acpi_os_initialize(void) * it while walking the namespace (bus 0 and root bridges w/ _BBNs). */ #ifdef CONFIG_ACPI_PCI - if (!pci_root_ops) { + if (!raw_pci_ops) { printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n"); return AE_NULL_ENTRY; } @@ -446,15 +444,9 @@ acpi_os_write_memory( #ifdef CONFIG_ACPI_PCI acpi_status -acpi_os_read_pci_configuration ( - struct acpi_pci_id *pci_id, - u32 reg, - void *value, - u32 width) +acpi_os_read_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, void *value, u32 width) { - int result = 0; - int size = 0; - struct pci_bus bus; + int result, size; if (!value) return AE_BAD_PARAMETER; @@ -470,27 +462,19 @@ acpi_os_read_pci_configuration ( size = 4; break; default: - BUG(); + return AE_ERROR; } - bus.number = pci_id->bus; - result = pci_root_ops->read(&bus, PCI_DEVFN(pci_id->device, - pci_id->function), - reg, size, value); + result = raw_pci_ops->read(pci_id->segment, pci_id->bus, + pci_id->device, pci_id->function, reg, size, value); return (result ? AE_ERROR : AE_OK); } acpi_status -acpi_os_write_pci_configuration ( - struct acpi_pci_id *pci_id, - u32 reg, - acpi_integer value, - u32 width) +acpi_os_write_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, acpi_integer value, u32 width) { - int result = 0; - int size = 0; - struct pci_bus bus; + int result, size; switch (width) { case 8: @@ -503,13 +487,12 @@ acpi_os_write_pci_configuration ( size = 4; break; default: - BUG(); + return AE_ERROR; } - bus.number = pci_id->bus; - result = pci_root_ops->write(&bus, PCI_DEVFN(pci_id->device, - pci_id->function), - reg, size, value); + result = raw_pci_ops->write(pci_id->segment, pci_id->bus, + pci_id->device, pci_id->function, reg, size, value); + return (result ? AE_ERROR : AE_OK); } diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 20a1a9fecc72..ce3d0f9a25bd 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -44,8 +44,6 @@ ACPI_MODULE_NAME ("pci_root") #define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" -extern struct pci_ops *pci_root_ops; - static int acpi_pci_root_add (struct acpi_device *device); static int acpi_pci_root_remove (struct acpi_device *device, int type); diff --git a/include/linux/pci.h b/include/linux/pci.h index 92dfe4e29368..c6f775f3af78 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -486,6 +486,13 @@ struct pci_ops { int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); }; +struct pci_raw_ops { + int (*read)(int dom, int bus, int dev, int func, int reg, int len, u32 *val); + int (*write)(int dom, int bus, int dev, int func, int reg, int len, u32 val); +}; + +extern struct pci_raw_ops *raw_pci_ops; + struct pci_bus_region { unsigned long start; unsigned long end; -- cgit v1.2.3 From 6bc2700336a7ad2d9f87f477413bfcb83e992108 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 19 Jun 2003 02:14:18 -0700 Subject: [PATCH] PCI: rename pci_get_dev() and pci_put_dev() to pci_dev_get() and pci_dev_put() This makes things more consistant with the other get and put functions in the driver code. --- drivers/pci/hotplug.c | 2 +- drivers/pci/pci-driver.c | 20 ++++++++++---------- drivers/pci/probe.c | 2 +- drivers/pci/proc.c | 4 ++-- drivers/pci/search.c | 4 ++-- include/linux/pci.h | 4 ++-- 6 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 81e4020be4b9..3b2ac2a8c080 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -188,7 +188,7 @@ static void pci_destroy_dev(struct pci_dev *dev) spin_unlock(&pci_bus_lock); pci_free_resources(dev); - pci_put_dev(dev); + pci_dev_put(dev); } /** diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index dde99a9f3e3d..d7f601cdde3f 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -138,10 +138,10 @@ static int pci_device_probe(struct device * dev) drv = to_pci_driver(dev->driver); pci_dev = to_pci_dev(dev); - pci_get_dev(pci_dev); + pci_dev_get(pci_dev); error = __pci_device_probe(drv, pci_dev); if (error) - pci_put_dev(pci_dev); + pci_dev_put(pci_dev); return error; } @@ -156,7 +156,7 @@ static int pci_device_remove(struct device * dev) drv->remove(pci_dev); pci_dev->driver = NULL; } - pci_put_dev(pci_dev); + pci_dev_put(pci_dev); return 0; } @@ -448,18 +448,18 @@ static int pci_bus_match(struct device * dev, struct device_driver * drv) } /** - * pci_get_dev - increments the reference count of the pci device structure + * pci_dev_get - increments the reference count of the pci device structure * @dev: the device being referenced * * Each live reference to a device should be refcounted. * * Drivers for PCI devices should normally record such references in * their probe() methods, when they bind to a device, and release - * them by calling pci_put_dev(), in their disconnect() methods. + * them by calling pci_dev_put(), in their disconnect() methods. * * A pointer to the device with the incremented reference counter is returned. */ -struct pci_dev *pci_get_dev (struct pci_dev *dev) +struct pci_dev *pci_dev_get(struct pci_dev *dev) { struct device *tmp; @@ -474,13 +474,13 @@ struct pci_dev *pci_get_dev (struct pci_dev *dev) } /** - * pci_put_dev - release a use of the pci device structure + * pci_dev_put - release a use of the pci device structure * @dev: device that's been disconnected * * Must be called when a user of a device is finished with it. When the last * user of the device calls this function, the memory of the device is freed. */ -void pci_put_dev(struct pci_dev *dev) +void pci_dev_put(struct pci_dev *dev) { if (dev) put_device(&dev->dev); @@ -504,5 +504,5 @@ EXPORT_SYMBOL(pci_register_driver); EXPORT_SYMBOL(pci_unregister_driver); EXPORT_SYMBOL(pci_dev_driver); EXPORT_SYMBOL(pci_bus_type); -EXPORT_SYMBOL(pci_get_dev); -EXPORT_SYMBOL(pci_put_dev); +EXPORT_SYMBOL(pci_dev_get); +EXPORT_SYMBOL(pci_dev_put); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 42f8a6d92228..ee71590f89ca 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -524,7 +524,7 @@ pci_scan_device(struct pci_bus *bus, int devfn) } device_initialize(&dev->dev); dev->dev.release = pci_release_dev; - pci_get_dev(dev); + pci_dev_get(dev); pci_name_device(dev); diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 4bc22bd29cce..95522e71f61e 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -334,7 +334,7 @@ static void pci_seq_stop(struct seq_file *m, void *v) { if (v) { struct pci_dev *dev = v; - pci_put_dev(dev); + pci_dev_put(dev); } } @@ -471,7 +471,7 @@ static int show_dev_config(struct seq_file *m, void *v) first_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); if (dev == first_dev) seq_puts(m, "PCI devices found:\n"); - pci_put_dev(first_dev); + pci_dev_put(first_dev); drv = pci_dev_driver(dev); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 604073295ec4..85c74126ee6a 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -205,8 +205,8 @@ pci_get_subsys(unsigned int vendor, unsigned int device, } dev = NULL; exit: - pci_put_dev(from); - dev = pci_get_dev(dev); + pci_dev_put(from); + dev = pci_dev_get(dev); spin_unlock(&pci_bus_lock); return dev; } diff --git a/include/linux/pci.h b/include/linux/pci.h index c6f775f3af78..87ad2d6fd1e7 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -556,8 +556,8 @@ char *pci_class_name(u32 class); void pci_read_bridge_bases(struct pci_bus *child); struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res); int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge); -extern struct pci_dev *pci_get_dev(struct pci_dev *dev); -extern void pci_put_dev(struct pci_dev *dev); +extern struct pci_dev *pci_dev_get(struct pci_dev *dev); +extern void pci_dev_put(struct pci_dev *dev); extern void pci_remove_bus_device(struct pci_dev *dev); -- cgit v1.2.3 From b7245e829caee36e0a45923d2d081ed85a2a779c Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Thu, 19 Jun 2003 22:31:01 -0700 Subject: [PATCH] reimplement pci proc name Hi Greg. Ivan's not happy with the solution I came up with for naming /proc/bus/pci and Anton would prefer something slightly different too, so I abstracted the name out so each architecture can do its own thing. This is against 2.5.72 so won't apply cleanly to your tree (it applies to bitkeeper as of a few minutes ago with only minor offsets). I've implemented the original name for non-PCI-domain machines; done what ia64 and alpha need, respectively (assuming I didn't misunderstand Ivan), and plopped in the Old Way of doing things for Sparc64, PPC and PPC64. Maintainers may alter this to whatever degree of complexity they wish. --- drivers/pci/proc.c | 3 ++- include/asm-alpha/pci.h | 12 ++++++++++++ include/asm-ia64/pci.h | 10 ++++++++++ include/asm-ppc/pci.h | 7 +++++++ include/asm-ppc64/pci.h | 7 +++++++ include/asm-sparc64/pci.h | 7 +++++++ include/linux/pci.h | 5 +++++ 7 files changed, 50 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 6607a3b7ce2f..44d859888d5b 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -389,7 +389,8 @@ int pci_proc_attach_device(struct pci_dev *dev) return -EACCES; if (!(de = bus->procdir)) { - sprintf(name, "%02x", bus->number); + if (!pci_name_bus(name, bus)) + return -EEXIST; de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir); if (!de) return -ENOMEM; diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h index d23b1f5db70c..34d0376dc322 100644 --- a/include/asm-alpha/pci.h +++ b/include/asm-alpha/pci.h @@ -194,6 +194,18 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index +/* Bus number == domain number until we get above 256 busses */ +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + int domain = pci_domain_nr(bus) + if (domain < 256) { + sprintf(name, "%02x", domain); + } else { + sprintf(name, "%04x:%02x", domain, bus->number); + } + return 0; +} + #endif /* __KERNEL__ */ /* Values for the `which' argument to sys_pciconfig_iobase. */ diff --git a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h index 13e56cfe1e3c..129436b9e730 100644 --- a/include/asm-ia64/pci.h +++ b/include/asm-ia64/pci.h @@ -102,6 +102,16 @@ struct pci_controller { #define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata) #define pci_domain_nr(busdev) (PCI_CONTROLLER(busdev)->segment) +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + if (pci_domain_nr(bus) == 0) { + sprintf(name, "%02x", bus->number); + } else { + sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number); + } + return 0; +} + /* generic pci stuff */ #include diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h index ae9f2d0d8a4f..0f535e374c97 100644 --- a/include/asm-ppc/pci.h +++ b/include/asm-ppc/pci.h @@ -269,6 +269,13 @@ pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, /* Return the index of the PCI controller for device PDEV. */ #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index +/* Set the name of the bus as it appears in /proc/bus/pci */ +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + sprintf(name, "%02x", bus->number); + return 0; +} + /* Map a range of PCI memory or I/O space for a device into user space */ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h index 12c74914bc5d..289683028031 100644 --- a/include/asm-ppc64/pci.h +++ b/include/asm-ppc64/pci.h @@ -88,6 +88,13 @@ static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) extern int pci_domain_nr(struct pci_bus *bus); +/* Set the name of the bus as it appears in /proc/bus/pci */ +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + sprintf(name, "%02x", bus->number); + return 0; +} + struct vm_area_struct; /* Map a range of PCI memory or I/O space for a device into user space */ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma, diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h index 440e7ac0c934..c276200453a3 100644 --- a/include/asm-sparc64/pci.h +++ b/include/asm-sparc64/pci.h @@ -191,6 +191,13 @@ pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, extern int pci_domain_nr(struct pci_bus *bus); +/* Set the name of the bus as it appears in /proc/bus/pci */ +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + sprintf(name, "%02x", bus->number); + return 0; +} + /* Platform support for /proc/bus/pci/X/Y mmap()s. */ #define HAVE_PCI_MMAP diff --git a/include/linux/pci.h b/include/linux/pci.h index 87ad2d6fd1e7..0a2ecb5fd9e7 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -768,6 +768,11 @@ static inline int pci_module_init(struct pci_driver *drv) */ #ifndef CONFIG_PCI_DOMAINS static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + sprintf(name, "%02x", bus->number); + return 0; +} #endif #endif /* !CONFIG_PCI */ -- cgit v1.2.3 From e6d3a689b294a0f7bb5532c762cd261a168b8a0d Mon Sep 17 00:00:00 2001 From: Lionel Bouton Date: Fri, 20 Jun 2003 03:44:03 -0700 Subject: [PATCH] Enhanced SiS96x support This is an update for the SiS IDE driver. This is a 99% Vojtech work : - Independant southbridge detection (no need to add current and future MuTIOL northbridge PCI ids knowledge to the driver), - Lots of code cleanup, - Debug code removed (unused for a while, I will maintain it in my tree if needed), I changed some things: - the new config_xfer_rate is commented out until ide_find_best_mode is patched for bad drive handling (until then I reverted to the old one using the config_drive_xfer_rate helper function). --- drivers/ide/pci/sis5513.c | 464 +++++++++++++++++----------------------------- include/linux/pci_ids.h | 5 + 2 files changed, 177 insertions(+), 292 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 5b7d079bf96a..3f2405966a15 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -1,8 +1,9 @@ /* - * linux/drivers/ide/pci/sis5513.c Version 0.14ac Sept 11, 2002 + * linux/drivers/ide/pci/sis5513.c Version 0.16ac+vp Jun 18, 2003 * * Copyright (C) 1999-2000 Andre Hedrick * Copyright (C) 2002 Lionel Bouton , Maintainer + * Copyright (C) 2003 Vojtech Pavlik * May be copied or modified under the terms of the GNU General Public License * * @@ -14,31 +15,33 @@ * for checking code correctness, providing patches. * * - * Original tests and design on the SiS620/5513 chipset. - * ATA100 tests and design on the SiS735/5513 chipset. + * Original tests and design on the SiS620 chipset. + * ATA100 tests and design on the SiS735 chipset. * ATA16/33 support from specs * ATA133 support for SiS961/962 by L.C. Chang + * ATA133 961/962/963 fixes by Vojtech Pavlik * * Documentation: - * SiS chipset documentation available under NDA to companies not - * individuals only. + * SiS chipset documentation available under NDA to companies only + * (not to individuals). */ /* - * Notes/Special cases: - * - SiS5513 derivatives usually have the same PCI IDE register layout when - * supporting the same UDMA modes. - * - There are exceptions : - * . SiS730 and SiS550 use the same layout than ATA_66 chipsets but support - * ATA_100 - * . ATA_133 capable chipsets mark a shift in SiS chipset designs : previously - * south and northbridge were integrated, making IDE (a southbridge function) - * capabilities easily deduced from the northbridge PCI id. With ATA_133, - * chipsets started to be split in the usual north/south bridges chips - * -> the driver needs to detect the correct southbridge when faced to newest - * northbridges. - * . On ATA133 capable chipsets when bit 30 of dword at 0x54 is 1 the - * configuration space is moved from 0x40 to 0x70. + * The original SiS5513 comes from a SiS5511/55112/5513 chipset. The original + * SiS5513 was also used in the SiS5596/5513 chipset. Thus if we see a SiS5511 + * or SiS5596, we can assume we see the first MWDMA-16 capable SiS5513 chip. + * + * Later SiS chipsets integrated the 5513 functionality into the NorthBridge, + * starting with SiS5571 and up to SiS745. The PCI ID didn't change, though. We + * can figure out that we have a more modern and more capable 5513 by looking + * for the respective NorthBridge IDs. + * + * Even later (96x family) SiS chipsets use the MuTIOL link and place the 5513 + * into the SouthBrige. Here we cannot rely on looking up the NorthBridge PCI + * ID, while the now ATA-133 capable 5513 still has the same PCI ID. + * Fortunately the 5513 can be 'unmasked' by fiddling with some config space + * bits, changing its device id to the true one - 5517 for 961 and 5518 for + * 962/963. */ #include @@ -57,94 +60,23 @@ #include #include -#include #include +#include "ide-timing.h" #include "ide_modes.h" #include "sis5513.h" -/* When DEBUG is defined it outputs initial PCI config register - values and changes made to them by the driver */ -// #define DEBUG -/* When BROKEN_LEVEL is defined it limits the DMA mode - at boot time to its value */ -// #define BROKEN_LEVEL XFER_SW_DMA_0 - -/* Miscellaneous flags */ -#define SIS5513_LATENCY 0x01 - /* registers layout and init values are chipset family dependant */ -/* 1/ define families */ -#define ATA_00 0x00 + #define ATA_16 0x01 #define ATA_33 0x02 #define ATA_66 0x03 -#define ATA_100a 0x04 // SiS730 is ATA100 with ATA66 layout +#define ATA_100a 0x04 // SiS730/SiS550 is ATA100 with ATA66 layout #define ATA_100 0x05 #define ATA_133a 0x06 // SiS961b with 133 support -#define ATA_133 0x07 // SiS962 -/* 2/ variable holding the controller chipset family value */ -static u8 chipset_family; - - -/* - * Debug code: following IDE config registers' changes - */ -#ifdef DEBUG -/* Copy of IDE Config registers fewer will be used - * Some odd chipsets hang if unused registers are accessed - * -> We only access them in #DEBUG code (then we'll see if SiS did - * it right from day one) */ -static u8 ide_regs_copy[0xff]; - -/* Read config registers, print differences from previous read */ -static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) { - int i; - u8 reg_val; - u8 changed=0; - - printk("SIS5513: %s, changed registers:\n", info); - for(i=0; i<=0xff; i++) { - pci_read_config_byte(dev, i, ®_val); - if (reg_val != ide_regs_copy[i]) { - printk("%02x: %02x -> %02x\n", - i, ide_regs_copy[i], reg_val); - ide_regs_copy[i]=reg_val; - changed=1; - } - } - - if (!changed) { - printk("none\n"); - } -} - -/* Load config registers, no printing */ -static void sis5513_load_registers(struct pci_dev* dev) { - int i; - - for(i=0; i<=0xff; i++) { - pci_read_config_byte(dev, i, &(ide_regs_copy[i])); - } -} - -/* Print config space registers a la "lspci -vxxx" */ -static void sis5513_print_registers(struct pci_dev* dev, char* marker) { - int i,j; - - sis5513_load_registers(dev); - printk("SIS5513 %s\n", marker); - - for(i=0; i<=0xf; i++) { - printk("SIS5513 dump: %d" "0:", i); - for(j=0; j<=0xf; j++) { - printk(" %02x", ide_regs_copy[(i<<16)+j]); - } - printk("\n"); - } -} -#endif +#define ATA_133 0x07 // SiS962/963 +static u8 chipset_family; /* * Devices supported @@ -155,42 +87,38 @@ static const struct { u8 chipset_family; u8 flags; } SiSHostChipInfo[] = { - { "SiS752", PCI_DEVICE_ID_SI_752, ATA_133, 0 }, - { "SiS751", PCI_DEVICE_ID_SI_751, ATA_133, 0 }, - { "SiS750", PCI_DEVICE_ID_SI_750, ATA_133, 0 }, - { "SiS748", PCI_DEVICE_ID_SI_748, ATA_133, 0 }, - { "SiS746", PCI_DEVICE_ID_SI_746, ATA_133, 0 }, - { "SiS745", PCI_DEVICE_ID_SI_745, ATA_133, 0 }, - { "SiS740", PCI_DEVICE_ID_SI_740, ATA_133, 0 }, - { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100, SIS5513_LATENCY }, - { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a, SIS5513_LATENCY }, - { "SiS655", PCI_DEVICE_ID_SI_655, ATA_133, 0 }, - { "SiS652", PCI_DEVICE_ID_SI_652, ATA_133, 0 }, - { "SiS651", PCI_DEVICE_ID_SI_651, ATA_133, 0 }, - { "SiS650", PCI_DEVICE_ID_SI_650, ATA_133, 0 }, - { "SiS648", PCI_DEVICE_ID_SI_648, ATA_133, 0 }, - { "SiS646", PCI_DEVICE_ID_SI_646, ATA_133, 0 }, - { "SiS645", PCI_DEVICE_ID_SI_645, ATA_133, 0 }, - { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100, SIS5513_LATENCY }, - { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66, SIS5513_LATENCY }, - { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66, SIS5513_LATENCY }, - { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66, SIS5513_LATENCY }, - { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a, 0}, - { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66, 0}, - { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66, 0}, - { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33, 0}, - { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33, 0}, - { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33, 0}, - { "SiS5591", PCI_DEVICE_ID_SI_5591, ATA_33, 0}, - { "SiS5513", PCI_DEVICE_ID_SI_5513, ATA_16, 0}, - { "SiS5511", PCI_DEVICE_ID_SI_5511, ATA_16, 0}, + { "SiS745", PCI_DEVICE_ID_SI_745, ATA_100 }, + { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100 }, + { "SiS733", PCI_DEVICE_ID_SI_733, ATA_100 }, + { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100 }, + { "SiS633", PCI_DEVICE_ID_SI_633, ATA_100 }, + + { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a }, + { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a }, + + { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66 }, + { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66 }, + { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66 }, + { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66 }, + { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66 }, + + { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33 }, + { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33 }, + { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33 }, + { "SiS5591/2", PCI_DEVICE_ID_SI_5591, ATA_33 }, + { "SiS5582", PCI_DEVICE_ID_SI_5582, ATA_33 }, + { "SiS5581", PCI_DEVICE_ID_SI_5581, ATA_33 }, + + { "SiS5596", PCI_DEVICE_ID_SI_5596, ATA_16 }, + { "SiS5571", PCI_DEVICE_ID_SI_5571, ATA_16 }, + { "SiS551x", PCI_DEVICE_ID_SI_5511, ATA_16 }, }; /* Cycle time bits and values vary across chip dma capabilities These three arrays hold the register layout and the values to set. Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */ -/* {ATA_00, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */ +/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */ static u8 cycle_time_offset[] = {0,0,5,4,4,0,0}; static u8 cycle_time_range[] = {0,0,2,3,3,4,4}; static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { @@ -249,8 +177,6 @@ static u8 rco_time_value[][8] = { {40,12,4,12,5,34,12,5}, }; -static struct pci_dev *host_dev = NULL; - /* * Printing configuration */ @@ -334,6 +260,7 @@ static char* get_drives_info (char *buffer, u8 pos) } pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos, ®dw0); pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos+8, ®dw1); + p += sprintf(p, "Drive %d:\n", pos); } @@ -372,11 +299,12 @@ static char* get_drives_info (char *buffer, u8 pos) p += sprintf(p, "\n"); } - if (chipset_family < ATA_133) { /* else case TODO */ + + if (chipset_family < ATA_133) { /* else case TODO */ + /* Data Active */ p += sprintf(p, " Data Active Time "); switch(chipset_family) { - case ATA_00: case ATA_16: /* confirmed */ case ATA_33: case ATA_66: @@ -387,7 +315,6 @@ static char* get_drives_info (char *buffer, u8 pos) } p += sprintf(p, " \t Data Active Time "); switch(chipset_family) { - case ATA_00: case ATA_16: case ATA_33: case ATA_66: @@ -493,39 +420,16 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count) len = (p - buffer) - offset; *addr = buffer + offset; - + return len > count ? count : len; } #endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */ static u8 sis5513_ratemask (ide_drive_t *drive) { -#if 0 u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 }; u8 mode = rates[chipset_family]; -#else - u8 mode; - switch(chipset_family) { - case ATA_133: - case ATA_133a: - mode = 4; - break; - case ATA_100: - case ATA_100a: - mode = 3; - break; - case ATA_66: - mode = 2; - break; - case ATA_33: - return 1; - case ATA_16: - case ATA_00: - default: - return 0; - } -#endif if (!eighty_ninty_three(drive)) mode = min(mode, (u8)1); return mode; @@ -543,20 +447,12 @@ static void config_drive_art_rwp (ide_drive_t *drive) u8 reg4bh = 0; u8 rw_prefetch = (0x11 << drive->dn); -#ifdef DEBUG - printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn); - sis5513_load_verify_registers(dev, "config_drive_art_rwp start"); -#endif - if (drive->media != ide_disk) return; pci_read_config_byte(dev, 0x4b, ®4bh); if ((reg4bh & rw_prefetch) != rw_prefetch) pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); -#ifdef DEBUG - sis5513_load_verify_registers(dev, "config_drive_art_rwp end"); -#endif } @@ -571,10 +467,6 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; u16 xfer_pio = drive->id->eide_pio_modes; -#ifdef DEBUG - sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start"); -#endif - config_drive_art_rwp(drive); pio = ide_get_best_pio_mode(drive, 255, pio, NULL); @@ -594,12 +486,6 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) timing = (xfer_pio >= pio) ? xfer_pio : pio; -#ifdef DEBUG - printk("SIS5513: config_drive_art_rwp_pio, " - "drive %d, pio %d, timing %d\n", - drive->dn, pio, timing); -#endif - /* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */ drive_pci = 0x40; /* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */ @@ -645,41 +531,24 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) pci_read_config_dword(dev, drive_pci, &test3); test3 &= 0xc0c00fff; if (test3 & 0x08) { - test3 |= (unsigned long)ini_time_value[ATA_133-ATA_00][timing] << 12; - test3 |= (unsigned long)act_time_value[ATA_133-ATA_00][timing] << 16; - test3 |= (unsigned long)rco_time_value[ATA_133-ATA_00][timing] << 24; + test3 |= (unsigned long)ini_time_value[ATA_133][timing] << 12; + test3 |= (unsigned long)act_time_value[ATA_133][timing] << 16; + test3 |= (unsigned long)rco_time_value[ATA_133][timing] << 24; } else { - test3 |= (unsigned long)ini_time_value[ATA_100-ATA_00][timing] << 12; - test3 |= (unsigned long)act_time_value[ATA_100-ATA_00][timing] << 16; - test3 |= (unsigned long)rco_time_value[ATA_100-ATA_00][timing] << 24; + test3 |= (unsigned long)ini_time_value[ATA_100][timing] << 12; + test3 |= (unsigned long)act_time_value[ATA_100][timing] << 16; + test3 |= (unsigned long)rco_time_value[ATA_100][timing] << 24; } pci_write_config_dword(dev, drive_pci, test3); } - -#ifdef DEBUG - sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start"); -#endif } static int config_chipset_for_pio (ide_drive_t *drive, u8 pio) { -#if 0 - config_art_rwp_pio(drive, pio); - return ide_config_drive_speed(drive, (XFER_PIO_0 + pio)); -#else - u8 speed; - - switch(pio) { - case 4: speed = XFER_PIO_4; break; - case 3: speed = XFER_PIO_3; break; - case 2: speed = XFER_PIO_2; break; - case 1: speed = XFER_PIO_1; break; - default: speed = XFER_PIO_0; break; - } - + if (pio == 255) + pio = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; config_art_rwp_pio(drive, pio); - return ide_config_drive_speed(drive, speed); -#endif + return ide_config_drive_speed(drive, XFER_PIO_0 + min_t(u8, pio, 4)); } static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) @@ -690,24 +559,8 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) u8 drive_pci, reg, speed; u32 regdw; -#ifdef DEBUG - sis5513_load_verify_registers(dev, "sis5513_tune_chipset start"); -#endif - -#ifdef BROKEN_LEVEL -#ifdef DEBUG - printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", xferspeed, BROKEN_LEVEL); -#endif - if (xferspeed > BROKEN_LEVEL) xferspeed = BROKEN_LEVEL; -#endif - speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed); -#ifdef DEBUG - printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n", - drive->dn, xferspeed); -#endif - /* See config_art_rwp_pio for drive pci config registers */ drive_pci = 0x40; if (chipset_family >= ATA_133) { @@ -746,14 +599,14 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) regdw &= 0xfffff00f; /* check if ATA133 enable */ if (regdw & 0x08) { - regdw |= (unsigned long)cycle_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 4; - regdw |= (unsigned long)cvs_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 8; + regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4; + regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8; } else { /* if ATA133 disable, we should not set speed above UDMA5 */ if (speed > XFER_UDMA_5) speed = XFER_UDMA_5; - regdw |= (unsigned long)cycle_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 4; - regdw |= (unsigned long)cvs_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 8; + regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4; + regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8; } pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); } else { @@ -763,7 +616,7 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family])) << cycle_time_offset[chipset_family]); /* set reg cycle time bits */ - reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0] + reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0] << cycle_time_offset[chipset_family]; pci_write_config_byte(dev, drive_pci+1, reg); } @@ -782,9 +635,7 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) case XFER_PIO_0: default: return((int) config_chipset_for_pio(drive, 0)); } -#ifdef DEBUG - sis5513_load_verify_registers(dev, "sis5513_tune_chipset end"); -#endif + return ((int) ide_config_drive_speed(drive, speed)); } @@ -863,18 +714,34 @@ static int sis5513_config_xfer_rate (ide_drive_t *drive) return sis5513_config_drive_xfer_rate(drive); } -/* Helper function used at init time - * returns a PCI device revision ID - * (used to detect different IDE controller versions) - */ -static u8 __init devfn_rev(int device, int function) +/* + Future simpler config_xfer_rate : + When ide_find_best_mode is made bad-drive aware + - remove config_drive_xfer_rate and config_chipset_for_dma, + - replace config_xfer_rate with the following + +static int sis5513_config_xfer_rate (ide_drive_t *drive) { - u8 revision; - /* Find device */ - struct pci_dev* dev = pci_find_slot(0,PCI_DEVFN(device,function)); - pci_read_config_byte(dev, PCI_REVISION_ID, &revision); - return revision; + u16 w80 = HWIF(drive)->udma_four; + u16 speed; + + config_drive_art_rwp(drive); + config_art_rwp_pio(drive, 5); + + speed = ide_find_best_mode(drive, + XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | + (chipset_family >= ATA_33 ? XFER_UDMA : 0) | + (w80 && chipset_family >= ATA_66 ? XFER_UDMA_66 : 0) | + (w80 && chipset_family >= ATA_100a ? XFER_UDMA_100 : 0) | + (w80 && chipset_family >= ATA_133a ? XFER_UDMA_133 : 0)); + + sis5513_tune_chipset(drive, speed); + + if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) + return HWIF(drive)->ide_dma_on(drive); + return HWIF(drive)->ide_dma_off_quietly(drive); } +*/ /* Chip detection and general config */ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name) @@ -882,71 +749,86 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char struct pci_dev *host; int i = 0; - /* Find the chip */ - for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) { - host = pci_find_device (PCI_VENDOR_ID_SI, - SiSHostChipInfo[i].host_id, - NULL); + chipset_family = 0; + + for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) { + + host = pci_find_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL); + if (!host) continue; - host_dev = host; chipset_family = SiSHostChipInfo[i].chipset_family; + + /* Special case for SiS630 : 630S/ET is ATA_100a */ + if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) { + u8 hostrev; + pci_read_config_byte(host, PCI_REVISION_ID, &hostrev); + if (hostrev >= 0x30) + chipset_family = ATA_100a; + } - /* check 100/133 chipset family */ - if (chipset_family == ATA_133) { - u32 reg54h; - u16 devid; - pci_read_config_dword(dev, 0x54, ®54h); - /* SiS962 and above report 0x5518 dev id if high bit is cleared */ - pci_write_config_dword(dev, 0x54, (reg54h & 0x7fffffff)); - pci_read_config_word(dev, 0x02, &devid); - /* restore register 0x54 */ - pci_write_config_dword(dev, 0x54, reg54h); - - /* devid 5518 here means SiS962 or later - which supports ATA133. - These are refered by chipset_family = ATA133 - */ - if (devid != 0x5518) { - u8 reg49h; - /* SiS961 family */ - pci_read_config_byte(dev, 0x49, ®49h); - /* check isa bridge device rev id */ - if (((devfn_rev(2,0) & 0xff) == 0x10) && (reg49h & 0x80)) - chipset_family = ATA_133a; - else - chipset_family = ATA_100; + printk(KERN_INFO "SIS5513: %s %s controller\n", + SiSHostChipInfo[i].name, chipset_capability[chipset_family]); + } + + if (!chipset_family) { /* Belongs to pci-quirks */ + + u32 idemisc; + u16 trueid; + + /* Disable ID masking and register remapping */ + pci_read_config_dword(dev, 0x54, &idemisc); + pci_write_config_dword(dev, 0x54, (idemisc & 0x7fffffff)); + pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); + pci_write_config_dword(dev, 0x54, idemisc); + + if (trueid == 0x5518) { + printk(KERN_INFO "SIS5513: SiS 962/963 MuTIOL IDE UDMA133 controller\n"); + chipset_family = ATA_133; } - } - printk(SiSHostChipInfo[i].name); - printk(" %s controller", chipset_capability[chipset_family]); - printk("\n"); + } -#ifdef DEBUG - sis5513_print_registers(dev, "pci_init_sis5513 start"); -#endif + if (!chipset_family) { /* Belongs to pci-quirks */ - if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) { - u8 latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency); - } + struct pci_dev *lpc_bridge; + u16 trueid; + u8 prefctl; + u8 idecfg; + u8 sbrev; - /* Special case for SiS630 : 630S/ET is ATA_100a */ - if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) { - /* check host device rev id */ - if (devfn_rev(0,0) >= 0x30) { - chipset_family = ATA_100a; + pci_read_config_byte(dev, 0x4a, &idecfg); + pci_write_config_byte(dev, 0x4a, idecfg | 0x10); + pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); + pci_write_config_byte(dev, 0x4a, idecfg); + + if (trueid == 0x5517) { /* SiS 961/961B */ + + lpc_bridge = pci_find_slot(0x00, 0x10); /* Bus 0, Dev 2, Fn 0 */ + pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev); + pci_read_config_byte(dev, 0x49, &prefctl); + + if (sbrev == 0x10 && (prefctl & 0x80)) { + printk(KERN_INFO "SIS5513: SiS 961B MuTIOL IDE UDMA133 controller\n"); + chipset_family = ATA_133a; + } else { + printk(KERN_INFO "SIS5513: SiS 961 MuTIOL IDE UDMA100 controller\n"); + chipset_family = ATA_100; + } } - } } + if (!chipset_family) + return -1; + /* Make general config ops here 1/ tell IDE channels to operate in Compatibility mode only 2/ tell old chips to allow per drive IDE timings */ - if (host_dev) { + + { u8 reg; u16 regw; + switch(chipset_family) { case ATA_133: /* SiS962 operation mode */ @@ -959,6 +841,8 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char break; case ATA_133a: case ATA_100: + /* Fixup latency */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80); /* Set compatibility bit */ pci_read_config_byte(dev, 0x49, ®); if (!(reg & 0x01)) { @@ -967,6 +851,9 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char break; case ATA_100a: case ATA_66: + /* Fixup latency */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); + /* On ATA_66 chips the bit was elsewhere */ pci_read_config_byte(dev, 0x52, ®); if (!(reg & 0x04)) { @@ -987,8 +874,6 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char pci_write_config_byte(dev, 0x52, reg|0x08); } break; - case ATA_00: - default: break; } #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) @@ -999,9 +884,7 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char } #endif } -#ifdef DEBUG - sis5513_load_verify_registers(dev, "pci_init_sis5513 end"); -#endif + return 0; } @@ -1044,7 +927,7 @@ static void __init init_hwif_sis5513 (ide_hwif_t *hwif) hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; - if (!host_dev) + if (!chipset_family) return; if (!(hwif->udma_four)) @@ -1102,19 +985,16 @@ static void sis5513_ide_exit(void) module_init(sis5513_ide_init); module_exit(sis5513_ide_exit); -MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick"); +MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik"); MODULE_DESCRIPTION("PCI driver module for SIS IDE"); MODULE_LICENSE("GPL"); /* * TODO: - * - Get ridden of SisHostChipInfo[] completness dependancy. - * - Study drivers/ide/ide-timing.h. - * - Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them - * or remove ATA_00 define + * - CLEANUP + * - Use drivers/ide/ide-timing.h ! * - More checks in the config registers (force values instead of * relying on the BIOS setting them correctly). * - Further optimisations ? * . for example ATA66+ regs 0x48 & 0x4A */ - diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 5b53ae25dfbe..5a5d32aabc0c 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -549,6 +549,7 @@ #define PCI_DEVICE_ID_SI_601 0x0601 #define PCI_DEVICE_ID_SI_620 0x0620 #define PCI_DEVICE_ID_SI_630 0x0630 +#define PCI_DEVICE_ID_SI_633 0x0633 #define PCI_DEVICE_ID_SI_635 0x0635 #define PCI_DEVICE_ID_SI_640 0x0640 #define PCI_DEVICE_ID_SI_645 0x0645 @@ -559,6 +560,7 @@ #define PCI_DEVICE_ID_SI_652 0x0652 #define PCI_DEVICE_ID_SI_655 0x0655 #define PCI_DEVICE_ID_SI_730 0x0730 +#define PCI_DEVICE_ID_SI_733 0x0733 #define PCI_DEVICE_ID_SI_630_VGA 0x6300 #define PCI_DEVICE_ID_SI_730_VGA 0x7300 #define PCI_DEVICE_ID_SI_735 0x0735 @@ -579,7 +581,10 @@ #define PCI_DEVICE_ID_SI_5513 0x5513 #define PCI_DEVICE_ID_SI_5518 0x5518 #define PCI_DEVICE_ID_SI_5571 0x5571 +#define PCI_DEVICE_ID_SI_5581 0x5581 +#define PCI_DEVICE_ID_SI_5582 0x5582 #define PCI_DEVICE_ID_SI_5591 0x5591 +#define PCI_DEVICE_ID_SI_5596 0x5596 #define PCI_DEVICE_ID_SI_5597 0x5597 #define PCI_DEVICE_ID_SI_5598 0x5598 #define PCI_DEVICE_ID_SI_5600 0x5600 -- cgit v1.2.3 From 244f36266d58f4c26d707fdbcff592209d56aa80 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 20 Jun 2003 08:13:06 -0700 Subject: [PATCH] Add system calls statfs64 and fstatfs64 From: Peter Chubb Add two new system calls, statfs64 and fstatfs64. This has been needed sincew the 64-bit sector_t merge - the current structures will overflow. - Use a common interface (vfs_statfs) with the rest of the kernel, - convert to 32-bit at (f)statfs time. - New field f_frsize gives underlying fragment size for the filesystem. (Solaris has this, and the Open Group describe it). - The old statfs syscalls will now return -EOVERFLOW if the device was too large to be represented inthe old data structures. The new system calls take a size_t argument, which is the size of the structure to be filled in (as requested by Ben LaHaise), to `futureproof' the interface. Has been reviewed by the arch maintainers and by Ulrich Drepper. --- arch/alpha/kernel/osf_sys.c | 7 ++- arch/i386/kernel/entry.S | 3 +- arch/ia64/ia32/ia32_entry.S | 22 ++++++++ arch/ia64/kernel/entry.S | 4 +- arch/ia64/kernel/ivt.S | 2 +- fs/adfs/super.c | 4 +- fs/affs/super.c | 4 +- fs/befs/linuxvfs.c | 4 +- fs/bfs/inode.c | 2 +- fs/cifs/cifsfs.c | 2 +- fs/coda/inode.c | 4 +- fs/coda/upcall.c | 2 +- fs/compat.c | 16 ++++-- fs/cramfs/inode.c | 2 +- fs/efs/super.c | 2 +- fs/ext2/super.c | 4 +- fs/ext3/super.c | 2 +- fs/fat/inode.c | 2 +- fs/freevxfs/vxfs_super.c | 4 +- fs/hfs/super.c | 4 +- fs/hpfs/hpfs_fn.h | 2 +- fs/hpfs/super.c | 2 +- fs/intermezzo/intermezzo_fs.h | 2 +- fs/isofs/inode.c | 4 +- fs/jfs/super.c | 2 +- fs/libfs.c | 2 +- fs/minix/inode.c | 4 +- fs/ncpfs/inode.c | 4 +- fs/nfs/inode.c | 4 +- fs/nfsd/nfs3xdr.c | 2 +- fs/nfsd/nfs4xdr.c | 2 +- fs/nfsd/nfsxdr.c | 2 +- fs/nfsd/vfs.c | 2 +- fs/ntfs/super.c | 2 +- fs/open.c | 115 +++++++++++++++++++++++++++++++++++++++--- fs/qnx4/inode.c | 4 +- fs/reiserfs/super.c | 6 +-- fs/romfs/inode.c | 2 +- fs/smbfs/inode.c | 4 +- fs/smbfs/proc.c | 2 +- fs/smbfs/proto.h | 2 +- fs/super.c | 2 +- fs/sysv/inode.c | 2 +- fs/udf/super.c | 4 +- fs/ufs/super.c | 6 +-- fs/xfs/linux/xfs_super.c | 4 +- fs/xfs/linux/xfs_vfs.c | 2 +- fs/xfs/linux/xfs_vfs.h | 6 +-- fs/xfs/xfs_vfsops.c | 4 +- include/asm-alpha/statfs.h | 21 +------- include/asm-arm/statfs.h | 21 +------- include/asm-cris/statfs.h | 21 +------- include/asm-generic/statfs.h | 37 ++++++++++++++ include/asm-h8300/statfs.h | 21 +------- include/asm-i386/statfs.h | 21 +------- include/asm-i386/unistd.h | 4 +- include/asm-ia64/compat.h | 3 +- include/asm-ia64/statfs.h | 27 +++++++--- include/asm-ia64/unistd.h | 2 + include/asm-m68k/statfs.h | 21 +------- include/asm-parisc/compat.h | 3 +- include/asm-parisc/statfs.h | 21 +++++++- include/asm-ppc/statfs.h | 22 +------- include/asm-ppc64/compat.h | 3 +- include/asm-ppc64/statfs.h | 20 +++++++- include/asm-sparc/statfs.h | 21 +------- include/asm-sparc64/statfs.h | 17 ++++++- include/asm-x86_64/compat.h | 3 +- include/asm-x86_64/statfs.h | 21 +++++++- include/linux/coda_psdev.h | 2 +- include/linux/efs_fs.h | 2 +- include/linux/ext3_fs.h | 2 +- include/linux/fs.h | 8 +-- include/linux/msdos_fs.h | 2 +- include/linux/nfsd/nfsd.h | 2 +- include/linux/nfsd/xdr.h | 2 +- include/linux/nfsd/xdr3.h | 2 +- include/linux/statfs.h | 22 ++++++++ include/linux/vfs.h | 2 +- kernel/acct.c | 14 +++-- mm/shmem.c | 2 +- 81 files changed, 414 insertions(+), 275 deletions(-) create mode 100644 include/asm-generic/statfs.h create mode 100644 include/linux/statfs.h (limited to 'include/linux') diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index c42a9d7b84b0..cce7e0d07250 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -218,15 +218,14 @@ struct osf_statfs { } *osf_stat; static int -linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf_stat, +linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs *osf_stat, unsigned long bufsiz) { struct osf_statfs tmp_stat; tmp_stat.f_type = linux_stat->f_type; tmp_stat.f_flags = 0; /* mount flags */ - /* Linux doesn't provide a "fundamental filesystem block size": */ - tmp_stat.f_fsize = linux_stat->f_bsize; + tmp_stat.f_fsize = linux_stat->f_frsize; tmp_stat.f_bsize = linux_stat->f_bsize; tmp_stat.f_blocks = linux_stat->f_blocks; tmp_stat.f_bfree = linux_stat->f_bfree; @@ -243,7 +242,7 @@ static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsigned long bufsiz) { - struct statfs linux_stat; + struct kstatfs linux_stat; int error = vfs_statfs(dentry->d_inode->i_sb, &linux_stat); if (!error) error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz); diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index ad45189c98ce..5aef7a47a383 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -874,6 +874,7 @@ ENTRY(sys_call_table) .long sys_clock_gettime /* 265 */ .long sys_clock_getres .long sys_clock_nanosleep - + .long sys_statfs64 + .long sys_fstatfs64 nr_syscalls=(.-sys_call_table)/4 diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index 200add0897e5..17ec2150ffbe 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -436,6 +436,28 @@ ia32_syscall_table: data8 sys_ni_syscall data8 sys_ni_syscall data8 sys_ni_syscall + data8 sys_ni_syscall /* 250 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /*255*/ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 260 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 265 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_statfs64 + data8 sys_fstatfs64 + data8 sys_ni_syscall + /* * CAUTION: If any system calls are added beyond this point * then the check in `arch/ia64/kernel/ivt.S' will have diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index b7e92042b522..ba2bcfc717b9 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1430,8 +1430,8 @@ sys_call_table: data8 sys_clock_gettime data8 sys_clock_getres // 1255 data8 sys_clock_nanosleep - data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_fstatfs64 + data8 sys_statfs64 data8 ia64_ni_syscall data8 ia64_ni_syscall // 1260 data8 ia64_ni_syscall diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index b57e638f6ed5..db9500165ab8 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -1513,7 +1513,7 @@ ENTRY(dispatch_to_ia32_handler) alloc r15=ar.pfs,0,0,6,0 // must first in an insn group ;; ld4 r8=[r14],8 // r8 == eax (syscall number) - mov r15=250 // number of entries in ia32 system call table + mov r15=270 // number of entries in ia32 system call table ;; cmp.ltu.unc p6,p7=r8,r15 ld4 out1=[r14],8 // r9 == ecx diff --git a/fs/adfs/super.c b/fs/adfs/super.c index d5b8294a2fa1..31591a9d6ea3 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -189,7 +189,7 @@ static int adfs_remount(struct super_block *sb, int *flags, char *data) return parse_options(sb, data); } -static int adfs_statfs(struct super_block *sb, struct statfs *buf) +static int adfs_statfs(struct super_block *sb, struct kstatfs *buf) { struct adfs_sb_info *asb = ADFS_SB(sb); @@ -200,7 +200,7 @@ static int adfs_statfs(struct super_block *sb, struct statfs *buf) buf->f_files = asb->s_ids_per_zone * asb->s_map_size; buf->f_bavail = buf->f_bfree = adfs_map_free(sb); - buf->f_ffree = buf->f_bfree * buf->f_files / buf->f_blocks; + buf->f_ffree = (long)(buf->f_bfree * buf->f_files) / (long)buf->f_blocks; return 0; } diff --git a/fs/affs/super.c b/fs/affs/super.c index 61c71fe3f785..5a07bcd17f60 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -33,7 +33,7 @@ extern struct timezone sys_tz; -static int affs_statfs(struct super_block *sb, struct statfs *buf); +static int affs_statfs(struct super_block *sb, struct kstatfs *buf); static int affs_remount (struct super_block *sb, int *flags, char *data); static void @@ -524,7 +524,7 @@ affs_remount(struct super_block *sb, int *flags, char *data) } static int -affs_statfs(struct super_block *sb, struct statfs *buf) +affs_statfs(struct super_block *sb, struct kstatfs *buf) { int free; diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 5295f9d97c84..4fb5a163e50d 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -47,7 +47,7 @@ static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, char **out, int *out_len); static void befs_put_super(struct super_block *); static int befs_remount(struct super_block *, int *, char *); -static int befs_statfs(struct super_block *, struct statfs *); +static int befs_statfs(struct super_block *, struct kstatfs *); static int parse_options(char *, befs_mount_options *); static const struct super_operations befs_sops = { @@ -896,7 +896,7 @@ befs_remount(struct super_block *sb, int *flags, char *data) } static int -befs_statfs(struct super_block *sb, struct statfs *buf) +befs_statfs(struct super_block *sb, struct kstatfs *buf) { befs_debug(sb, "---> befs_statfs()"); diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 7a28495b0a87..1cd9f94879a5 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -191,7 +191,7 @@ static void bfs_put_super(struct super_block *s) s->s_fs_info = NULL; } -static int bfs_statfs(struct super_block *s, struct statfs *buf) +static int bfs_statfs(struct super_block *s, struct kstatfs *buf) { struct bfs_sb_info *info = BFS_SB(s); buf->f_type = BFS_MAGIC; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index fa62f928c838..1b3c43949f33 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -146,7 +146,7 @@ cifs_put_super(struct super_block *sb) } int -cifs_statfs(struct super_block *sb, struct statfs *buf) +cifs_statfs(struct super_block *sb, struct kstatfs *buf) { int xid, rc; struct cifs_sb_info *cifs_sb; diff --git a/fs/coda/inode.c b/fs/coda/inode.c index b7a836f30cf5..91087269e255 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -34,7 +34,7 @@ /* VFS super_block ops */ static void coda_clear_inode(struct inode *); static void coda_put_super(struct super_block *); -static int coda_statfs(struct super_block *sb, struct statfs *buf); +static int coda_statfs(struct super_block *sb, struct kstatfs *buf); static kmem_cache_t * coda_inode_cachep; @@ -273,7 +273,7 @@ struct inode_operations coda_file_inode_operations = { .setattr = coda_setattr, }; -static int coda_statfs(struct super_block *sb, struct statfs *buf) +static int coda_statfs(struct super_block *sb, struct kstatfs *buf) { int error; diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 9a15dedc8d8a..6ab4f181513e 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -585,7 +585,7 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, return error; } -int venus_statfs(struct super_block *sb, struct statfs *sfs) +int venus_statfs(struct super_block *sb, struct kstatfs *sfs) { union inputArgs *inp; union outputArgs *outp; diff --git a/fs/compat.c b/fs/compat.c index 832fc6042d81..21cc8f185df9 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -87,8 +87,15 @@ asmlinkage long compat_sys_newfstat(unsigned int fd, return error; } -static int put_compat_statfs(struct compat_statfs *ubuf, struct statfs *kbuf) +static int put_compat_statfs(struct compat_statfs *ubuf, struct kstatfs *kbuf) { + + if (sizeof ubuf->f_blocks == 4) { + if ((kbuf->f_blocks | kbuf->f_bfree | + kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) & + 0xffffffff00000000ULL) + return -EOVERFLOW; + } if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) || __put_user(kbuf->f_type, &ubuf->f_type) || __put_user(kbuf->f_bsize, &ubuf->f_bsize) || @@ -99,7 +106,8 @@ static int put_compat_statfs(struct compat_statfs *ubuf, struct statfs *kbuf) __put_user(kbuf->f_ffree, &ubuf->f_ffree) || __put_user(kbuf->f_namelen, &ubuf->f_namelen) || __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) || - __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1])) + __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) || + __put_user(kbuf->f_frsize, &ubuf->f_frsize)) return -EFAULT; return 0; } @@ -115,7 +123,7 @@ asmlinkage long compat_sys_statfs(const char *path, struct compat_statfs *buf) error = user_path_walk(path, &nd); if (!error) { - struct statfs tmp; + struct kstatfs tmp; error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp); if (!error && put_compat_statfs(buf, &tmp)) error = -EFAULT; @@ -127,7 +135,7 @@ asmlinkage long compat_sys_statfs(const char *path, struct compat_statfs *buf) asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs *buf) { struct file * file; - struct statfs tmp; + struct kstatfs tmp; int error; error = -EBADF; diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 7e7f162fc0e3..c6d6844796bb 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -266,7 +266,7 @@ out: return -EINVAL; } -static int cramfs_statfs(struct super_block *sb, struct statfs *buf) +static int cramfs_statfs(struct super_block *sb, struct kstatfs *buf) { buf->f_type = CRAMFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; diff --git a/fs/efs/super.c b/fs/efs/super.c index f7276de1f6b1..13ef5b5b7813 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -278,7 +278,7 @@ out_no_fs: return -EINVAL; } -int efs_statfs(struct super_block *s, struct statfs *buf) { +int efs_statfs(struct super_block *s, struct kstatfs *buf) { struct efs_sb_info *sb = SUPER_INFO(s); buf->f_type = EFS_SUPER_MAGIC; /* efs magic number */ diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 48a3d099f9a0..c4604187f186 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -34,7 +34,7 @@ static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es); static int ext2_remount (struct super_block * sb, int * flags, char * data); -static int ext2_statfs (struct super_block * sb, struct statfs * buf); +static int ext2_statfs (struct super_block * sb, struct kstatfs * buf); static char error_buf[1024]; @@ -939,7 +939,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) return 0; } -static int ext2_statfs (struct super_block * sb, struct statfs * buf) +static int ext2_statfs (struct super_block * sb, struct kstatfs * buf) { struct ext2_sb_info *sbi = EXT2_SB(sb); unsigned long overhead; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 91dca2770189..8769dc2cc593 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1934,7 +1934,7 @@ int ext3_remount (struct super_block * sb, int * flags, char * data) return 0; } -int ext3_statfs (struct super_block * sb, struct statfs * buf) +int ext3_statfs (struct super_block * sb, struct kstatfs * buf) { struct ext3_super_block *es = EXT3_SB(sb)->s_es; unsigned long overhead; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index d11c0fbd0a24..55df25851655 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1019,7 +1019,7 @@ out_fail: return error; } -int fat_statfs(struct super_block *sb,struct statfs *buf) +int fat_statfs(struct super_block *sb, struct kstatfs *buf) { int free,nr; diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index d3ebd64c780e..d49c04846e4f 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -55,7 +55,7 @@ MODULE_LICENSE("Dual BSD/GPL"); static void vxfs_put_super(struct super_block *); -static int vxfs_statfs(struct super_block *, struct statfs *); +static int vxfs_statfs(struct super_block *, struct kstatfs *); static struct super_operations vxfs_super_ops = { .read_inode = vxfs_read_inode, @@ -105,7 +105,7 @@ vxfs_put_super(struct super_block *sbp) * This is everything but complete... */ static int -vxfs_statfs(struct super_block *sbp, struct statfs *bufp) +vxfs_statfs(struct super_block *sbp, struct kstatfs *bufp) { struct vxfs_sb_info *infp = VXFS_SBI(sbp); diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 48be69ce4108..408911021654 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -40,7 +40,7 @@ MODULE_LICENSE("GPL"); static void hfs_read_inode(struct inode *); static void hfs_put_super(struct super_block *); -static int hfs_statfs(struct super_block *, struct statfs *); +static int hfs_statfs(struct super_block *, struct kstatfs *); static void hfs_write_super(struct super_block *); static kmem_cache_t * hfs_inode_cachep; @@ -195,7 +195,7 @@ static void hfs_put_super(struct super_block *sb) * * changed f_files/f_ffree to reflect the fs_ablock/free_ablocks. */ -static int hfs_statfs(struct super_block *sb, struct statfs *buf) +static int hfs_statfs(struct super_block *sb, struct kstatfs *buf) { struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb; diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 84d5023cac6c..91f880e88362 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -310,7 +310,7 @@ int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *); int hpfs_remount_fs(struct super_block *, int *, char *); void hpfs_put_super(struct super_block *); unsigned hpfs_count_one_bitmap(struct super_block *, secno); -int hpfs_statfs(struct super_block *, struct statfs *); +int hpfs_statfs(struct super_block *, struct kstatfs *); extern struct address_space_operations hpfs_aops; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 36aa38cd829a..5827a006dd9b 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -136,7 +136,7 @@ static unsigned count_bitmaps(struct super_block *s) return count; } -int hpfs_statfs(struct super_block *s, struct statfs *buf) +int hpfs_statfs(struct super_block *s, struct kstatfs *buf) { struct hpfs_sb_info *sbi = hpfs_sb(s); lock_kernel(); diff --git a/fs/intermezzo/intermezzo_fs.h b/fs/intermezzo/intermezzo_fs.h index 5a91c61188da..8d2d33fcee0e 100644 --- a/fs/intermezzo/intermezzo_fs.h +++ b/fs/intermezzo/intermezzo_fs.h @@ -530,7 +530,7 @@ int do_rename(struct presto_file_set *fset, struct dentry *old_dir, struct dentry *old_dentry, struct dentry *new_dir, struct dentry *new_dentry, struct lento_vfs_context *info); int presto_do_statfs (struct presto_file_set *fset, - struct statfs * buf); + struct kstatfs * buf); int lento_setattr(const char *name, struct iattr *iattr, struct lento_vfs_context *info); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 5e21abe15531..a28d5f174b9b 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -74,7 +74,7 @@ static void isofs_put_super(struct super_block *sb) } static void isofs_read_inode(struct inode *); -static int isofs_statfs (struct super_block *, struct statfs *); +static int isofs_statfs (struct super_block *, struct kstatfs *); static kmem_cache_t *isofs_inode_cachep; @@ -884,7 +884,7 @@ out_freesbi: return -EINVAL; } -static int isofs_statfs (struct super_block *sb, struct statfs *buf) +static int isofs_statfs (struct super_block *sb, struct kstatfs *buf) { buf->f_type = ISOFS_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 74036f743e31..32a123400a79 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -117,7 +117,7 @@ static void jfs_destroy_inode(struct inode *inode) kmem_cache_free(jfs_inode_cachep, ji); } -static int jfs_statfs(struct super_block *sb, struct statfs *buf) +static int jfs_statfs(struct super_block *sb, struct kstatfs *buf) { struct jfs_sb_info *sbi = JFS_SBI(sb); s64 maxinodes; diff --git a/fs/libfs.c b/fs/libfs.c index 2553f5463419..62fb3c0fbc24 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -16,7 +16,7 @@ int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, return 0; } -int simple_statfs(struct super_block *sb, struct statfs *buf) +int simple_statfs(struct super_block *sb, struct kstatfs *buf) { buf->f_type = sb->s_magic; buf->f_bsize = PAGE_CACHE_SIZE; diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 93005e83d319..710e46886609 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -19,7 +19,7 @@ static void minix_read_inode(struct inode * inode); static void minix_write_inode(struct inode * inode, int wait); -static int minix_statfs(struct super_block *sb, struct statfs *buf); +static int minix_statfs(struct super_block *sb, struct kstatfs *buf); static int minix_remount (struct super_block * sb, int * flags, char * data); static void minix_delete_inode(struct inode *inode) @@ -294,7 +294,7 @@ out_bad_sb: return -EINVAL; } -static int minix_statfs(struct super_block *sb, struct statfs *buf) +static int minix_statfs(struct super_block *sb, struct kstatfs *buf) { struct minix_sb_info *sbi = minix_sb(sb); buf->f_type = sb->s_magic; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index a982e1f14dc0..70eab7961377 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -39,7 +39,7 @@ static void ncp_delete_inode(struct inode *); static void ncp_put_super(struct super_block *); -static int ncp_statfs(struct super_block *, struct statfs *); +static int ncp_statfs(struct super_block *, struct kstatfs *); static kmem_cache_t * ncp_inode_cachep; @@ -717,7 +717,7 @@ static void ncp_put_super(struct super_block *sb) kfree(server); } -static int ncp_statfs(struct super_block *sb, struct statfs *buf) +static int ncp_statfs(struct super_block *sb, struct kstatfs *buf) { struct dentry* d; struct inode* i; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index b27662b85b3c..cdf78285b736 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -53,7 +53,7 @@ static void nfs_delete_inode(struct inode *); static void nfs_put_super(struct super_block *); static void nfs_clear_inode(struct inode *); static void nfs_umount_begin(struct super_block *); -static int nfs_statfs(struct super_block *, struct statfs *); +static int nfs_statfs(struct super_block *, struct kstatfs *); static int nfs_show_options(struct seq_file *, struct vfsmount *); static struct super_operations nfs_sops = { @@ -474,7 +474,7 @@ out_fail: } static int -nfs_statfs(struct super_block *sb, struct statfs *buf) +nfs_statfs(struct super_block *sb, struct kstatfs *buf) { struct nfs_server *server = NFS_SB(sb); unsigned char blockbits; diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index ea64d649de3d..b3bcce53d605 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -866,7 +866,7 @@ int nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p, struct nfsd3_fsstatres *resp) { - struct statfs *s = &resp->stats; + struct kstatfs *s = &resp->stats; u64 bs = s->f_bsize; *p++ = xdr_zero; /* no post_op_attr */ diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2146b8eaa045..26cf94635f61 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1081,7 +1081,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, struct name_ent *owner = NULL; struct name_ent *group = NULL; struct svc_fh tempfh; - struct statfs statfs; + struct kstatfs statfs; int buflen = *countp << 2; u32 *attrlenp; u32 dummy; diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index f28c4c0d2508..f724778dc44c 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -441,7 +441,7 @@ int nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p, struct nfsd_statfsres *resp) { - struct statfs *stat = &resp->stats; + struct kstatfs *stat = &resp->stats; *p++ = htonl(NFSSVC_MAXBLKSIZE); /* max transfer size */ *p++ = htonl(stat->f_bsize); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 294860aefa8b..8759cb1076ad 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1505,7 +1505,7 @@ out: * N.B. After this call fhp needs an fh_put */ int -nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct statfs *stat) +nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) { int err = fh_verify(rqstp, fhp, 0, MAY_NOP); if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat)) diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 475799f476ac..aaa7ec00b633 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -1251,7 +1251,7 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol) * * Return 0 on success or -errno on error. */ -static int ntfs_statfs(struct super_block *sb, struct statfs *sfs) +static int ntfs_statfs(struct super_block *sb, struct kstatfs *sfs) { ntfs_volume *vol = NTFS_SB(sb); s64 size; diff --git a/fs/open.c b/fs/open.c index fac3d44702d6..2e2e4e4dae97 100644 --- a/fs/open.c +++ b/fs/open.c @@ -23,23 +23,85 @@ #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) -int vfs_statfs(struct super_block *sb, struct statfs *buf) +int vfs_statfs(struct super_block *sb, struct kstatfs *buf) { int retval = -ENODEV; if (sb) { retval = -ENOSYS; if (sb->s_op->statfs) { - memset(buf, 0, sizeof(struct statfs)); + memset(buf, 0, sizeof(*buf)); retval = security_sb_statfs(sb); if (retval) return retval; retval = sb->s_op->statfs(sb, buf); + if (retval == 0 && buf->f_frsize == 0) + buf->f_frsize = buf->f_bsize; } } return retval; } +static int vfs_statfs_native(struct super_block *sb, struct statfs *buf) +{ + struct kstatfs st; + int retval; + + retval = vfs_statfs(sb, &st); + if (retval) + return retval; + + if (sizeof(*buf) == sizeof(st)) + memcpy(buf, &st, sizeof(st)); + else { + if (sizeof buf->f_blocks == 4) { + if ((st.f_blocks | st.f_bfree | + st.f_bavail | st.f_files | st.f_ffree) & + 0xffffffff00000000ULL) + return -EOVERFLOW; + } + + buf->f_type = st.f_type; + buf->f_bsize = st.f_bsize; + buf->f_blocks = st.f_blocks; + buf->f_bfree = st.f_bfree; + buf->f_bavail = st.f_bavail; + buf->f_files = st.f_files; + buf->f_ffree = st.f_ffree; + buf->f_fsid = st.f_fsid; + buf->f_namelen = st.f_namelen; + buf->f_frsize = st.f_frsize; + memset(buf->f_spare, 0, sizeof(buf->f_spare)); + } + return 0; +} + +static int vfs_statfs64(struct super_block *sb, struct statfs64 *buf) +{ + struct kstatfs st; + int retval; + + retval = vfs_statfs(sb, &st); + if (retval) + return retval; + + if (sizeof(*buf) == sizeof(st)) + memcpy(buf, &st, sizeof(st)); + else { + buf->f_type = st.f_type; + buf->f_bsize = st.f_bsize; + buf->f_blocks = st.f_blocks; + buf->f_bfree = st.f_bfree; + buf->f_bavail = st.f_bavail; + buf->f_files = st.f_files; + buf->f_ffree = st.f_ffree; + buf->f_fsid = st.f_fsid; + buf->f_namelen = st.f_namelen; + buf->f_frsize = st.f_frsize; + memset(buf->f_spare, 0, sizeof(buf->f_spare)); + } + return 0; +} asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf) { @@ -49,14 +111,34 @@ asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf) error = user_path_walk(path, &nd); if (!error) { struct statfs tmp; - error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp); - if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs))) + error = vfs_statfs_native(nd.dentry->d_inode->i_sb, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_release(&nd); } return error; } + +asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 __user *buf) +{ + struct nameidata nd; + long error; + + if (sz != sizeof(*buf)) + return -EINVAL; + error = user_path_walk(path, &nd); + if (!error) { + struct statfs64 tmp; + error = vfs_statfs64(nd.dentry->d_inode->i_sb, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) + error = -EFAULT; + path_release(&nd); + } + return error; +} + + asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf) { struct file * file; @@ -67,8 +149,29 @@ asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf) file = fget(fd); if (!file) goto out; - error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp); - if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs))) + error = vfs_statfs_native(file->f_dentry->d_inode->i_sb, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) + error = -EFAULT; + fput(file); +out: + return error; +} + +asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user *buf) +{ + struct file * file; + struct statfs64 tmp; + int error; + + if (sz != sizeof(*buf)) + return -EINVAL; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + error = vfs_statfs64(file->f_dentry->d_inode->i_sb, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); out: diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 90f7a0034e64..c894b7ecac00 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -126,7 +126,7 @@ static struct inode *qnx4_alloc_inode(struct super_block *sb); static void qnx4_destroy_inode(struct inode *inode); static void qnx4_read_inode(struct inode *); static int qnx4_remount(struct super_block *sb, int *flags, char *data); -static int qnx4_statfs(struct super_block *, struct statfs *); +static int qnx4_statfs(struct super_block *, struct kstatfs *); static struct super_operations qnx4_sops = { @@ -276,7 +276,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock ) return block; } -static int qnx4_statfs(struct super_block *sb, struct statfs *buf) +static int qnx4_statfs(struct super_block *sb, struct kstatfs *buf) { lock_kernel(); diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 8ff47e47a2e1..9f37ffd92761 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -62,7 +62,7 @@ int is_reiserfs_super (struct super_block *s) } static int reiserfs_remount (struct super_block * s, int * flags, char * data); -static int reiserfs_statfs (struct super_block * s, struct statfs * buf); +static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf); static void reiserfs_write_super (struct super_block * s) { @@ -1414,13 +1414,11 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) } -static int reiserfs_statfs (struct super_block * s, struct statfs * buf) +static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf) { struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s); buf->f_namelen = (REISERFS_MAX_NAME (s->s_blocksize)); - buf->f_ffree = -1; - buf->f_files = -1; buf->f_bfree = sb_free_blocks(rs); buf->f_bavail = buf->f_bfree; buf->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1; diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index dd52de09689c..fb60389d42fc 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -176,7 +176,7 @@ outnobh: /* That's simple too. */ static int -romfs_statfs(struct super_block *sb, struct statfs *buf) +romfs_statfs(struct super_block *sb, struct kstatfs *buf) { buf->f_type = ROMFS_MAGIC; buf->f_bsize = ROMBSIZE; diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index abe004b1e78f..b3dd504d88e6 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -47,7 +47,7 @@ static void smb_delete_inode(struct inode *); static void smb_put_super(struct super_block *); -static int smb_statfs(struct super_block *, struct statfs *); +static int smb_statfs(struct super_block *, struct kstatfs *); static int smb_show_options(struct seq_file *, struct vfsmount *); static kmem_cache_t *smb_inode_cachep; @@ -610,7 +610,7 @@ out_no_server: } static int -smb_statfs(struct super_block *sb, struct statfs *buf) +smb_statfs(struct super_block *sb, struct kstatfs *buf) { int result; diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index e3221e28b887..8c386131c9ea 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -3160,7 +3160,7 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr) } int -smb_proc_dskattr(struct super_block *sb, struct statfs *attr) +smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr) { struct smb_sb_info *server = SMB_SB(sb); int result; diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h index ec44bad0e84e..e42cf69c061c 100644 --- a/fs/smbfs/proto.h +++ b/fs/smbfs/proto.h @@ -29,7 +29,7 @@ extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr); extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr); extern int smb_proc_setattr_unix(struct dentry *d, struct iattr *attr, unsigned int major, unsigned int minor); extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr); -extern int smb_proc_dskattr(struct super_block *sb, struct statfs *attr); +extern int smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr); extern int smb_proc_read_link(struct smb_sb_info *server, struct dentry *d, char *buffer, int len); extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *d, const char *oldpath); extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry); diff --git a/fs/super.c b/fs/super.c index 2aae8ed4cdcc..8f1f26de1673 100644 --- a/fs/super.c +++ b/fs/super.c @@ -409,7 +409,7 @@ asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf) { struct super_block *s; struct ustat tmp; - struct statfs sbuf; + struct kstatfs sbuf; int err = -EINVAL; s = user_get_super(dev); diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index d433042d358f..9a4564610aae 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -75,7 +75,7 @@ static void sysv_put_super(struct super_block *sb) kfree(sbi); } -static int sysv_statfs(struct super_block *sb, struct statfs *buf) +static int sysv_statfs(struct super_block *sb, struct kstatfs *buf) { struct sysv_sb_info *sbi = SYSV_SB(sb); diff --git a/fs/udf/super.c b/fs/udf/super.c index 00bfdd3d6a1b..2b82a0451814 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -95,7 +95,7 @@ static void udf_load_partdesc(struct super_block *, struct buffer_head *); static void udf_open_lvid(struct super_block *); static void udf_close_lvid(struct super_block *); static unsigned int udf_count_free(struct super_block *); -static int udf_statfs(struct super_block *, struct statfs *); +static int udf_statfs(struct super_block *, struct kstatfs *); /* UDF filesystem type */ static struct super_block *udf_get_sb(struct file_system_type *fs_type, @@ -1720,7 +1720,7 @@ udf_put_super(struct super_block *sb) * Written, tested, and released. */ static int -udf_statfs(struct super_block *sb, struct statfs *buf) +udf_statfs(struct super_block *sb, struct kstatfs *buf) { buf->f_type = UDF_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; diff --git a/fs/ufs/super.c b/fs/ufs/super.c index d9d96adb4672..802ca517153e 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -973,7 +973,7 @@ int ufs_remount (struct super_block * sb, int * mount_flags, char * data) return 0; } -int ufs_statfs (struct super_block * sb, struct statfs * buf) +int ufs_statfs (struct super_block * sb, struct kstatfs * buf) { struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; @@ -988,8 +988,8 @@ int ufs_statfs (struct super_block * sb, struct statfs * buf) buf->f_blocks = uspi->s_dsize; buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) + fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree); - buf->f_bavail = (buf->f_bfree > ((buf->f_blocks / 100) * uspi->s_minfree)) - ? (buf->f_bfree - ((buf->f_blocks / 100) * uspi->s_minfree)) : 0; + buf->f_bavail = (buf->f_bfree > (((long)buf->f_blocks / 100) * uspi->s_minfree)) + ? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0; buf->f_files = uspi->s_ncg * uspi->s_ipg; buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree); buf->f_namelen = UFS_MAXNAMLEN; diff --git a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c index 7d2662e59031..160db99c007e 100644 --- a/fs/xfs/linux/xfs_super.c +++ b/fs/xfs/linux/xfs_super.c @@ -477,7 +477,7 @@ linvfs_write_super( STATIC int linvfs_statfs( struct super_block *sb, - struct statfs *statp) + struct kstatfs *statp) { vfs_t *vfsp = LINVFS_GET_VFS(sb); int error; @@ -673,7 +673,7 @@ linvfs_fill_super( vnode_t *rootvp; struct vfs *vfsp = vfs_allocate(); struct xfs_mount_args *args = args_allocate(sb); - struct statfs statvfs; + struct kstatfs statvfs; int error; vfsp->vfs_super = sb; diff --git a/fs/xfs/linux/xfs_vfs.c b/fs/xfs/linux/xfs_vfs.c index 86329735784f..938a2a449475 100644 --- a/fs/xfs/linux/xfs_vfs.c +++ b/fs/xfs/linux/xfs_vfs.c @@ -134,7 +134,7 @@ vfs_root( int vfs_statvfs( struct bhv_desc *bdp, - struct statfs *sp, + struct kstatfs *sp, struct vnode *vp) { struct bhv_desc *next = bdp; diff --git a/fs/xfs/linux/xfs_vfs.h b/fs/xfs/linux/xfs_vfs.h index 3379ecbdc28d..4fdc33919ee0 100644 --- a/fs/xfs/linux/xfs_vfs.h +++ b/fs/xfs/linux/xfs_vfs.h @@ -37,7 +37,7 @@ struct fid; struct cred; struct vnode; -struct statfs; +struct kstatfs; struct seq_file; struct super_block; struct xfs_mount_args; @@ -100,7 +100,7 @@ typedef int (*vfs_unmount_t)(bhv_desc_t *, int, struct cred *); typedef int (*vfs_mntupdate_t)(bhv_desc_t *, int *, struct xfs_mount_args *); typedef int (*vfs_root_t)(bhv_desc_t *, struct vnode **); -typedef int (*vfs_statvfs_t)(bhv_desc_t *, struct statfs *, struct vnode *); +typedef int (*vfs_statvfs_t)(bhv_desc_t *, struct kstatfs *, struct vnode *); typedef int (*vfs_sync_t)(bhv_desc_t *, int, struct cred *); typedef int (*vfs_vget_t)(bhv_desc_t *, struct vnode **, struct fid *); typedef int (*vfs_dmapiops_t)(bhv_desc_t *, caddr_t); @@ -167,7 +167,7 @@ extern int vfs_showargs(bhv_desc_t *, struct seq_file *); extern int vfs_unmount(bhv_desc_t *, int, struct cred *); extern int vfs_mntupdate(bhv_desc_t *, int *, struct xfs_mount_args *); extern int vfs_root(bhv_desc_t *, struct vnode **); -extern int vfs_statvfs(bhv_desc_t *, struct statfs *, struct vnode *); +extern int vfs_statvfs(bhv_desc_t *, struct kstatfs *, struct vnode *); extern int vfs_sync(bhv_desc_t *, int, struct cred *); extern int vfs_vget(bhv_desc_t *, struct vnode **, struct fid *); extern int vfs_dmapiops(bhv_desc_t *, caddr_t); diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index f19ace802b69..4f1af83546f8 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -752,7 +752,7 @@ xfs_root( STATIC int xfs_statvfs( bhv_desc_t *bdp, - struct statfs *statp, + struct kstatfs *statp, vnode_t *vp) { __uint64_t fakeinos; @@ -782,7 +782,7 @@ xfs_statvfs( if (!mp->m_inoadd) #endif statp->f_files = - MIN(statp->f_files, (long)mp->m_maxicount); + min_t(sector_t, statp->f_files, mp->m_maxicount); statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree); XFS_SB_UNLOCK(mp, s); diff --git a/include/asm-alpha/statfs.h b/include/asm-alpha/statfs.h index cc4ba1de0ede..ad15830baefe 100644 --- a/include/asm-alpha/statfs.h +++ b/include/asm-alpha/statfs.h @@ -1,25 +1,6 @@ #ifndef _ALPHA_STATFS_H #define _ALPHA_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - int f_type; - int f_bsize; - int f_blocks; - int f_bfree; - int f_bavail; - int f_files; - int f_ffree; - __kernel_fsid_t f_fsid; - int f_namelen; - int f_spare[6]; -}; +#include #endif diff --git a/include/asm-arm/statfs.h b/include/asm-arm/statfs.h index a1eba73ded99..e81f82783b87 100644 --- a/include/asm-arm/statfs.h +++ b/include/asm-arm/statfs.h @@ -1,25 +1,6 @@ #ifndef _ASMARM_STATFS_H #define _ASMARM_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif diff --git a/include/asm-cris/statfs.h b/include/asm-cris/statfs.h index 9bfcc5ea2808..fdaf921844bc 100644 --- a/include/asm-cris/statfs.h +++ b/include/asm-cris/statfs.h @@ -1,25 +1,6 @@ #ifndef _CRIS_STATFS_H #define _CRIS_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif diff --git a/include/asm-generic/statfs.h b/include/asm-generic/statfs.h new file mode 100644 index 000000000000..fecaf8fd5c10 --- /dev/null +++ b/include/asm-generic/statfs.h @@ -0,0 +1,37 @@ +#ifndef _GENERIC_STATFS_H +#define _GENERIC_STATFS_H + +#ifndef __KERNEL_STRICT_NAMES +# include +typedef __kernel_fsid_t fsid_t; +#endif + +struct statfs { + __u32 f_type; + __u32 f_bsize; + __u32 f_blocks; + __u32 f_bfree; + __u32 f_bavail; + __u32 f_files; + __u32 f_ffree; + __kernel_fsid_t f_fsid; + __u32 f_namelen; + __u32 f_frsize; + __u32 f_spare[5]; +}; + +struct statfs64 { + __u32 f_type; + __u32 f_bsize; + __u64 f_blocks; + __u64 f_bfree; + __u64 f_bavail; + __u64 f_files; + __u64 f_ffree; + __kernel_fsid_t f_fsid; + __u32 f_namelen; + __u32 f_frsize; + __u32 f_spare[5]; +}; + +#endif diff --git a/include/asm-h8300/statfs.h b/include/asm-h8300/statfs.h index 9e3be68f0c07..b96efa712aac 100644 --- a/include/asm-h8300/statfs.h +++ b/include/asm-h8300/statfs.h @@ -1,25 +1,6 @@ #ifndef _H8300_STATFS_H #define _H8300_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif /* _H8300_STATFS_H */ diff --git a/include/asm-i386/statfs.h b/include/asm-i386/statfs.h index 113d5d428aa0..24972c175132 100644 --- a/include/asm-i386/statfs.h +++ b/include/asm-i386/statfs.h @@ -1,25 +1,6 @@ #ifndef _I386_STATFS_H #define _I386_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 84d35a14522e..b1bdc016eed5 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -273,8 +273,10 @@ #define __NR_clock_gettime (__NR_timer_create+6) #define __NR_clock_getres (__NR_timer_create+7) #define __NR_clock_nanosleep (__NR_timer_create+8) +#define __NR_statfs64 268 +#define __NR_fstatfs64 269 -#define NR_syscalls 268 +#define NR_syscalls 270 /* user-visible error numbers are in the range -1 - -124: see */ diff --git a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h index 83e8115083f2..b8c101e54e47 100644 --- a/include/asm-ia64/compat.h +++ b/include/asm-ia64/compat.h @@ -99,7 +99,8 @@ struct compat_statfs { int f_ffree; compat_fsid_t f_fsid; int f_namelen; /* SunOS ignores this field. */ - int f_spare[6]; + int f_frsize; + int f_spare[5]; }; #define COMPAT_RLIM_OLD_INFINITY 0x7fffffff diff --git a/include/asm-ia64/statfs.h b/include/asm-ia64/statfs.h index 4e684d5c8e14..56f545513f95 100644 --- a/include/asm-ia64/statfs.h +++ b/include/asm-ia64/statfs.h @@ -6,11 +6,9 @@ * Copyright (C) 1998, 1999 David Mosberger-Tang */ -# ifndef __KERNEL_STRICT_NAMES -# include - typedef __kernel_fsid_t fsid_t; -# endif - +/* + * This is ugly --- we're already 64-bit, so just duplicate the definitions + */ struct statfs { long f_type; long f_bsize; @@ -21,7 +19,24 @@ struct statfs { long f_ffree; __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_frsize; + long f_spare[5]; +}; + + +struct statfs64 { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; }; + #endif /* _ASM_IA64_STATFS_H */ diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index 6bb7dff36ffe..8a254dbd5e1c 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -246,6 +246,8 @@ #define __NR_sys_clock_gettime 1254 #define __NR_sys_clock_getres 1255 #define __NR_sys_clock_nanosleep 1256 +#define __NR_sys_fstatfs64 1257 +#define __NR_sys_statfs64 1258 #ifdef __KERNEL__ diff --git a/include/asm-m68k/statfs.h b/include/asm-m68k/statfs.h index 1ee08965d53b..08d93f14e061 100644 --- a/include/asm-m68k/statfs.h +++ b/include/asm-m68k/statfs.h @@ -1,25 +1,6 @@ #ifndef _M68K_STATFS_H #define _M68K_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif /* _M68K_STATFS_H */ diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h index f888716df94f..cbb696307310 100644 --- a/include/asm-parisc/compat.h +++ b/include/asm-parisc/compat.h @@ -97,7 +97,8 @@ struct compat_statfs { s32 f_ffree; __kernel_fsid_t f_fsid; s32 f_namelen; - s32 f_spare[6]; + s32 f_frsize; + s32 f_spare[5]; }; #define COMPAT_RLIM_INFINITY 0xffffffff diff --git a/include/asm-parisc/statfs.h b/include/asm-parisc/statfs.h index db72e852efd8..e8c8169d5d7f 100644 --- a/include/asm-parisc/statfs.h +++ b/include/asm-parisc/statfs.h @@ -9,6 +9,10 @@ typedef __kernel_fsid_t fsid_t; #endif +/* + * It appears that PARISC could be 64 _or_ 32 bit. + * 64-bit fields must be explicitly 64-bit in statfs64. + */ struct statfs { long f_type; long f_bsize; @@ -19,7 +23,22 @@ struct statfs { long f_ffree; __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_frsize; + long f_spare[5]; +}; + +struct statfs64 { + long f_type; + long f_bsize; + u64 f_blocks; + u64 f_bfree; + u64 f_bavail; + u64 f_files; + u64 f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; }; #endif diff --git a/include/asm-ppc/statfs.h b/include/asm-ppc/statfs.h index b2fd73564310..807c69954a1b 100644 --- a/include/asm-ppc/statfs.h +++ b/include/asm-ppc/statfs.h @@ -1,27 +1,7 @@ #ifndef _PPC_STATFS_H #define _PPC_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; - +#include #endif diff --git a/include/asm-ppc64/compat.h b/include/asm-ppc64/compat.h index 31e9ce210904..e4bacd3278ad 100644 --- a/include/asm-ppc64/compat.h +++ b/include/asm-ppc64/compat.h @@ -91,7 +91,8 @@ struct compat_statfs { int f_ffree; compat_fsid_t f_fsid; int f_namelen; /* SunOS ignores this field. */ - int f_spare[6]; + int f_frsize; + int f_spare[5]; }; #define COMPAT_RLIM_OLD_INFINITY 0x7fffffff diff --git a/include/asm-ppc64/statfs.h b/include/asm-ppc64/statfs.h index dc3830d054c5..7cce64bf7ee0 100644 --- a/include/asm-ppc64/statfs.h +++ b/include/asm-ppc64/statfs.h @@ -13,6 +13,9 @@ typedef __kernel_fsid_t fsid_t; #endif +/* + * We're already 64-bit, so duplicate the definition + */ struct statfs { long f_type; long f_bsize; @@ -23,7 +26,22 @@ struct statfs { long f_ffree; __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_frsize; + long f_spare[5]; +}; + +struct statfs64 { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; }; #endif /* _PPC64_STATFS_H */ diff --git a/include/asm-sparc/statfs.h b/include/asm-sparc/statfs.h index 91a19b92aa29..d623f144247d 100644 --- a/include/asm-sparc/statfs.h +++ b/include/asm-sparc/statfs.h @@ -2,25 +2,6 @@ #ifndef _SPARC_STATFS_H #define _SPARC_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; /* SunOS ignores this field. */ - long f_spare[6]; -}; +#include #endif diff --git a/include/asm-sparc64/statfs.h b/include/asm-sparc64/statfs.h index 3866255b84de..5985f1901cfc 100644 --- a/include/asm-sparc64/statfs.h +++ b/include/asm-sparc64/statfs.h @@ -20,7 +20,22 @@ struct statfs { long f_ffree; __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_frsize; + long f_spare[5]; +}; + +struct statfs64 { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; }; #endif diff --git a/include/asm-x86_64/compat.h b/include/asm-x86_64/compat.h index 63064e779369..60eb12d5cc0d 100644 --- a/include/asm-x86_64/compat.h +++ b/include/asm-x86_64/compat.h @@ -101,7 +101,8 @@ struct compat_statfs { int f_ffree; compat_fsid_t f_fsid; int f_namelen; /* SunOS ignores this field. */ - int f_spare[6]; + int f_frsize; + int f_spare[5]; }; #define COMPAT_RLIM_OLD_INFINITY 0x7fffffff diff --git a/include/asm-x86_64/statfs.h b/include/asm-x86_64/statfs.h index 2d6ea7a6b60f..bb11240c22b8 100644 --- a/include/asm-x86_64/statfs.h +++ b/include/asm-x86_64/statfs.h @@ -9,6 +9,10 @@ typedef __kernel_fsid_t fsid_t; #endif +/* + * This is ugly -- we're already 64-bit clean, so just duplicate the + * definitions. + */ struct statfs { long f_type; long f_bsize; @@ -19,7 +23,22 @@ struct statfs { long f_ffree; __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_frsize; + long f_spare[5]; +}; + +struct statfs64 { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; }; #endif diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h index 5c3fefddd4f7..e355bcacac17 100644 --- a/include/linux/coda_psdev.h +++ b/include/linux/coda_psdev.h @@ -73,7 +73,7 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, unsigned int cmd, struct PioctlData *data); int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb); int venus_fsync(struct super_block *sb, struct ViceFid *fid); -int venus_statfs(struct super_block *sb, struct statfs *sfs); +int venus_statfs(struct super_block *sb, struct kstatfs *sfs); /* messages between coda filesystem in kernel and Venus */ diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h index 808df8727891..c78e9c2a7b3a 100644 --- a/include/linux/efs_fs.h +++ b/include/linux/efs_fs.h @@ -41,7 +41,7 @@ extern struct file_operations efs_dir_operations; extern struct address_space_operations efs_symlink_aops; extern int efs_fill_super(struct super_block *, void *, int); -extern int efs_statfs(struct super_block *, struct statfs *); +extern int efs_statfs(struct super_block *, struct kstatfs *); extern void efs_read_inode(struct inode *); extern efs_block_t efs_map_block(struct inode *, efs_block_t); diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index a7f6c48a5ab9..62f37c1a17ba 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -764,7 +764,7 @@ extern void ext3_write_super (struct super_block *); extern void ext3_write_super_lockfs (struct super_block *); extern void ext3_unlockfs (struct super_block *); extern int ext3_remount (struct super_block *, int *, char *); -extern int ext3_statfs (struct super_block *, struct statfs *); +extern int ext3_statfs (struct super_block *, struct kstatfs *); #define ext3_std_error(sb, errno) \ do { \ diff --git a/include/linux/fs.h b/include/linux/fs.h index 0f79ec6c6949..c3bda88631bc 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -25,7 +25,7 @@ struct iovec; struct nameidata; struct pipe_inode_info; struct poll_table_struct; -struct statfs; +struct kstatfs; struct vm_area_struct; struct vfsmount; @@ -781,7 +781,7 @@ struct super_operations { int (*sync_fs)(struct super_block *sb, int wait); void (*write_super_lockfs) (struct super_block *); void (*unlockfs) (struct super_block *); - int (*statfs) (struct super_block *, struct statfs *); + int (*statfs) (struct super_block *, struct kstatfs *); int (*remount_fs) (struct super_block *, int *, char *); void (*clear_inode) (struct inode *); void (*umount_begin) (struct super_block *); @@ -960,7 +960,7 @@ extern struct vfsmount *kern_mount(struct file_system_type *); extern int may_umount(struct vfsmount *); extern long do_mount(char *, char *, char *, unsigned long, void *); -extern int vfs_statfs(struct super_block *, struct statfs *); +extern int vfs_statfs(struct super_block *, struct kstatfs *); /* Return value for VFS lock functions - tells locks.c to lock conventionally * REALLY kosha for root NFS and nfs_lock @@ -1278,7 +1278,7 @@ extern int dcache_dir_close(struct inode *, struct file *); extern loff_t dcache_dir_lseek(struct file *, loff_t, int); extern int dcache_readdir(struct file *, void *, filldir_t); extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *); -extern int simple_statfs(struct super_block *, struct statfs *); +extern int simple_statfs(struct super_block *, struct kstatfs *); extern int simple_link(struct dentry *, struct inode *, struct dentry *); extern int simple_unlink(struct inode *, struct dentry *); extern int simple_rmdir(struct inode *, struct dentry *); diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index 0555d7d08894..4268ed112436 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -270,7 +270,7 @@ extern void fat_clear_inode(struct inode *inode); extern void fat_put_super(struct super_block *sb); int fat_fill_super(struct super_block *sb, void *data, int silent, struct inode_operations *fs_dir_inode_ops, int isvfat); -extern int fat_statfs(struct super_block *sb, struct statfs *buf); +extern int fat_statfs(struct super_block *sb, struct kstatfs *buf); extern void fat_write_inode(struct inode *inode, int wait); extern int fat_notify_change(struct dentry * dentry, struct iattr * attr); diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 6c936cc67ec1..667e7f223a10 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -113,7 +113,7 @@ int nfsd_truncate(struct svc_rqst *, struct svc_fh *, int nfsd_readdir(struct svc_rqst *, struct svc_fh *, loff_t *, struct readdir_cd *, encode_dent_fn); int nfsd_statfs(struct svc_rqst *, struct svc_fh *, - struct statfs *); + struct kstatfs *); int nfsd_notify_change(struct inode *, struct iattr *); int nfsd_permission(struct svc_export *, struct dentry *, int); diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h index 970474550bb9..0164bd1fc109 100644 --- a/include/linux/nfsd/xdr.h +++ b/include/linux/nfsd/xdr.h @@ -113,7 +113,7 @@ struct nfsd_readdirres { }; struct nfsd_statfsres { - struct statfs stats; + struct kstatfs stats; }; /* diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h index df2de40faa23..1240afe79da9 100644 --- a/include/linux/nfsd/xdr3.h +++ b/include/linux/nfsd/xdr3.h @@ -176,7 +176,7 @@ struct nfsd3_readdirres { struct nfsd3_fsstatres { __u32 status; - struct statfs stats; + struct kstatfs stats; __u32 invarsec; }; diff --git a/include/linux/statfs.h b/include/linux/statfs.h new file mode 100644 index 000000000000..ad83a2bdb821 --- /dev/null +++ b/include/linux/statfs.h @@ -0,0 +1,22 @@ +#ifndef _LINUX_STATFS_H +#define _LINUX_STATFS_H + +#include + +#include + +struct kstatfs { + long f_type; + long f_bsize; + sector_t f_blocks; + sector_t f_bfree; + sector_t f_bavail; + sector_t f_files; + sector_t f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; +}; + +#endif diff --git a/include/linux/vfs.h b/include/linux/vfs.h index b3a58657d766..e701d0541405 100644 --- a/include/linux/vfs.h +++ b/include/linux/vfs.h @@ -1,6 +1,6 @@ #ifndef _LINUX_VFS_H #define _LINUX_VFS_H -#include +#include #endif diff --git a/kernel/acct.c b/kernel/acct.c index 9f7cdf9a826b..e63095525ac2 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -54,6 +54,7 @@ #include #include #include +#include /* sector_div */ /* * These constants control the amount of freespace that suspend and @@ -100,9 +101,11 @@ static void acct_timeout(unsigned long unused) */ static int check_free_space(struct file *file) { - struct statfs sbuf; + struct kstatfs sbuf; int res; int act; + sector_t resume; + sector_t suspend; spin_lock(&acct_globals.lock); res = acct_globals.active; @@ -113,10 +116,15 @@ static int check_free_space(struct file *file) /* May block */ if (vfs_statfs(file->f_dentry->d_inode->i_sb, &sbuf)) return res; + suspend = sbuf.f_blocks * SUSPEND; + resume = sbuf.f_blocks * RESUME; - if (sbuf.f_bavail <= SUSPEND * sbuf.f_blocks / 100) + sector_div(suspend, 100); + sector_div(resume, 100); + + if (sbuf.f_bavail <= suspend) act = -1; - else if (sbuf.f_bavail >= RESUME * sbuf.f_blocks / 100) + else if (sbuf.f_bavail >= resume) act = 1; else act = 0; diff --git a/mm/shmem.c b/mm/shmem.c index 8df99f64eb9e..239564a4e5bf 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1352,7 +1352,7 @@ static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos, return desc.error; } -static int shmem_statfs(struct super_block *sb, struct statfs *buf) +static int shmem_statfs(struct super_block *sb, struct kstatfs *buf) { struct shmem_sb_info *sbinfo = SHMEM_SB(sb); -- cgit v1.2.3 From 660a73583d38e35da377963eaa7657104ed758c1 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 20 Jun 2003 08:13:39 -0700 Subject: [PATCH] revert adjtimex changes From: John Stultz, George Anzinger, Eric Piel There was confusion over the definition of TICK_USEC. TICK_USEC is supposed to be based on USER_HZ, however a recent change caused TICK_USEC to be based on HZ. This broke the adjtimex() interface on systems where USER_HZ != HZ. This patch reverts the change to TICK_USEC, removes an added mis-use of the value and fixes some incorrect comments that could lead to this sort of confusion. Also this patch resolves the related LTP adjtimex failures. --- include/asm-i386/mach-pc9800/setup_arch_pre.h | 4 ++-- include/linux/time.h | 3 ++- include/linux/timex.h | 2 +- kernel/timer.c | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/asm-i386/mach-pc9800/setup_arch_pre.h b/include/asm-i386/mach-pc9800/setup_arch_pre.h index 47d5f0c7c140..bd53bddd6956 100644 --- a/include/asm-i386/mach-pc9800/setup_arch_pre.h +++ b/include/asm-i386/mach-pc9800/setup_arch_pre.h @@ -25,8 +25,8 @@ static inline void arch_setup_pc9800(void) { CLOCK_TICK_RATE = PC9800_8MHz_P() ? 1996800 : 2457600; printk(KERN_DEBUG "CLOCK_TICK_RATE = %d\n", CLOCK_TICK_RATE); - tick_usec = TICK_USEC; /* ACTHZ period (usec) */ - tick_nsec = TICK_NSEC; /* USER_HZ period (nsec) */ + tick_usec = TICK_USEC; /* USER_HZ period (usec) */ + tick_nsec = TICK_NSEC; /* ACTHZ period (nsec) */ pc9800_misc_flags = PC9800_MISC_FLAGS; #ifdef CONFIG_SMP diff --git a/include/linux/time.h b/include/linux/time.h index 12d0a89a4ee9..e739d8128253 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -130,7 +130,8 @@ static __inline__ unsigned long timeval_to_jiffies(struct timeval *value) { unsigned long sec = value->tv_sec; - long usec = value->tv_usec + TICK_USEC - 1; + long usec = value->tv_usec + + ((TICK_NSEC + 1000UL/2) / 1000UL) - 1; if (sec >= MAX_SEC_IN_JIFFIES){ sec = MAX_SEC_IN_JIFFIES; diff --git a/include/linux/timex.h b/include/linux/timex.h index 593cdf411500..2b1665d57ad0 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -176,7 +176,7 @@ #define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8)) /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ -#define TICK_USEC ((TICK_NSEC + 1000UL/2) / 1000UL) +#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) /* TICK_USEC_TO_NSEC is the time between ticks in nsec assuming real ACTHZ and */ /* a value TUSEC for TICK_USEC (can be set bij adjtimex) */ diff --git a/kernel/timer.c b/kernel/timer.c index 5136630693b4..ad3758c663d4 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -439,8 +439,8 @@ repeat: /* * Timekeeping variables */ -unsigned long tick_usec = TICK_USEC; /* ACTHZ period (usec) */ -unsigned long tick_nsec = TICK_NSEC; /* USER_HZ period (nsec) */ +unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */ +unsigned long tick_nsec = TICK_NSEC; /* ACTHZ period (nsec) */ /* * The current time -- cgit v1.2.3 From 0d5ff9d0ca5801ccc5dd8f1f6023629bbc6090da Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 20 Jun 2003 08:13:46 -0700 Subject: [PATCH] show_stack() portability and cleanup patch From: David Mosberger This is an attempt at sanitizing the interface for stack trace dumping somewhat. It's basically the last thing which prevents 2.5.x from working out-of-the-box for ia64. ia64 apparently cannot reasonably implement the show_stack interface declared in sched.h. Here is the rationale: modern calling conventions don't maintain a frame pointer and it's not possible to get a reliable stack trace with only a stack pointer as the starting point. You really need more machine state to start with. For a while, I thought the solution is to pass a task pointer to show_stack(), but it turns out that this would negatively impact x86 because it's sometimes useful to show only portions of a stack trace (e.g., starting from the point at which a trap occurred). Thus, this patch _adds_ the task pointer instead: extern void show_stack(struct task_struct *tsk, unsigned long *sp); The idea here is that show_stack(tsk, sp) will show the backtrace of task "tsk", starting from the stack frame that "sp" is pointing to. If tsk is NULL, the trace will be for the current task. If "sp" is NULL, all stack frames of the task are shown. If both are NULL, you'll get the full trace of the current task. I _think_ this should make everyone happy. The patch also removes the declaration of show_trace() in linux/sched.h (it never was a generic function; some platforms, in particular x86, may want to update accordingly). Finally, the patch replaces the one call to show_trace_task() with the equivalent call show_stack(task, NULL). The patch below is for Alpha and i386, since I can (compile-)test those (I'll provide the ia64 update through my regular updates). The other arches will break visibly and updating the code should be trivial: - add a task pointer argument to show_stack() and pass NULL as the first argument where needed - remove show_trace_task() - declare show_trace() in a platform-specific header file if you really want to keep it around --- arch/alpha/kernel/traps.c | 4 ++-- arch/i386/kernel/process.c | 2 +- arch/i386/kernel/traps.c | 14 +++++++------- arch/ppc64/kernel/process.c | 17 ++++++++++------- include/asm-i386/processor.h | 1 + include/linux/sched.h | 9 +++++++-- kernel/sched.c | 5 +---- 7 files changed, 29 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index ddea651cb87e..412cd3672573 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -148,7 +148,7 @@ void show_trace_task(struct task_struct * tsk) static int kstack_depth_to_print = 24; -void show_stack(unsigned long *sp) +void show_stack(struct task_struct *task, unsigned long *sp) { unsigned long *stack; int i; @@ -174,7 +174,7 @@ void show_stack(unsigned long *sp) void dump_stack(void) { - show_stack(NULL); + show_stack(NULL, NULL); } void diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 8cb6adb50b8a..61bc3326e287 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -190,7 +190,7 @@ void show_regs(struct pt_regs * regs) ".previous \n" : "=r" (cr4): "0" (0)); printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); - show_trace(®s->esp); + show_trace(NULL, ®s->esp); } /* diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index c6bc1936f45b..7fcedfd5cc4b 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -32,9 +32,9 @@ #ifdef CONFIG_MCA #include -#include #endif +#include #include #include #include @@ -92,7 +92,7 @@ asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; -void show_trace(unsigned long * stack) +void show_trace(struct task_struct *task, unsigned long * stack) { int i; unsigned long addr; @@ -122,10 +122,10 @@ void show_trace_task(struct task_struct *tsk) /* User space on another CPU? */ if ((esp ^ (unsigned long)tsk->thread_info) & (PAGE_MASK<<1)) return; - show_trace((unsigned long *)esp); + show_trace(tsk, (unsigned long *)esp); } -void show_stack(unsigned long * esp) +void show_stack(struct task_struct *task, unsigned long * esp) { unsigned long *stack; int i; @@ -145,7 +145,7 @@ void show_stack(unsigned long * esp) printk("%08lx ", *stack++); } printk("\n"); - show_trace(esp); + show_trace(task, esp); } /* @@ -155,7 +155,7 @@ void dump_stack(void) { unsigned long stack; - show_trace(&stack); + show_trace(current, &stack); } void show_registers(struct pt_regs *regs) @@ -192,7 +192,7 @@ void show_registers(struct pt_regs *regs) if (in_kernel) { printk("\nStack: "); - show_stack((unsigned long*)esp); + show_stack(NULL, (unsigned long*)esp); printk("Code: "); if(regs->eip < PAGE_OFFSET) diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index 949425d44cb3..c22a54fe544f 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -129,7 +129,6 @@ struct task_struct *__switch_to(struct task_struct *prev, return last; } -static void show_tsk_stack(struct task_struct *p, unsigned long sp); char *ppc_find_proc_name(unsigned *p, char *buf, unsigned buflen); void show_regs(struct pt_regs * regs) @@ -172,7 +171,7 @@ void show_regs(struct pt_regs * regs) printk("NIP [%016lx] ", regs->nip); printk("%s\n", ppc_find_proc_name((unsigned *)regs->nip, name_buf, 256)); - show_tsk_stack(current, regs->gpr[1]); + show_stack(current, (unsigned long *)regs->gpr[1]); } void exit_thread(void) @@ -517,22 +516,26 @@ unsigned long get_wchan(struct task_struct *p) return 0; } -static void show_tsk_stack(struct task_struct *p, unsigned long sp) +void show_stack(struct task_struct *p, unsigned long *_sp) { unsigned long ip; unsigned long stack_page = (unsigned long)p->thread_info; int count = 0; char name_buf[256]; + unsigned long sp = (unsigned long)_sp; if (!p) return; + if (sp == 0) + sp = p->thread.ksp; printk("Call Trace:\n"); do { if (__get_user(sp, (unsigned long *)sp)) break; - if (sp < (stack_page + sizeof(struct thread_struct)) || - sp >= (stack_page + THREAD_SIZE)) + if (sp < stack_page + sizeof(struct thread_struct)) + break; + if (sp >= stack_page + THREAD_SIZE) break; if (__get_user(ip, (unsigned long *)(sp + 16))) break; @@ -544,10 +547,10 @@ static void show_tsk_stack(struct task_struct *p, unsigned long sp) void dump_stack(void) { - show_tsk_stack(current, (unsigned long)_get_SP()); + show_stack(current, (unsigned long *)_get_SP()); } void show_trace_task(struct task_struct *tsk) { - show_tsk_stack(tsk, tsk->thread.ksp); + show_stack(tsk, (unsigned long *)tsk->thread.ksp); } diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 770938129032..ac14135d83ba 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -468,6 +468,7 @@ extern void prepare_to_copy(struct task_struct *tsk); extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern unsigned long thread_saved_pc(struct task_struct *tsk); +void show_trace(struct task_struct *task, unsigned long *stack); unsigned long get_wchan(struct task_struct *p); #define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1019]) diff --git a/include/linux/sched.h b/include/linux/sched.h index d313e2ccbf42..f5cdfefc5b05 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -148,10 +148,15 @@ extern void sched_init(void); extern void init_idle(task_t *idle, int cpu); extern void show_state(void); -extern void show_trace(unsigned long *stack); -extern void show_stack(unsigned long *stack); extern void show_regs(struct pt_regs *); +/* + * TASK is a pointer to the task whose backtrace we want to see (or NULL for current + * task), SP is the stack pointer of the first frame that should be shown in the back + * trace (or NULL if the entire call-chain of the task should be shown). + */ +extern void show_stack(struct task_struct *task, unsigned long *sp); + void io_schedule(void); long io_schedule_timeout(long timeout); diff --git a/kernel/sched.c b/kernel/sched.c index c603aaa67790..aa79183f1453 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2182,10 +2182,7 @@ static void show_task(task_t * p) else printk(" (NOTLB)\n"); - { - extern void show_trace_task(task_t *tsk); - show_trace_task(p); - } + show_stack(p, NULL); } void show_state(void) -- cgit v1.2.3 From 1327ca85e19e5ea19c9fcab0b54f093ddaaca31a Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 20 Jun 2003 08:13:53 -0700 Subject: [PATCH] sysv semundo fixes From: Manfred Spraul The CLONE_SYSVSEM implementation is racy: it does an (atomic_read(->refcnt) ==1) instead of atomic_dec_and_test calls in the exit handling. The patch fixes that. Additionally, the patch contains the following changes: - lock_undo() locks the list of undo structures. The lock is held throughout the semop() syscall, but that's unnecessary - we can drop it immediately after the lookup. - undo structures are only allocated when necessary. The need for undo structures is only noticed in the middle of the semop operation, while holding the semaphore array spinlock. The result is a convoluted unlock&revalidate implementation. I've reordered the code, and now the undo allocation can happen before acquiring the semaphore array spinlock. As a bonus, less code runs under the semaphore array spinlock. - sysvsem.sleep_list looks like code to handle oopses: if an oops kills a thread that sleeps in sys_timedsemop(), then sem_exit tries to recover. I've removed that - too fragile. --- include/linux/sem.h | 4 +- ipc/sem.c | 298 +++++++++++++++++++++------------------------------- ipc/util.c | 8 +- kernel/exit.c | 2 +- kernel/fork.c | 4 +- 5 files changed, 128 insertions(+), 188 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sem.h b/include/linux/sem.h index 38a64f8ea69b..2821bc07f647 100644 --- a/include/linux/sem.h +++ b/include/linux/sem.h @@ -128,13 +128,11 @@ struct sem_undo { struct sem_undo_list { atomic_t refcnt; spinlock_t lock; - volatile unsigned long add_count; struct sem_undo *proc_list; }; struct sysv_sem { struct sem_undo_list *undo_list; - struct sem_queue *sleep_list; }; asmlinkage long sys_semget (key_t key, int nsems, int semflg); @@ -143,6 +141,8 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg); asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, unsigned nsops, const struct timespec __user *timeout); +void exit_sem(struct task_struct *p); + #endif /* __KERNEL__ */ #endif /* _LINUX_SEM_H */ diff --git a/ipc/sem.c b/ipc/sem.c index 991831da7f11..07d9a2e054b7 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -214,7 +214,7 @@ static int sem_revalidate(int semid, struct sem_array* sma, int nsems, short flg return -EIDRM; } - if (ipcperms(&sma->sem_perm, flg)) { + if (flg && ipcperms(&sma->sem_perm, flg)) { sem_unlock(smanew); return -EACCES; } @@ -412,7 +412,7 @@ static void freeary (struct sem_array *sma, int id) int size; /* Invalidate the existing undo structures for this semaphore set. - * (They will be freed without any further action in sem_exit() + * (They will be freed without any further action in exit_sem() * or during the next semop.) */ for (un = sma->undo; un; un = un->id_next) @@ -887,106 +887,87 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp) return 0; } -static struct sem_undo* freeundos(struct sem_undo* un) +static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) { - struct sem_undo* u; - struct sem_undo** up; - - for(up = ¤t->sysvsem.undo_list->proc_list;(u=*up);up=&u->proc_next) { - if(un==u) { - un=u->proc_next; - *up=un; - kfree(u); - return un; - } - } - printk ("freeundos undo list error id=%d\n", un->semid); - return un->proc_next; -} + struct sem_undo **last, *un; -static inline struct sem_undo *find_undo(int semid) -{ - struct sem_undo *un; - - un = NULL; - if (current->sysvsem.undo_list != NULL) { - un = current->sysvsem.undo_list->proc_list; - } + last = &ulp->proc_list; + un = *last; while(un != NULL) { if(un->semid==semid) break; - if(un->semid==-1) - un=freeundos(un); - else - un=un->proc_next; + if(un->semid==-1) { + *last=un->proc_next; + kfree(un); + } else { + last=&un->proc_next; + } + un=*last; } return un; } -/* returns without sem_lock and semundo list locks on error! */ -static int alloc_undo(struct sem_array *sma, struct sem_undo** unp, int semid, int alter) +static struct sem_undo *find_undo(int semid) { - int size, nsems, error; - struct sem_undo *un, *new_un; - struct sem_undo_list *undo_list; - unsigned long saved_add_count; + struct sem_array *sma; + struct sem_undo_list *ulp; + struct sem_undo *un, *new; + int nsems; + int error; + error = get_undo_list(&ulp); + if (error) + return ERR_PTR(error); - nsems = sma->sem_nsems; - saved_add_count = 0; - if (current->sysvsem.undo_list != NULL) - saved_add_count = current->sysvsem.undo_list->add_count; - sem_unlock(sma); + lock_semundo(); + un = lookup_undo(ulp, semid); unlock_semundo(); + if (likely(un!=NULL)) + goto out; - error = get_undo_list(&undo_list); - if (error) - return error; + /* no undo structure around - allocate one. */ + sma = sem_lock(semid); + un = ERR_PTR(-EINVAL); + if(sma==NULL) + goto out; + un = ERR_PTR(-EIDRM); + if (sem_checkid(sma,semid)) + goto out_unlock; + nsems = sma->sem_nsems; + sem_unlock(sma); - size = sizeof(struct sem_undo) + sizeof(short)*nsems; - un = (struct sem_undo *) kmalloc(size, GFP_KERNEL); - if (!un) - return -ENOMEM; + new = (struct sem_undo *) kmalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); + if (!new) + return ERR_PTR(-ENOMEM); + memset(new, 0, sizeof(struct sem_undo) + sizeof(short)*nsems); + new->semadj = (short *) &new[1]; + new->semid = semid; - memset(un, 0, size); lock_semundo(); - error = sem_revalidate(semid, sma, nsems, alter ? S_IWUGO : S_IRUGO); - if(error) { + un = lookup_undo(ulp, semid); + if (un) { unlock_semundo(); - kfree(un); - return error; + kfree(new); + goto out; } - - - /* alloc_undo has just - * released all locks and reacquired them. - * But, another thread may have - * added the semundo we were looking for - * during that time. - * So, we check for it again. - * only initialize and add the new one - * if we don't discover one. - */ - new_un = NULL; - if (current->sysvsem.undo_list->add_count != saved_add_count) - new_un = find_undo(semid); - - if (new_un != NULL) { - if (sma->undo != new_un) - BUG(); - kfree(un); - un = new_un; - } else { - current->sysvsem.undo_list->add_count++; - un->semadj = (short *) &un[1]; - un->semid = semid; - un->proc_next = undo_list->proc_list; - undo_list->proc_list = un; - un->id_next = sma->undo; - sma->undo = un; + error = sem_revalidate(semid, sma, nsems, 0); + if (error) { + sem_unlock(sma); + unlock_semundo(); + kfree(new); + un = ERR_PTR(error); + goto out; } - *unp = un; - return 0; + new->proc_next = ulp->proc_list; + ulp->proc_list = new; + new->id_next = sma->undo; + sma->undo = new; + sem_unlock(sma); + un = new; +out_unlock: + unlock_semundo(); +out: + return un; } asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops) @@ -1002,7 +983,7 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops, struct sembuf fast_sops[SEMOPM_FAST]; struct sembuf* sops = fast_sops, *sop; struct sem_undo *un; - int undos = 0, decrease = 0, alter = 0; + int undos = 0, decrease = 0, alter = 0, max; struct sem_queue queue; unsigned long jiffies_left = 0; @@ -1032,18 +1013,10 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops, } jiffies_left = timespec_to_jiffies(&_timeout); } - lock_semundo(); - sma = sem_lock(semid); - error=-EINVAL; - if(sma==NULL) - goto out_semundo_free; - error = -EIDRM; - if (sem_checkid(sma,semid)) - goto out_unlock_semundo_free; - error = -EFBIG; + max = 0; for (sop = sops; sop < sops + nsops; sop++) { - if (sop->sem_num >= sma->sem_nsems) - goto out_unlock_semundo_free; + if (sop->sem_num >= max) + max = sop->sem_num; if (sop->sem_flg & SEM_UNDO) undos++; if (sop->sem_op < 0) @@ -1053,30 +1026,42 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops, } alter |= decrease; - error = -EACCES; - if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) - goto out_unlock_semundo_free; - - error = security_sem_semop(sma, sops, nsops, alter); - if (error) - goto out_unlock_semundo_free; - - error = -EACCES; +retry_undos: if (undos) { - /* Make sure we have an undo structure - * for this process and this semaphore set. - */ - un = find_undo(semid); - if (!un) { - error = alloc_undo(sma,&un,semid,alter); - if (error) - goto out_free; - + if (IS_ERR(un)) { + error = PTR_ERR(un); + goto out_free; } } else un = NULL; + sma = sem_lock(semid); + error=-EINVAL; + if(sma==NULL) + goto out_free; + error = -EIDRM; + if (sem_checkid(sma,semid)) + goto out_unlock_free; + /* + * semid identifies are not unique - find_undo may have + * allocated an undo structure, it was invalidated by an RMID + * and now a new array with received the same id. Check and retry. + */ + if (un && un->semid == -1) + goto retry_undos; + error = -EFBIG; + if (max >= sma->sem_nsems) + goto out_unlock_free; + + error = -EACCES; + if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) + goto out_unlock_free; + + error = security_sem_semop(sma, sops, nsops, alter); + if (error) + goto out_unlock_free; + error = try_atomic_semop (sma, sops, nsops, un, current->pid, 0); if (error <= 0) goto update; @@ -1096,28 +1081,24 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops, append_to_queue(sma ,&queue); else prepend_to_queue(sma ,&queue); - current->sysvsem.sleep_list = &queue; for (;;) { queue.status = -EINTR; queue.sleeper = current; current->state = TASK_INTERRUPTIBLE; sem_unlock(sma); - unlock_semundo(); if (timeout) jiffies_left = schedule_timeout(jiffies_left); else schedule(); - lock_semundo(); sma = sem_lock(semid); if(sma==NULL) { if(queue.prev != NULL) BUG(); - current->sysvsem.sleep_list = NULL; error = -EIDRM; - goto out_semundo_free; + goto out_free; } /* * If queue.status == 1 we where woken up and @@ -1139,19 +1120,15 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops, if (queue.prev) /* got Interrupt */ break; /* Everything done by update_queue */ - current->sysvsem.sleep_list = NULL; - goto out_unlock_semundo_free; + goto out_unlock_free; } } - current->sysvsem.sleep_list = NULL; remove_from_queue(sma,&queue); update: if (alter) update_queue (sma); -out_unlock_semundo_free: +out_unlock_free: sem_unlock(sma); -out_semundo_free: - unlock_semundo(); out_free: if(sops != fast_sops) kfree(sops); @@ -1185,21 +1162,6 @@ int copy_semundo(unsigned long clone_flags, struct task_struct *tsk) return 0; } -static inline void __exit_semundo(struct task_struct *tsk) -{ - struct sem_undo_list *undo_list; - - undo_list = tsk->sysvsem.undo_list; - if (!atomic_dec_and_test(&undo_list->refcnt)) - kfree(undo_list); -} - -void exit_semundo(struct task_struct *tsk) -{ - if (tsk->sysvsem.undo_list != NULL) - __exit_semundo(tsk); -} - /* * add semadj values to semaphores, free undo structures. * undo structures are not freed when semaphore arrays are destroyed @@ -1212,44 +1174,29 @@ void exit_semundo(struct task_struct *tsk) * The current implementation does not do so. The POSIX standard * and SVID should be consulted to determine what behavior is mandated. */ -void sem_exit (void) +void exit_sem(struct task_struct *tsk) { - struct sem_queue *q; - struct sem_undo *u, *un = NULL, **up, **unp; - struct sem_array *sma; struct sem_undo_list *undo_list; - int nsems, i; - - lock_kernel(); - - /* If the current process was sleeping for a semaphore, - * remove it from the queue. - */ - if ((q = current->sysvsem.sleep_list)) { - int semid = q->id; - sma = sem_lock(semid); - current->sysvsem.sleep_list = NULL; + struct sem_undo *u, **up; - if (q->prev) { - if(sma==NULL) - BUG(); - remove_from_queue(q->sma,q); - } - if(sma!=NULL) - sem_unlock(sma); - } + undo_list = tsk->sysvsem.undo_list; + if (!undo_list) + return; - undo_list = current->sysvsem.undo_list; - if ((undo_list == NULL) || (atomic_read(&undo_list->refcnt) != 1)) { - unlock_kernel(); + if (!atomic_dec_and_test(&undo_list->refcnt)) return; - } /* There's no need to hold the semundo list lock, as current * is the last task exiting for this undo list. */ for (up = &undo_list->proc_list; (u = *up); *up = u->proc_next, kfree(u)) { - int semid = u->semid; + struct sem_array *sma; + int nsems, i; + struct sem_undo *un, **unp; + int semid; + + semid = u->semid; + if(semid == -1) continue; sma = sem_lock(semid); @@ -1259,15 +1206,14 @@ void sem_exit (void) if (u->semid == -1) goto next_entry; - if (sem_checkid(sma,u->semid)) - goto next_entry; + BUG_ON(sem_checkid(sma,u->semid)); /* remove u from the sma->undo list */ for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { if (u == un) goto found; } - printk ("sem_exit undo list error id=%d\n", u->semid); + printk ("exit_sem undo list error id=%d\n", u->semid); goto next_entry; found: *unp = un->id_next; @@ -1275,10 +1221,12 @@ found: nsems = sma->sem_nsems; for (i = 0; i < nsems; i++) { struct sem * sem = &sma->sem_base[i]; - sem->semval += u->semadj[i]; - if (sem->semval < 0) - sem->semval = 0; /* shouldn't happen */ - sem->sempid = current->pid; + if (u->semadj[i]) { + sem->semval += u->semadj[i]; + if (sem->semval < 0) + sem->semval = 0; /* shouldn't happen */ + sem->sempid = current->pid; + } } sma->sem_otime = get_seconds(); /* maybe some queued-up processes were waiting for this */ @@ -1286,9 +1234,7 @@ found: next_entry: sem_unlock(sma); } - __exit_semundo(current); - - unlock_kernel(); + kfree(undo_list); } #ifdef CONFIG_PROC_FS diff --git a/ipc/util.c b/ipc/util.c index a2f4c3b1c680..b1e76464b850 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -541,17 +541,11 @@ int copy_semundo(unsigned long clone_flags, struct task_struct *tsk) return 0; } -void exit_semundo(struct task_struct *tsk) +void exit_sem(struct task_struct *tsk) { return; } - -void sem_exit (void) -{ - return; -} - asmlinkage long sys_semget (key_t key, int nsems, int semflg) { return -ENOSYS; diff --git a/kernel/exit.c b/kernel/exit.c index c5b8ec241a83..7dee095b31bd 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -698,7 +698,7 @@ NORET_TYPE void do_exit(long code) acct_process(code); __exit_mm(tsk); - sem_exit(); + exit_sem(tsk); __exit_files(tsk); __exit_fs(tsk); exit_namespace(tsk); diff --git a/kernel/fork.c b/kernel/fork.c index 0fe154adc3ef..5ef2dca02354 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -39,7 +39,7 @@ #include extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk); -extern void exit_semundo(struct task_struct *tsk); +extern void exit_sem(struct task_struct *tsk); /* The idle threads do not count.. * Protected by write_lock_irq(&tasklist_lock) @@ -1032,7 +1032,7 @@ bad_fork_cleanup_fs: bad_fork_cleanup_files: exit_files(p); /* blocking */ bad_fork_cleanup_semundo: - exit_semundo(p); + exit_sem(p); bad_fork_cleanup_security: security_task_free(p); bad_fork_cleanup: -- cgit v1.2.3 From 7872c516b80e6a01e9368c2c524291f1f544be5e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 20 Jun 2003 08:14:11 -0700 Subject: [PATCH] hugetlbfs: specify size & inodes at mount From: "Seth, Rohit" - Add support for setting the filesystem's maximum size and maximum inode count on the mount command line. This is needed because the system admin can now set the ownership of teh fs to non-root users. We don't want those users to be able to use all of the hugepage pool. - Prroperly update the inode creation/modification time. - Set the blocksize to HPAGE_SIZE (instead of PAGE_CACHE_SIZE). - Update Documentation/vm/hugetlbpage.txt. --- Documentation/vm/hugetlbpage.txt | 11 +- fs/hugetlbfs/inode.c | 237 +++++++++++++++++++++++++++++++++------ include/linux/hugetlb.h | 23 +++- 3 files changed, 231 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index f39e2bb310cb..55b3cc0efda3 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -68,14 +68,21 @@ call, then it is required that system administrator mount a file system of type hugetlbfs: mount none /mnt/huge -t hugetlbfs + This command mounts a (pseudo) filesystem of type hugetlbfs on the directory /mnt/huge. Any files created on /mnt/huge uses hugepages. The uid and gid options sets the owner and group of the root of the file system. By default the uid and gid of the current process are taken. The mode option sets the mode of root of file system to value & 0777. This value is given in octal. -By default the value 0755 is picked. An example is given at the end of this -document. +By default the value 0755 is picked. The size option sets the maximum value of +memory (huge pages) allowed for that filesystem (/mnt/huge). The size is +rounded down to HPAGE_SIZE. The option nr_inode sets the maximum number of +inodes that /mnt/huge can use. If the size or nr_inode options are not +provided on command line then no limits are set. For size and nr_inodes +options, you can use [G|g]/[M|m]/[K|k] to represent giga/mega/kilo. For +example, size=2K has the same meaning as size=2048. An example is given at +the end of this document. read and write system calls are not supported on files that reside on hugetlb file systems. diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 4c83c32a1905..9781a30bbb09 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -22,10 +22,12 @@ #include #include #include +#include #include #include #include +#include /* some random number */ #define HUGETLBFS_MAGIC 0x958458f6 @@ -43,8 +45,9 @@ static struct backing_dev_info hugetlbfs_backing_dev_info = { static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) { - struct inode *inode =file->f_dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(inode->i_sb); loff_t len; int ret; @@ -57,6 +60,18 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) if (vma->vm_end - vma->vm_start < HPAGE_SIZE) return -EINVAL; + len = (loff_t)(vma->vm_end - vma->vm_start); + if (sbinfo->free_blocks >= 0) { /* Check if there is any size limit. */ + spin_lock(&sbinfo->stat_lock); + if ((len >> HPAGE_SHIFT) <= sbinfo->free_blocks) { + sbinfo->free_blocks -= (len >> HPAGE_SHIFT); + spin_unlock(&sbinfo->stat_lock); + } else { + spin_unlock(&sbinfo->stat_lock); + return -ENOMEM; + } + } + down(&inode->i_sem); update_atime(inode); @@ -68,6 +83,16 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) if (ret == 0 && inode->i_size < len) inode->i_size = len; up(&inode->i_sem); + + /* + * If the huge page allocation has failed then increment free_blocks. + */ + if ((ret != 0) && (sbinfo->free_blocks >= 0)) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_blocks += (len >> HPAGE_SHIFT); + spin_unlock(&sbinfo->stat_lock); + } + return ret; } @@ -154,6 +179,7 @@ void truncate_huge_page(struct page *page) void truncate_hugepages(struct address_space *mapping, loff_t lstart) { + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb); const pgoff_t start = lstart >> HPAGE_SHIFT; struct pagevec pvec; pgoff_t next; @@ -178,6 +204,11 @@ void truncate_hugepages(struct address_space *mapping, loff_t lstart) ++next; truncate_huge_page(page); unlock_page(page); + if (sbinfo->free_blocks >= 0) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_blocks++; + spin_unlock(&sbinfo->stat_lock); + } } huge_pagevec_release(&pvec); } @@ -186,6 +217,8 @@ void truncate_hugepages(struct address_space *mapping, loff_t lstart) static void hugetlbfs_delete_inode(struct inode *inode) { + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(inode->i_sb); + hlist_del_init(&inode->i_hash); list_del_init(&inode->i_list); inode->i_state |= I_FREEING; @@ -197,6 +230,12 @@ static void hugetlbfs_delete_inode(struct inode *inode) security_inode_delete(inode); + if (sbinfo->free_inodes >= 0) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_inodes++; + spin_unlock(&sbinfo->stat_lock); + } + clear_inode(inode); destroy_inode(inode); } @@ -204,6 +243,7 @@ static void hugetlbfs_delete_inode(struct inode *inode) static void hugetlbfs_forget_inode(struct inode *inode) { struct super_block *super_block = inode->i_sb; + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(super_block); if (hlist_unhashed(&inode->i_hash)) goto out_truncate; @@ -229,6 +269,12 @@ out_truncate: if (inode->i_data.nrpages) truncate_hugepages(&inode->i_data, 0); + if (sbinfo->free_inodes >= 0) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_inodes++; + spin_unlock(&sbinfo->stat_lock); + } + clear_inode(inode); destroy_inode(inode); } @@ -341,13 +387,25 @@ out: static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, gid_t gid, int mode, dev_t dev) { - struct inode * inode = new_inode(sb); + struct inode *inode; + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb); + + if (sbinfo->free_inodes >= 0) { + spin_lock(&sbinfo->stat_lock); + if (!sbinfo->free_inodes) { + spin_unlock(&sbinfo->stat_lock); + return NULL; + } + sbinfo->free_inodes--; + spin_unlock(&sbinfo->stat_lock); + } + inode = new_inode(sb); if (inode) { inode->i_mode = mode; inode->i_uid = uid; inode->i_gid = gid; - inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blksize = HPAGE_SIZE; inode->i_blocks = 0; inode->i_rdev = NODEV; inode->i_mapping->a_ops = &hugetlbfs_aops; @@ -379,17 +437,18 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, /* * File creation. Allocate an inode, and we're done.. */ -/* SMP-safe */ static int hugetlbfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { - struct inode * inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, + struct inode *inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, current->fsgid, mode, dev); int error = -ENOSPC; if (inode) { + dir->i_size += PSEUDO_DIRENT_SIZE; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; d_instantiate(dentry, inode); - dget(dentry); /* Extra count - pin the dentry in core */ + dget(dentry); /* Extra count - pin the dentry in core */ error = 0; } return error; @@ -425,6 +484,9 @@ static int hugetlbfs_symlink(struct inode *dir, } else iput(inode); } + dir->i_size += PSEUDO_DIRENT_SIZE; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + return error; } @@ -436,6 +498,83 @@ int hugetlbfs_set_page_dirty(struct page *page) return 0; } +static int hugetlbfs_statfs(struct super_block *sb, struct statfs *buf) +{ + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb); + + buf->f_type = HUGETLBFS_MAGIC; + buf->f_bsize = HPAGE_SIZE; + if (sbinfo) { + spin_lock(&sbinfo->stat_lock); + buf->f_blocks = sbinfo->max_blocks; + buf->f_bavail = buf->f_bfree = sbinfo->free_blocks; + buf->f_files = sbinfo->max_inodes; + buf->f_ffree = sbinfo->free_inodes; + spin_unlock(&sbinfo->stat_lock); + } + buf->f_namelen = NAME_MAX; + return 0; +} + +static int hugetlbfs_link(struct dentry *old_dentry, + struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = old_dentry->d_inode; + + dir->i_size += PSEUDO_DIRENT_SIZE; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + inode->i_nlink++; + atomic_inc(&inode->i_count); + dget(dentry); + d_instantiate(dentry, inode); + return 0; +} + +static int hugetlbfs_unlink(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + + dir->i_size -= PSEUDO_DIRENT_SIZE; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + inode->i_nlink--; + dput(dentry); + return 0; +} + +static int hugetlbfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + if (!simple_empty(dentry)) + return -ENOTEMPTY; + + dir->i_nlink--; + return hugetlbfs_unlink(dir, dentry); +} + +static int hugetlbfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct inode *inode = old_dentry->d_inode; + int they_are_dirs = S_ISDIR(inode->i_mode); + + if (!simple_empty(new_dentry)) + return -ENOTEMPTY; + + if (new_dentry->d_inode) { + hugetlbfs_unlink(new_dir, new_dentry); + if (they_are_dirs) + old_dir->i_nlink--; + } else if (they_are_dirs) { + old_dir->i_nlink--; + new_dir->i_nlink++; + } + + old_dir->i_size -= PSEUDO_DIRENT_SIZE; + new_dir->i_size += PSEUDO_DIRENT_SIZE; + old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime = + new_dir->i_mtime = inode->i_ctime = CURRENT_TIME; + return 0; +} + static struct address_space_operations hugetlbfs_aops = { .readpage = hugetlbfs_readpage, .prepare_write = hugetlbfs_prepare_write, @@ -452,13 +591,13 @@ struct file_operations hugetlbfs_file_operations = { static struct inode_operations hugetlbfs_dir_inode_operations = { .create = hugetlbfs_create, .lookup = simple_lookup, - .link = simple_link, - .unlink = simple_unlink, + .link = hugetlbfs_link, + .unlink = hugetlbfs_unlink, .symlink = hugetlbfs_symlink, .mkdir = hugetlbfs_mkdir, - .rmdir = simple_rmdir, + .rmdir = hugetlbfs_rmdir, .mknod = hugetlbfs_mknod, - .rename = simple_rename, + .rename = hugetlbfs_rename, .setattr = hugetlbfs_setattr, }; @@ -467,29 +606,26 @@ static struct inode_operations hugetlbfs_inode_operations = { }; static struct super_operations hugetlbfs_ops = { - .statfs = simple_statfs, + .statfs = hugetlbfs_statfs, .drop_inode = hugetlbfs_drop_inode, }; static int hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) { - char *opt, *value; - int ret = 0; + char *opt, *value, *rest; if (!options) - goto out; + return 0; while ((opt = strsep(&options, ",")) != NULL) { if (!*opt) continue; value = strchr(opt, '='); - if (!value || !*value) { - ret = -EINVAL; - goto out; - } else { + if (!value || !*value) + return -EINVAL; + else *value++ = '\0'; - } if (!strcmp(opt, "uid")) pconfig->uid = simple_strtoul(value, &value, 0); @@ -497,22 +633,27 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) pconfig->gid = simple_strtoul(value, &value, 0); else if (!strcmp(opt, "mode")) pconfig->mode = simple_strtoul(value,&value,0) & 0777U; - else { - ret = -EINVAL; - goto out; - } + else if (!strcmp(opt, "size")) { + unsigned long long size = memparse(value, &rest); + if (*rest == '%') { + size <<= HPAGE_SHIFT; + size *= htlbpage_max; + do_div(size, 100); + rest++; + } + size &= HPAGE_MASK; + pconfig->nr_blocks = (size >> HPAGE_SHIFT); + value = rest; + } else if (!strcmp(opt,"nr_inodes")) { + pconfig->nr_inodes = memparse(value, &rest); + value = rest; + } else + return -EINVAL; - if (*value) { - ret = -EINVAL; - goto out; - } + if (*value) + return -EINVAL; } return 0; -out: - pconfig->uid = current->fsuid; - pconfig->gid = current->fsgid; - pconfig->mode = 0755; - return ret; } static int @@ -522,13 +663,30 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) struct dentry * root; int ret; struct hugetlbfs_config config; + struct hugetlbfs_sb_info *sbinfo; + + sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL); + if (!sbinfo) + return -ENOMEM; + sb->s_fs_info = sbinfo; + config.nr_blocks = -1; /* No limit on size by default */ + config.nr_inodes = -1; /* No limit on number of inodes by default */ + config.uid = current->fsuid; + config.gid = current->fsgid; + config.mode = 0755; ret = hugetlbfs_parse_options(data, &config); + if (ret) return ret; - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + spin_lock_init(&sbinfo->stat_lock); + sbinfo->max_blocks = config.nr_blocks; + sbinfo->free_blocks = config.nr_blocks; + sbinfo->max_inodes = config.nr_inodes; + sbinfo->free_inodes = config.nr_inodes; + sb->s_blocksize = HPAGE_SIZE; + sb->s_blocksize_bits = HPAGE_SHIFT; sb->s_magic = HUGETLBFS_MAGIC; sb->s_op = &hugetlbfs_ops; inode = hugetlbfs_get_inode(sb, config.uid, config.gid, @@ -551,10 +709,19 @@ static struct super_block *hugetlbfs_get_sb(struct file_system_type *fs_type, return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super); } +static void hugetlbfs_kill_super(struct super_block *sb) +{ + if (sb) { + if(sb->s_fs_info) + kfree(sb->s_fs_info); + kill_litter_super(sb); + } +} + static struct file_system_type hugetlbfs_fs_type = { .name = "hugetlbfs", .get_sb = hugetlbfs_get_sb, - .kill_sb = kill_litter_super, + .kill_sb = hugetlbfs_kill_super }; static struct vfsmount *hugetlbfs_vfsmount; diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 266762203a70..edc512ee628f 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -73,11 +73,28 @@ static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) #ifdef CONFIG_HUGETLBFS struct hugetlbfs_config { - uid_t uid; - gid_t gid; - umode_t mode; + uid_t uid; + gid_t gid; + umode_t mode; + long nr_blocks; + long nr_inodes; }; +struct hugetlbfs_sb_info { + long max_blocks; /* blocks allowed */ + long free_blocks; /* blocks free */ + long max_inodes; /* inodes allowed */ + long free_inodes; /* inodes free */ + spinlock_t stat_lock; +}; + +static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb) +{ + return sb->s_fs_info; +} + +#define PSEUDO_DIRENT_SIZE 20 + extern struct file_operations hugetlbfs_file_operations; extern struct vm_operations_struct hugetlb_vm_ops; struct file *hugetlb_zero_setup(size_t); -- cgit v1.2.3 From 95ea8516e903ca4ad248714bd0f616972404912e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 20 Jun 2003 08:14:24 -0700 Subject: [PATCH] misc fixes - shmem: remove unneeded test for null inode->i_sb (James Morris) - kill unused var warning in traps.c (Geert Uytterhoeven) - s/u64/__u64/ in bitops.h (needed for klibc) - comment fix in gfp.h (Matthew Dobson ) - fix smbfs constant overflow warning (Flameeyes ) - yam.c irqreturn_t fix. - Remove some unused variables from baycom_epp.c (Adrian Bunk) - Remove 5-year-old unreferenced RCS string from xirc2ps_cs.c (Adrian Bunk) --- arch/i386/kernel/traps.c | 2 -- drivers/net/hamradio/baycom_epp.c | 2 -- drivers/net/hamradio/yam.c | 12 ++++++++---- drivers/net/pcmcia/xirc2ps_cs.c | 4 +--- include/linux/bitops.h | 2 +- include/linux/gfp.h | 2 +- include/linux/smbno.h | 4 ++-- mm/shmem.c | 2 +- 8 files changed, 14 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 7fcedfd5cc4b..5a7a28deb04a 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -94,7 +94,6 @@ static int kstack_depth_to_print = 24; void show_trace(struct task_struct *task, unsigned long * stack) { - int i; unsigned long addr; if (!stack) @@ -104,7 +103,6 @@ void show_trace(struct task_struct *task, unsigned long * stack) #ifdef CONFIG_KALLSYMS printk("\n"); #endif - i = 1; while (((long) stack & (THREAD_SIZE-1)) != 0) { addr = *stack++; if (kernel_text_address(addr)) { diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 0842e54df8bd..26ac864936e8 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -376,7 +376,6 @@ static int eppconfig(struct baycom_state *bc) char portarg[16]; char *argv[] = { eppconfig_path, "-s", "-p", portarg, "-m", modearg, NULL }; - int ret; /* set up arguments */ sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat", @@ -1164,7 +1163,6 @@ static int baycom_setmode(struct baycom_state *bc, const char *modestr) static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct baycom_state *bc; - struct baycom_ioctl bi; struct hdlcdrv_ioctl hi; baycom_paranoia_check(dev, "baycom_ioctl", -EINVAL); diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index ce3bd5f5e30d..e4d961b00eda 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -721,7 +721,7 @@ static irqreturn_t yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned char iir; int counter = 100; int i; - + int handled = 0; for (i = 0; i < NR_PORTS; i++) { yp = &yam_ports[i]; @@ -735,14 +735,17 @@ static irqreturn_t yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned char lsr = inb(LSR(dev->base_addr)); unsigned char rxb; + handled = 1; + if (lsr & LSR_OE) ++yp->stats.rx_fifo_errors; yp->dcd = (msr & RX_DCD) ? 1 : 0; if (--counter <= 0) { - printk(KERN_ERR "%s: too many irq iir=%d\n", dev->name, iir); - return; + printk(KERN_ERR "%s: too many irq iir=%d\n", + dev->name, iir); + goto out; } if (msr & TX_RDY) { ++yp->nb_mdint; @@ -758,7 +761,8 @@ static irqreturn_t yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) } } } - return IRQ_HANDLED; +out: + return IRQ_RETVAL(handled); } static int yam_net_get_info(char *buffer, char **start, off_t offset, int length) diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 5874aa1b7625..9b8c823f5cc1 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -225,9 +225,7 @@ MODULE_PARM(pc_debug, "i"); #else #define DEBUG(n, args...) #endif -static char *version = -"xirc2ps_cs.c 1.31 1998/12/09 19:32:55 (dd9jn+kvh)"; - /* !--- CVS revision */ + #define KDBG_XIRC KERN_DEBUG "xirc2ps_cs: " #define KERR_XIRC KERN_ERR "xirc2ps_cs: " #define KWRN_XIRC KERN_WARNING "xirc2ps_cs: " diff --git a/include/linux/bitops.h b/include/linux/bitops.h index b7487acd00cb..c23ac5fc0a53 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -108,7 +108,7 @@ static inline unsigned int generic_hweight8(unsigned int w) return (res & 0x0F) + ((res >> 4) & 0x0F); } -static inline unsigned long generic_hweight64(u64 w) +static inline unsigned long generic_hweight64(__u64 w) { #if BITS_PER_LONG < 64 return generic_hweight32((unsigned int)(w >> 32)) + diff --git a/include/linux/gfp.h b/include/linux/gfp.h index be82baa340fa..aa3705a9a21e 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -7,7 +7,7 @@ /* * GFP bitmasks.. */ -/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low four bits) */ +/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low two bits) */ #define __GFP_DMA 0x01 #define __GFP_HIGHMEM 0x02 diff --git a/include/linux/smbno.h b/include/linux/smbno.h index c202e2d6cb80..f99e02d9ffe2 100644 --- a/include/linux/smbno.h +++ b/include/linux/smbno.h @@ -347,8 +347,8 @@ #define SMB_MODE_NO_CHANGE 0xFFFFFFFF #define SMB_UID_NO_CHANGE 0xFFFFFFFF #define SMB_GID_NO_CHANGE 0xFFFFFFFF -#define SMB_TIME_NO_CHANGE 0xFFFFFFFFFFFFFFFF -#define SMB_SIZE_NO_CHANGE 0xFFFFFFFFFFFFFFFF +#define SMB_TIME_NO_CHANGE 0xFFFFFFFFFFFFFFFFULL +#define SMB_SIZE_NO_CHANGE 0xFFFFFFFFFFFFFFFFULL /* UNIX filetype mappings. */ #define UNIX_TYPE_FILE 0 diff --git a/mm/shmem.c b/mm/shmem.c index 239564a4e5bf..73301cee3f41 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1010,7 +1010,7 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma) struct inode *inode = file->f_dentry->d_inode; ops = &shmem_vm_ops; - if (!inode->i_sb || !S_ISREG(inode->i_mode)) + if (!S_ISREG(inode->i_mode)) return -EACCES; update_atime(inode); vma->vm_ops = ops; -- cgit v1.2.3 From 6fb00b5042b604c8f57b6278ffbce1c242e31cc5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 20 Jun 2003 08:15:49 -0700 Subject: [PATCH] highmem.h needs mm.h From: David Mosberger highmem.h uses stuff like page_address(), but fails to include . --- include/linux/highmem.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 4cd2f596e705..2c9139a94f8f 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -3,6 +3,8 @@ #include #include +#include + #include #ifdef CONFIG_HIGHMEM -- cgit v1.2.3 From f5d256f844d50805f2e6b40aaf19460cd9b2e22b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 20 Jun 2003 08:16:09 -0700 Subject: [PATCH] ext3/JBD: remove trailing whitespace ext3 and JBD still have enormous numbers of lines which end in tabs. Fix them all up. --- fs/ext3/acl.c | 2 +- fs/ext3/balloc.c | 36 +++++++++++++-------------- fs/ext3/bitmap.c | 2 +- fs/ext3/dir.c | 12 ++++----- fs/ext3/file.c | 6 ++--- fs/ext3/hash.c | 12 ++++----- fs/ext3/ialloc.c | 8 +++--- fs/ext3/inode.c | 61 +++++++++++++++++++++++----------------------- fs/ext3/ioctl.c | 6 ++--- fs/ext3/namei.c | 46 +++++++++++++++++------------------ fs/ext3/super.c | 33 ++++++++++++------------- fs/ext3/xattr.c | 14 +++++------ fs/jbd/checkpoint.c | 9 +++---- fs/jbd/commit.c | 8 +++--- fs/jbd/journal.c | 13 +++++----- fs/jbd/recovery.c | 62 ++++++++++++++++++++++------------------------- fs/jbd/revoke.c | 60 ++++++++++++++++++++++----------------------- fs/jbd/transaction.c | 55 +++++++++++++++++++++-------------------- include/linux/ext3_fs_i.h | 2 +- 19 files changed, 216 insertions(+), 231 deletions(-) (limited to 'include/linux') diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 146dd832e23b..9313430093c5 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -361,7 +361,7 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) error = -ENOMEM; if (!clone) goto cleanup; - + mode = inode->i_mode; error = posix_acl_create_masq(clone, &mode); if (error >= 0) { diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 8f2003b11d0e..9ce1003c13bd 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -54,7 +54,7 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, return NULL; } - + group_desc = block_group / EXT3_DESC_PER_BLOCK(sb); desc = block_group % EXT3_DESC_PER_BLOCK(sb); if (!EXT3_SB(sb)->s_group_desc[group_desc]) { @@ -64,7 +64,7 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, block_group, group_desc, desc); return NULL; } - + gdp = (struct ext3_group_desc *) EXT3_SB(sb)->s_group_desc[group_desc]->b_data; if (bh) @@ -83,7 +83,7 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) { struct ext3_group_desc * desc; struct buffer_head * bh = NULL; - + desc = ext3_get_group_desc (sb, block_group, NULL); if (!desc) goto error_out; @@ -174,19 +174,19 @@ do_more: err = ext3_journal_get_undo_access(handle, bitmap_bh, NULL); if (err) goto error_return; - + /* * We are about to modify some metadata. Call the journal APIs * to unshare ->b_data if a currently-committing transaction is * using it */ BUFFER_TRACE(gd_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, gd_bh); + err = ext3_journal_get_write_access(handle, gd_bh); if (err) goto error_return; jbd_lock_bh_state(bitmap_bh); - + for (i = 0; i < count; i++) { /* * An HJ special. This is expensive... @@ -316,7 +316,7 @@ static int find_next_usable_block(int start, struct buffer_head *bh, { int here, next; char *p, *r; - + if (start > 0) { /* * The goal was occupied; search forward for a free @@ -331,15 +331,14 @@ static int find_next_usable_block(int start, struct buffer_head *bh, if (here < end_goal && ext3_test_allocatable(here, bh, have_access)) return here; - + ext3_debug ("Bit not found near goal\n"); - } - + here = start; if (here < 0) here = 0; - + /* * There has been no free block found in the near vicinity of * the goal: do a search forward through the block groups, @@ -351,10 +350,10 @@ static int find_next_usable_block(int start, struct buffer_head *bh, p = ((char *) bh->b_data) + (here >> 3); r = memscan(p, 0, (maxblocks - here + 7) >> 3); next = (r - ((char *) bh->b_data)) << 3; - + if (next < maxblocks && ext3_test_allocatable(next, bh, have_access)) return next; - + /* The bitmap search --- search forward alternately * through the actual bitmap and the last-committed copy * until we find a bit free in both. */ @@ -547,7 +546,7 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, EXT3_BLOCKS_PER_GROUP(sb)); bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) - goto io_error; + goto io_error; ret_block = ext3_try_to_allocate(sb, handle, group_no, bitmap_bh, ret_block, &fatal); if (fatal) @@ -555,7 +554,7 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, if (ret_block >= 0) goto allocated; } - + /* * Now search the rest of the groups. We assume that * i and gdp correctly point to the last group visited. @@ -675,7 +674,7 @@ allocated: *errp = 0; brelse(bitmap_bh); return ret_block; - + io_error: *errp = -EIO; out: @@ -690,7 +689,6 @@ out: DQUOT_FREE_BLOCK(inode, 1); brelse(bitmap_bh); return 0; - } unsigned long ext3_count_free_blocks(struct super_block *sb) @@ -702,7 +700,7 @@ unsigned long ext3_count_free_blocks(struct super_block *sb) struct ext3_super_block *es; unsigned long bitmap_count, x; struct buffer_head *bitmap_bh = NULL; - + lock_super(sb); es = EXT3_SB(sb)->s_es; desc_count = 0; @@ -717,7 +715,7 @@ unsigned long ext3_count_free_blocks(struct super_block *sb) bitmap_bh = read_block_bitmap(sb, i); if (bitmap_bh == NULL) continue; - + x = ext3_count_free(bitmap_bh, sb->s_blocksize); printk("group %d: stored = %d, counted = %lu\n", i, le16_to_cpu(gdp->bg_free_blocks_count), x); diff --git a/fs/ext3/bitmap.c b/fs/ext3/bitmap.c index 381559e65f01..6c419b9ab0e8 100644 --- a/fs/ext3/bitmap.c +++ b/fs/ext3/bitmap.c @@ -16,7 +16,7 @@ unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars) { unsigned int i; unsigned long sum = 0; - + if (!map) return (0); for (i = 0; i < numchars; i++) diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index d2cc5b92676a..b9c64eb1d664 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -157,7 +157,7 @@ static int ext3_readdir(struct file * filp, brelse (bha[i]); } } - + revalidate: /* If the dir block has changed since the last call to * readdir(2), then we might be pointing to an invalid @@ -183,7 +183,7 @@ revalidate: | offset; filp->f_version = inode->i_version; } - + while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ext3_dir_entry_2 *) (bh->b_data + offset); @@ -329,7 +329,7 @@ void ext3_htree_free_dir_info(struct dir_private_info *p) free_rb_tree_fname(&p->root); kfree(p); } - + /* * Given a directory entry, enter it into the fname rb tree. */ @@ -358,7 +358,7 @@ int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, new_fn->file_type = dirent->file_type; memcpy(new_fn->name, dirent->name, dirent->name_len); new_fn->name[dirent->name_len] = 0; - + while (*p) { parent = *p; fname = rb_entry(parent, struct fname, rb_hash); @@ -373,7 +373,7 @@ int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, fname->next = new_fn; return 0; } - + if (new_fn->hash < fname->hash) p = &(*p)->rb_left; else if (new_fn->hash > fname->hash) @@ -406,7 +406,7 @@ static int call_filldir(struct file * filp, void * dirent, int error; sb = inode->i_sb; - + if (!fname) { printk("call_filldir: called with null fname?!?\n"); return 0; diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 7a329a70a6f2..94ac5cd28480 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -69,7 +69,7 @@ ext3_file_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos) */ if (ret <= 0) return ret; - + /* * If the inode is IS_SYNC, or is O_SYNC and we are doing data * journalling then we need to make sure that we force the transaction @@ -97,14 +97,14 @@ ext3_file_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos) */ if (!IS_SYNC(inode)) return ret; - + /* * Open question #2 --- should we force data to disk here too? If we * don't, the only impact is that data=writeback filesystems won't * flush data to disk automatically on IS_SYNC, only metadata (but * historically, that is what ext2 has done.) */ - + force_commit: err = ext3_force_commit(inode->i_sb); if (err) diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c index d00d658b1cfb..f3780279f5c5 100644 --- a/fs/ext3/hash.c +++ b/fs/ext3/hash.c @@ -23,10 +23,10 @@ static void TEA_transform(__u32 buf[4], __u32 const in[]) __u32 a = in[0], b = in[1], c = in[2], d = in[3]; int n = 16; - do { - sum += DELTA; - b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); - b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); + do { + sum += DELTA; + b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); + b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); } while(--n); buf[0] += b0; @@ -107,7 +107,7 @@ static __u32 dx_hack_hash (const char *name, int len) __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; while (len--) { __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373)); - + if (hash & 0x80000000) hash -= 0x7fffffff; hash1 = hash0; hash0 = hash; @@ -178,7 +178,7 @@ int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) if (i < 4) memcpy(buf, hinfo->seed, sizeof(buf)); } - + switch (hinfo->hash_version) { case DX_HASH_LEGACY: hash = dx_hack_hash(name, len); diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index fd83ce45b353..7f0c2bfb81f7 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -462,13 +462,13 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) for (i = 0; i < sbi->s_groups_count; i++) { gdp = ext3_get_group_desc(sb, group, &bh2); - + err = -EIO; brelse(bitmap_bh); bitmap_bh = read_inode_bitmap(sb, group); if (!bitmap_bh) goto fail; - + ino = ext3_find_first_zero_bit((unsigned long *) bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb)); if (ino < EXT3_INODES_PER_GROUP(sb)) { @@ -532,7 +532,7 @@ got: BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, bh2); if (err) goto fail; - + percpu_counter_dec(&sbi->s_freeinodes_counter); if (S_ISDIR(mode)) percpu_counter_inc(&sbi->s_dirs_counter); @@ -580,7 +580,7 @@ got: ei->i_prealloc_count = 0; #endif ei->i_block_group = group; - + ext3_set_inode_flags(inode); if (IS_DIRSYNC(inode)) handle->h_sync = 1; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 277f940cc002..190875df3a11 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -72,7 +72,7 @@ int ext3_forget(handle_t *handle, int is_metadata, "data mode %lx\n", bh, is_metadata, inode->i_mode, test_opt(inode->i_sb, DATA_FLAGS)); - + /* Never use the revoke function if we are doing full data * journaling: there is no need to, and a V1 superblock won't * support it. Otherwise, only skip the revoke on un-journaled @@ -107,7 +107,7 @@ int ext3_forget(handle_t *handle, int is_metadata, static unsigned long blocks_for_truncate(struct inode *inode) { unsigned long needed; - + needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); /* Give ourselves just enough room to cope with inodes in which @@ -126,7 +126,7 @@ static unsigned long blocks_for_truncate(struct inode *inode) return EXT3_DATA_TRANS_BLOCKS + needed; } - + /* * Truncate transactions can be complex and absolutely huge. So we need to * be able to restart the transaction at a conventient checkpoint to make @@ -141,11 +141,11 @@ static unsigned long blocks_for_truncate(struct inode *inode) static handle_t *start_transaction(struct inode *inode) { handle_t *result; - + result = ext3_journal_start(inode, blocks_for_truncate(inode)); if (!IS_ERR(result)) return result; - + ext3_std_error(inode->i_sb, PTR_ERR(result)); return result; } @@ -195,7 +195,7 @@ void ext3_put_inode(struct inode *inode) void ext3_delete_inode (struct inode * inode) { handle_t *handle; - + if (is_bad_inode(inode)) goto no_delete; @@ -209,7 +209,7 @@ void ext3_delete_inode (struct inode * inode) ext3_std_error(inode->i_sb, PTR_ERR(handle)); goto no_delete; } - + if (IS_SYNC(inode)) handle->h_sync = 1; inode->i_size = 0; @@ -593,7 +593,7 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, break; branch[n].key = cpu_to_le32(nr); keys = n+1; - + /* * Get buffer_head for parent block, zero it out * and set the pointer to new one, then send @@ -621,7 +621,7 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, err = ext3_journal_dirty_metadata(handle, bh); if (err) break; - + parent = nr; } } @@ -723,7 +723,7 @@ changed: */ jbd_debug(1, "the chain changed: try again\n"); err = -EAGAIN; - + err_out: for (i = 1; i < num; i++) { BUFFER_TRACE(where[i].bh, "call journal_forget"); @@ -915,7 +915,7 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode * inode, { struct buffer_head dummy; int fatal = 0, err; - + J_ASSERT(handle != NULL || create == 0); dummy.b_state = 0; @@ -1233,7 +1233,7 @@ static sector_t ext3_bmap(struct address_space *mapping, sector_t block) struct inode *inode = mapping->host; journal_t *journal; int err; - + if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) { /* * This is a REALLY heavyweight approach, but the use of @@ -1252,17 +1252,17 @@ static sector_t ext3_bmap(struct address_space *mapping, sector_t block) * hasn't yet been flushed to disk, they deserve * everything they get. */ - + EXT3_I(inode)->i_state &= ~EXT3_STATE_JDATA; journal = EXT3_JOURNAL(inode); journal_lock_updates(journal); err = journal_flush(journal); journal_unlock_updates(journal); - + if (err) return 0; } - + return generic_block_bmap(mapping,block,ext3_get_block); } @@ -1347,7 +1347,7 @@ static int ext3_ordered_writepage(struct page *page, int err; J_ASSERT(PageLocked(page)); - + /* * We give up here if we're reentered, because it might be for a * different filesystem. @@ -1356,7 +1356,7 @@ static int ext3_ordered_writepage(struct page *page, goto out_fail; handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); - + if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto out_fail; @@ -2003,7 +2003,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, if (is_handle_aborted(handle)) return; - + if (depth--) { struct buffer_head *bh; int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb); @@ -2165,7 +2165,6 @@ void ext3_truncate(struct inode * inode) >> EXT3_BLOCK_SIZE_BITS(inode->i_sb); ext3_block_truncate_page(handle, inode->i_mapping, inode->i_size); - n = ext3_block_to_path(inode, last_block, offsets, NULL); if (n == 0) @@ -2296,7 +2295,7 @@ int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc) unsigned long desc; unsigned long offset; struct ext3_group_desc * gdp; - + if ((inode->i_ino != EXT3_ROOT_INO && inode->i_ino != EXT3_JOURNAL_INO && inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) || @@ -2340,9 +2339,9 @@ int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc) iloc->bh = bh; iloc->raw_inode = (struct ext3_inode *) (bh->b_data + offset); iloc->block_group = block_group; - + return 0; - + bad_inode: return -EIO; } @@ -2372,7 +2371,7 @@ void ext3_read_inode(struct inode * inode) struct ext3_inode_info *ei = EXT3_I(inode); struct buffer_head *bh; int block; - + #ifdef CONFIG_EXT3_FS_POSIX_ACL ei->i_acl = EXT3_ACL_NOT_CACHED; ei->i_default_acl = EXT3_ACL_NOT_CACHED; @@ -2472,7 +2471,7 @@ void ext3_read_inode(struct inode * inode) } ext3_set_inode_flags(inode); return; - + bad_inode: make_bad_inode(inode); return; @@ -2634,7 +2633,7 @@ void ext3_write_inode(struct inode *inode, int wait) if (!wait) return; - ext3_force_commit(inode->i_sb); + ext3_force_commit(inode->i_sb); } /* @@ -2680,7 +2679,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) error = PTR_ERR(handle); goto err_out; } - + error = ext3_orphan_add(handle, inode); EXT3_I(inode)->i_disksize = attr->ia_size; rc = ext3_mark_inode_dirty(handle, inode); @@ -2688,7 +2687,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) error = rc; ext3_journal_stop(handle); } - + rc = inode_setattr(inode, attr); /* If inode_setattr's call to ext3_truncate failed to get a @@ -2740,7 +2739,7 @@ int ext3_writepage_trans_blocks(struct inode *inode) int bpp = ext3_journal_blocks_per_page(inode); int indirects = (EXT3_NDIR_BLOCKS % bpp) ? 5 : 3; int ret; - + if (ext3_should_journal_data(inode)) ret = 3 * (bpp + indirects) + 2; else @@ -2877,7 +2876,7 @@ static inline int ext3_pin_inode(handle_t *handle, struct inode *inode) { struct ext3_iloc iloc; - + int err = 0; if (handle) { err = ext3_get_inode_loc(inode, &iloc); @@ -2914,7 +2913,7 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val) journal = EXT3_JOURNAL(inode); if (is_journal_aborted(journal) || IS_RDONLY(inode)) return -EROFS; - + journal_lock_updates(journal); journal_flush(journal); @@ -2943,6 +2942,6 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val) handle->h_sync = 1; ext3_journal_stop(handle); ext3_std_error(inode->i_sb, err); - + return err; } diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index b250fbf55b29..3681474e57d9 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c @@ -61,7 +61,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, if (!capable(CAP_LINUX_IMMUTABLE)) return -EPERM; } - + /* * The JOURNAL_DATA flag can only be changed by * the relevant capability. @@ -80,7 +80,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, err = ext3_reserve_inode_write(handle, inode, &iloc); if (err) goto flags_err; - + flags = flags & EXT3_FL_USER_MODIFIABLE; flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE; ei->i_flags = flags; @@ -93,7 +93,7 @@ flags_err: ext3_journal_stop(handle); if (err) return err; - + if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) err = ext3_change_inode_journal_flag(inode, jflag); return err; diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 7d03324974e2..1e71616f4d92 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -263,7 +263,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_ent unsigned names = 0, space = 0; char *base = (char *) de; struct dx_hash_info h = *hinfo; - + printk("names: "); while ((char *) de < base + size) { @@ -546,7 +546,7 @@ static int htree_dirblock_to_tree(struct file *dir_file, dxtrace(printk("In htree dirblock_to_tree: block %d\n", block)); if (!(bh = ext3_bread (NULL, dir, block, 0, &err))) return err; - + de = (struct ext3_dir_entry_2 *) bh->b_data; top = (struct ext3_dir_entry_2 *) ((char *) de + dir->i_sb->s_blocksize - @@ -588,11 +588,11 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, int count = 0; int ret; __u32 hashval; - + dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash, start_minor_hash)); dir = dir_file->f_dentry->d_inode; - if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) { + if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) { hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed; count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo, @@ -663,7 +663,7 @@ static int dx_make_map (struct ext3_dir_entry_2 *de, int size, int count = 0; char *base = (char *) de; struct dx_hash_info h = *hinfo; - + while ((char *) de < base + size) { if (de->name_len && de->inode) { @@ -798,8 +798,6 @@ static inline int search_dirblock(struct buffer_head * bh, * The returned buffer_head has ->b_count elevated. The caller is expected * to brelse() it when appropriate. */ - - static struct buffer_head * ext3_find_entry (struct dentry *dentry, struct ext3_dir_entry_2 ** res_dir) { @@ -903,7 +901,7 @@ restart: start = 0; goto restart; } - + cleanup_and_exit: /* Clean up the read-ahead blocks */ for (; ra_ptr < ra_max; ra_ptr++) @@ -926,7 +924,7 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, int namelen = dentry->d_name.len; const u8 *name = dentry->d_name.name; struct inode *dir = dentry->d_parent->d_inode; - + sb = dir->i_sb; if (!(frame = dx_probe (dentry, 0, &hinfo, frames, err))) return NULL; @@ -963,7 +961,7 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, goto errout; } } while (retval == 1); - + *err = -ENOENT; errout: dxtrace(printk("%s not found\n", name)); @@ -1191,7 +1189,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, unsigned short reclen; int nlen, rlen, err; char *top; - + reclen = EXT3_DIR_REC_LEN(namelen); if (!de) { de = (struct ext3_dir_entry_2 *)bh->b_data; @@ -1223,7 +1221,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, brelse(bh); return err; } - + /* By now the buffer is marked for journaling */ nlen = EXT3_DIR_REC_LEN(de->name_len); rlen = le16_to_cpu(de->rec_len); @@ -1286,7 +1284,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, unsigned blocksize; struct dx_hash_info hinfo; u32 block; - + blocksize = dir->i_sb->s_blocksize; dxtrace(printk("Creating index\n")); retval = ext3_journal_get_write_access(handle, bh); @@ -1296,7 +1294,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, return retval; } root = (struct dx_root *) bh->b_data; - + EXT3_I(dir)->i_flags |= EXT3_INDEX_FL; bh2 = ext3_append (handle, dir, &block, &retval); if (!(bh2)) { @@ -1479,13 +1477,13 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, unsigned icount1 = icount/2, icount2 = icount - icount1; unsigned hash2 = dx_get_hash(entries + icount1); dxtrace(printk("Split index %i/%i\n", icount1, icount2)); - + BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ err = ext3_journal_get_write_access(handle, frames[0].bh); if (err) goto journal_error; - + memcpy ((char *) entries2, (char *) (entries + icount1), icount2 * sizeof(struct dx_entry)); dx_set_count (entries, icount1); @@ -1535,7 +1533,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, err = add_dirent_to_buf(handle, dentry, inode, de, bh); bh = 0; goto cleanup; - + journal_error: ext3_std_error(dir->i_sb, err); cleanup: @@ -1831,7 +1829,7 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode) struct super_block *sb = inode->i_sb; struct ext3_iloc iloc; int err = 0, rc; - + lock_super(sb); if (!list_empty(&EXT3_I(inode)->i_orphan)) goto out_unlock; @@ -1852,7 +1850,7 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode) err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); if (err) goto out_unlock; - + err = ext3_reserve_inode_write(handle, inode, &iloc); if (err) goto out_unlock; @@ -2045,7 +2043,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) retval = -EIO; if (le32_to_cpu(de->inode) != inode->i_ino) goto end_unlink; - + if (!inode->i_nlink) { ext3_warning (inode->i_sb, "ext3_unlink", "Deleting nonexistent file (%lu), %d", @@ -2251,7 +2249,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, */ struct buffer_head *old_bh2; struct ext3_dir_entry_2 *old_de2; - + old_bh2 = ext3_find_entry(old_dentry, &old_de2); if (old_bh2) { retval = ext3_delete_entry(handle, old_dir, @@ -2316,9 +2314,9 @@ struct inode_operations ext3_dir_inode_operations = { .mknod = ext3_mknod, .rename = ext3_rename, .setattr = ext3_setattr, - .setxattr = ext3_setxattr, - .getxattr = ext3_getxattr, - .listxattr = ext3_listxattr, + .setxattr = ext3_setxattr, + .getxattr = ext3_getxattr, + .listxattr = ext3_listxattr, .removexattr = ext3_removexattr, .permission = ext3_permission, }; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 8769dc2cc593..b5c72519d5fd 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -119,7 +119,7 @@ static void clear_ro_after(struct super_block *sb) handle_t *ext3_journal_start(struct inode *inode, int nblocks) { journal_t *journal; - + if (inode->i_sb->s_flags & MS_RDONLY) return ERR_PTR(-EROFS); @@ -132,7 +132,7 @@ handle_t *ext3_journal_start(struct inode *inode, int nblocks) "Detected aborted journal"); return ERR_PTR(-EROFS); } - + return journal_start(journal, nblocks); } @@ -164,7 +164,7 @@ void ext3_journal_abort_handle(const char *caller, const char *err_fn, { char nbuf[16]; const char *errstr = ext3_decode_error(NULL, err, nbuf); - + printk(KERN_ERR "%s: aborting transaction: %s in %s", caller, errstr, err_fn); @@ -236,7 +236,7 @@ void ext3_error (struct super_block * sb, const char * function, const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16]) { char *errstr = NULL; - + switch (errno) { case -EIO: errstr = "IO failure"; @@ -259,7 +259,6 @@ const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16]) if (snprintf(nbuf, 16, "error %d", -errno) >= 0) errstr = nbuf; } - break; } @@ -277,7 +276,7 @@ void __ext3_std_error (struct super_block * sb, const char * function, printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n", sb->s_id, function, errstr); - + ext3_handle_error(sb); } @@ -311,7 +310,7 @@ void ext3_abort (struct super_block * sb, const char * function, if (sb->s_flags & MS_RDONLY) return; - + printk (KERN_CRIT "Remounting filesystem read-only\n"); EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; sb->s_flags |= MS_RDONLY; @@ -426,10 +425,10 @@ static inline struct inode *orphan_list_entry(struct list_head *l) static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi) { struct list_head *l; - + printk(KERN_ERR "sb orphan head is %d\n", le32_to_cpu(sbi->s_es->s_last_orphan)); - + printk(KERN_ERR "sb_info orphan list:\n"); list_for_each(l, &sbi->s_orphan) { struct inode *inode = orphan_list_entry(l); @@ -1062,7 +1061,7 @@ static unsigned long descriptor_loc(struct super_block *sb, struct ext3_sb_info *sbi = EXT3_SB(sb); unsigned long bg, first_data_block, first_meta_bg; int has_super = 0; - + first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block); first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); @@ -1138,7 +1137,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sb->s_id); goto failed_mount; } - + /* Set defaults before we parse the mount options */ def_mount_opts = le32_to_cpu(es->s_default_mount_opts); if (def_mount_opts & EXT3_DEFM_DEBUG) @@ -1162,7 +1161,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) set_opt(sbi->s_mount_opt, ERRORS_PANIC); else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO) set_opt(sbi->s_mount_opt, ERRORS_RO); - + sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); @@ -1539,7 +1538,7 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb, "EXT3-fs: blocksize too small for journal device.\n"); goto out_bdev; } - + sb_block = EXT3_MIN_BLOCK_SIZE / blocksize; offset = EXT3_MIN_BLOCK_SIZE % blocksize; set_blocksize(bdev, blocksize); @@ -1753,7 +1752,7 @@ static void ext3_clear_journal_err(struct super_block * sb, journal_t *journal; int j_errno; const char *errstr; - + journal = EXT3_SB(sb)->s_journal; /* @@ -1764,13 +1763,13 @@ static void ext3_clear_journal_err(struct super_block * sb, j_errno = journal_errno(journal); if (j_errno) { char nbuf[16]; - + errstr = ext3_decode_error(sb, j_errno, nbuf); ext3_warning(sb, __FUNCTION__, "Filesystem error recorded " "from previous mount: %s", errstr); ext3_warning(sb, __FUNCTION__, "Marking fs in need of " "filesystem check."); - + EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; es->s_state |= cpu_to_le16(EXT3_ERROR_FS); ext3_commit_super (sb, es, 1); @@ -1886,7 +1885,7 @@ int ext3_remount (struct super_block * sb, int * flags, char * data) es = sbi->s_es; ext3_init_journal_params(sbi, sbi->s_journal); - + if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) return -EROFS; diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 5ca5e3086e06..066316459d83 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -481,7 +481,7 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, unsigned int name_len; int min_offs = sb->s_blocksize, not_found = 1, free, error; char *end; - + /* * header -- Points either into bh, or to a temporarily * allocated buffer. @@ -493,7 +493,7 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, * towards the end of the block). * end -- Points right after the block pointed to by header. */ - + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", name_index, name, value, (long)value_len); @@ -736,11 +736,11 @@ ext3_xattr_set_handle2(handle_t *handle, struct inode *inode, ea_bdebug(new_bh, "%s block %ld", (old_bh == new_bh) ? "keeping" : "reusing", new_bh->b_blocknr); - + error = -EDQUOT; if (DQUOT_ALLOC_BLOCK(inode, 1)) goto cleanup; - + error = ext3_journal_get_write_access(handle, new_bh); if (error) goto cleanup; @@ -782,7 +782,7 @@ getblk_failed: set_buffer_uptodate(new_bh); unlock_buffer(new_bh); ext3_xattr_cache_insert(new_bh); - + ext3_xattr_update_super_block(handle, sb); } error = ext3_journal_dirty_metadata(handle, new_bh); @@ -1108,7 +1108,7 @@ static void ext3_xattr_rehash(struct ext3_xattr_header *header, { struct ext3_xattr_entry *here; __u32 hash = 0; - + ext3_xattr_hash_entry(header, entry); here = ENTRY(header+1); while (!IS_LAST_ENTRY(here)) { @@ -1131,7 +1131,7 @@ int __init init_ext3_xattr(void) { int err; - + err = ext3_xattr_register(EXT3_XATTR_INDEX_USER, &ext3_xattr_user_handler); if (err) diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 7b2fbb503ce5..2052795b8255 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -85,7 +85,7 @@ void __log_wait_for_space(journal_t *journal, int nblocks) return; spin_unlock(&journal->j_state_lock); down(&journal->j_checkpoint_sem); - + /* * Test again, another process may have checkpointed while we * were waiting for the checkpoint lock @@ -232,7 +232,7 @@ static int __flush_buffer(journal_t *journal, struct journal_head *jh, if (buffer_dirty(bh) && !buffer_locked(bh) && jh->b_jlist == BJ_None) { J_ASSERT_JH(jh, jh->b_transaction == NULL); - + /* * Important: we are about to write the buffer, and * possibly block, while still holding the journal lock. @@ -267,7 +267,6 @@ static int __flush_buffer(journal_t *journal, struct journal_head *jh, return ret; } - /* * Perform an actual checkpoint. We don't write out only enough to * satisfy the current blocked requests: rather we submit a reasonably @@ -373,7 +372,7 @@ int log_do_checkpoint(journal_t *journal, int nblocks) result = cleanup_journal_tail(journal); if (result < 0) return result; - + return 0; } @@ -524,7 +523,7 @@ void __journal_remove_checkpoint(struct journal_head *jh) journal_t *journal; JBUFFER_TRACE(jh, "entry"); - + if ((transaction = jh->b_cp_transaction) == NULL) { JBUFFER_TRACE(jh, "not on transaction"); goto out; diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index b009d38fd63a..b41b26d758b4 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -197,7 +197,7 @@ void journal_commit_transaction(journal_t *journal) commit_transaction->t_log_start = journal->j_head; wake_up(&journal->j_wait_transaction_locked); spin_unlock(&journal->j_state_lock); - + jbd_debug (3, "JBD: commit phase 2\n"); /* @@ -368,7 +368,7 @@ sync_datalist_empty: __journal_abort_hard(journal); continue; } - + bh = jh2bh(descriptor); jbd_debug(4, "JBD: got buffer %llu (%p)\n", (unsigned long long)bh->b_blocknr, bh->b_data); @@ -622,7 +622,7 @@ skip_commit: /* The journal should be unlocked by now. */ if (err) __journal_abort_hard(journal); - + /* * Call any callbacks that had been registered for handles in this * transaction. It is up to the callback to free any allocated @@ -714,7 +714,7 @@ skip_commit: /* The journal should be unlocked by now. */ clear_buffer_freed(bh); clear_buffer_jbddirty(bh); } - + if (buffer_jbddirty(bh)) { JBUFFER_TRACE(jh, "add to new checkpointing trans"); __journal_insert_checkpoint(jh, commit_transaction); diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index d7ab5776d75b..fe4bdf4a6f34 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -175,7 +175,6 @@ loop: spin_unlock(&journal->j_state_lock); refrigerator(PF_IOTHREAD); spin_lock(&journal->j_state_lock); - jbd_debug(1, "Resuming kjournald\n"); } else { /* * We assume on resume that commits are already there, @@ -185,7 +184,7 @@ loop: int should_sleep = 1; prepare_to_wait(&journal->j_wait_commit, &wait, - TASK_INTERRUPTIBLE); + TASK_INTERRUPTIBLE); if (journal->j_commit_sequence != journal->j_commit_request) should_sleep = 0; transaction = journal->j_running_transaction; @@ -733,7 +732,7 @@ journal_t * journal_init_inode (struct inode *inode) kfree(journal); return NULL; } - + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); J_ASSERT(bh != NULL); journal->j_sb_buffer = bh; @@ -927,7 +926,7 @@ static int journal_get_superblock(journal_t *journal) struct buffer_head *bh; journal_superblock_t *sb; int err = -EIO; - + bh = journal->j_sb_buffer; J_ASSERT(bh != NULL); @@ -944,7 +943,7 @@ static int journal_get_superblock(journal_t *journal) sb = journal->j_superblock; err = -EINVAL; - + if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) || sb->s_blocksize != htonl(journal->j_blocksize)) { printk(KERN_WARNING "JBD: no valid journal superblock found\n"); @@ -1263,7 +1262,7 @@ int journal_flush(journal_t *journal) unsigned long old_tail; spin_lock(&journal->j_state_lock); - + /* Force everything buffered to the log... */ if (journal->j_running_transaction) { transaction = journal->j_running_transaction; @@ -1541,7 +1540,7 @@ int journal_blocks_per_page(struct inode *inode) */ void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry) { - return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0)); + return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0)); } /* diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index d9afa22f5de2..d6e080c8c5ec 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -29,9 +29,9 @@ */ struct recovery_info { - tid_t start_transaction; + tid_t start_transaction; tid_t end_transaction; - + int nr_replays; int nr_revokes; int nr_revoke_hits; @@ -72,9 +72,9 @@ static int do_readahead(journal_t *journal, unsigned int start) unsigned int max, nbufs, next; unsigned long blocknr; struct buffer_head *bh; - + struct buffer_head * bufs[MAXBUF]; - + /* Do up to 128K of readahead */ max = start + (128 * 1024 / journal->j_blocksize); if (max > journal->j_maxlen) @@ -82,9 +82,9 @@ static int do_readahead(journal_t *journal, unsigned int start) /* Do the readahead itself. We'll submit MAXBUF buffer_heads at * a time to the block device IO layer. */ - + nbufs = 0; - + for (next = start; next < max; next++) { err = journal_bmap(journal, next, &blocknr); @@ -115,7 +115,7 @@ static int do_readahead(journal_t *journal, unsigned int start) ll_rw_block(READ, nbufs, bufs); err = 0; -failed: +failed: if (nbufs) journal_brelse_array(bufs, nbufs); return err; @@ -138,7 +138,7 @@ static int jread(struct buffer_head **bhp, journal_t *journal, *bhp = NULL; J_ASSERT (offset < journal->j_maxlen); - + err = journal_bmap(journal, offset, &blocknr); if (err) { @@ -224,10 +224,10 @@ int journal_recover(journal_t *journal) journal_superblock_t * sb; struct recovery_info info; - + memset(&info, 0, sizeof(info)); sb = journal->j_superblock; - + /* * The journal superblock's s_start field (the current log head) * is always zero if, and only if, the journal was cleanly @@ -240,7 +240,6 @@ int journal_recover(journal_t *journal) journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1; return 0; } - err = do_one_pass(journal, &info, PASS_SCAN); if (!err) @@ -257,7 +256,7 @@ int journal_recover(journal_t *journal) /* Restart the log at the next transaction ID, thus invalidating * any existing commit records in the log. */ journal->j_transaction_sequence = ++info.end_transaction; - + journal_clear_revoke(journal); sync_blockdev(journal->j_fs_dev); return err; @@ -282,10 +281,10 @@ int journal_skip_recovery(journal_t *journal) journal_superblock_t * sb; struct recovery_info info; - + memset (&info, 0, sizeof(info)); sb = journal->j_superblock; - + err = do_one_pass(journal, &info, PASS_SCAN); if (err) { @@ -295,7 +294,6 @@ int journal_skip_recovery(journal_t *journal) #ifdef CONFIG_JBD_DEBUG int dropped = info.end_transaction - ntohl(sb->s_sequence); #endif - jbd_debug(0, "JBD: ignoring %d transaction%s from the journal.\n", dropped, (dropped == 1) ? "" : "s"); @@ -303,14 +301,12 @@ int journal_skip_recovery(journal_t *journal) } journal->j_tail = 0; - return err; } static int do_one_pass(journal_t *journal, struct recovery_info *info, enum passtype pass) { - unsigned int first_commit_ID, next_commit_ID; unsigned long next_log_block; int err, success = 0; @@ -319,7 +315,7 @@ static int do_one_pass(journal_t *journal, struct buffer_head * bh; unsigned int sequence; int blocktype; - + /* Precompute the maximum metadata descriptors in a descriptor block */ int MAX_BLOCKS_PER_DESC; MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t)) @@ -354,11 +350,11 @@ static int do_one_pass(journal_t *journal, journal_block_tag_t * tag; struct buffer_head * obh; struct buffer_head * nbh; - + /* If we already know where to stop the log traversal, * check right now that we haven't gone past the end of * the log. */ - + if (pass != PASS_SCAN) if (tid_geq(next_commit_ID, info->end_transaction)) break; @@ -369,7 +365,7 @@ static int do_one_pass(journal_t *journal, /* Skip over each chunk of the transaction looking * either the next descriptor block or the final commit * record. */ - + jbd_debug(3, "JBD: checking block %ld\n", next_log_block); err = jread(&bh, journal, next_log_block); if (err) @@ -377,7 +373,7 @@ static int do_one_pass(journal_t *journal, next_log_block++; wrap(journal, next_log_block); - + /* What kind of buffer is it? * * If it is a descriptor block, check that it has the @@ -385,7 +381,7 @@ static int do_one_pass(journal_t *journal, * here. */ tmp = (journal_header_t *)bh->b_data; - + if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) { brelse(bh); break; @@ -395,12 +391,12 @@ static int do_one_pass(journal_t *journal, sequence = ntohl(tmp->h_sequence); jbd_debug(3, "Found magic %d, sequence %d\n", blocktype, sequence); - + if (sequence != next_commit_ID) { brelse(bh); break; } - + /* OK, we have a valid descriptor block which matches * all of the sequence number checks. What are we going * to do with it? That depends on the pass... */ @@ -429,7 +425,7 @@ static int do_one_pass(journal_t *journal, tag = (journal_block_tag_t *) tagp; flags = ntohl(tag->t_flags); - + io_block = next_log_block++; wrap(journal, next_log_block); err = jread(&obh, journal, io_block); @@ -443,7 +439,7 @@ static int do_one_pass(journal_t *journal, err, io_block); } else { unsigned long blocknr; - + J_ASSERT(obh != NULL); blocknr = ntohl(tag->t_blocknr); @@ -457,7 +453,7 @@ static int do_one_pass(journal_t *journal, ++info->nr_revoke_hits; goto skip_write; } - + /* Find a buffer for the new * data being restored */ nbh = __getblk(journal->j_fs_dev, @@ -491,7 +487,7 @@ static int do_one_pass(journal_t *journal, brelse(obh); brelse(nbh); } - + skip_write: tagp += sizeof(journal_block_tag_t); if (!(flags & JFS_FLAG_SAME_UUID)) @@ -500,7 +496,7 @@ static int do_one_pass(journal_t *journal, if (flags & JFS_FLAG_LAST_TAG) break; } - + brelse(bh); continue; @@ -541,7 +537,7 @@ static int do_one_pass(journal_t *journal, * log. If the latter happened, then we know that the "current" * transaction marks the end of the valid log. */ - + if (pass == PASS_SCAN) info->end_transaction = next_commit_ID; else { @@ -574,11 +570,11 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, header = (journal_revoke_header_t *) bh->b_data; offset = sizeof(journal_revoke_header_t); max = ntohl(header->r_count); - + while (offset < max) { unsigned long blocknr; int err; - + blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset))); offset += 4; err = journal_set_revoke(journal, blocknr, sequence); diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index 933551effe14..0ab15014f950 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -81,7 +81,7 @@ struct jbd_revoke_record_s { struct list_head hash; tid_t sequence; /* Used for recovery only */ - unsigned long blocknr; + unsigned long blocknr; }; @@ -110,7 +110,7 @@ static inline int hash(journal_t *journal, unsigned long block) { struct jbd_revoke_table_s *table = journal->j_revoke; int hash_shift = table->hash_shift; - + return ((block << (hash_shift - 6)) ^ (block >> 13) ^ (block << (hash_shift - 12))) & (table->hash_size - 1); @@ -149,7 +149,7 @@ static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, { struct list_head *hash_list; struct jbd_revoke_record_s *record; - + hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; spin_lock(&journal->j_revoke_lock); @@ -161,7 +161,7 @@ static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, } record = (struct jbd_revoke_record_s *) record->hash.next; } - spin_unlock(&journal->j_revoke_lock); + spin_unlock(&journal->j_revoke_lock); return NULL; } @@ -182,7 +182,7 @@ int __init journal_init_revoke_caches(void) return -ENOMEM; } return 0; -} +} void journal_destroy_revoke_caches(void) { @@ -197,9 +197,9 @@ void journal_destroy_revoke_caches(void) int journal_init_revoke(journal_t *journal, int hash_size) { int shift, tmp; - + J_ASSERT (journal->j_revoke_table[0] == NULL); - + shift = 0; tmp = hash_size; while((tmp >>= 1UL) != 0UL) @@ -209,7 +209,7 @@ int journal_init_revoke(journal_t *journal, int hash_size) if (!journal->j_revoke_table[0]) return -ENOMEM; journal->j_revoke = journal->j_revoke_table[0]; - + /* Check that the hash_size is a power of two */ J_ASSERT ((hash_size & (hash_size-1)) == 0); @@ -224,19 +224,19 @@ int journal_init_revoke(journal_t *journal, int hash_size) journal->j_revoke = NULL; return -ENOMEM; } - + for (tmp = 0; tmp < hash_size; tmp++) INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); - + journal->j_revoke_table[1] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); if (!journal->j_revoke_table[1]) { kfree(journal->j_revoke_table[0]->hash_table); kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); return -ENOMEM; } - + journal->j_revoke = journal->j_revoke_table[1]; - + /* Check that the hash_size is a power of two */ J_ASSERT ((hash_size & (hash_size-1)) == 0); @@ -253,7 +253,7 @@ int journal_init_revoke(journal_t *journal, int hash_size) journal->j_revoke = NULL; return -ENOMEM; } - + for (tmp = 0; tmp < hash_size; tmp++) INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); @@ -269,16 +269,16 @@ void journal_destroy_revoke(journal_t *journal) struct jbd_revoke_table_s *table; struct list_head *hash_list; int i; - + table = journal->j_revoke_table[0]; if (!table) return; - + for (i=0; ihash_size; i++) { hash_list = &table->hash_table[i]; J_ASSERT (list_empty(hash_list)); } - + kfree(table->hash_table); kmem_cache_free(revoke_table_cache, table); journal->j_revoke = NULL; @@ -286,12 +286,12 @@ void journal_destroy_revoke(journal_t *journal) table = journal->j_revoke_table[1]; if (!table) return; - + for (i=0; ihash_size; i++) { hash_list = &table->hash_table[i]; J_ASSERT (list_empty(hash_list)); } - + kfree(table->hash_table); kmem_cache_free(revoke_table_cache, table); journal->j_revoke = NULL; @@ -420,7 +420,7 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) int need_cancel; int did_revoke = 0; /* akpm: debug */ struct buffer_head *bh = jh2bh(jh); - + jbd_debug(4, "journal_head %p, cancelling revoke\n", jh); /* Is the existing Revoke bit valid? If so, we trust it, and @@ -466,7 +466,6 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) __brelse(bh2); } } - return did_revoke; } @@ -482,7 +481,7 @@ void journal_switch_revoke_table(journal_t *journal) journal->j_revoke = journal->j_revoke_table[1]; else journal->j_revoke = journal->j_revoke_table[0]; - + for (i = 0; i < journal->j_revoke->hash_size; i++) INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]); } @@ -506,11 +505,11 @@ void journal_write_revoke_records(journal_t *journal, descriptor = NULL; offset = 0; count = 0; - + /* select revoke table for committing transaction */ revoke = journal->j_revoke == journal->j_revoke_table[0] ? journal->j_revoke_table[1] : journal->j_revoke_table[0]; - + for (i = 0; i < revoke->hash_size; i++) { hash_list = &revoke->hash_table[i]; @@ -562,7 +561,7 @@ static void write_one_revoke_record(journal_t *journal, descriptor = NULL; } } - + if (!descriptor) { descriptor = journal_get_descriptor_buffer(journal); if (!descriptor) @@ -579,7 +578,7 @@ static void write_one_revoke_record(journal_t *journal, offset = sizeof(journal_revoke_header_t); *descriptorp = descriptor; } - + * ((unsigned int *)(&jh2bh(descriptor)->b_data[offset])) = htonl(record->blocknr); offset += 4; @@ -604,7 +603,7 @@ static void flush_descriptor(journal_t *journal, __brelse(jh2bh(descriptor)); return; } - + header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data; header->r_count = htonl(offset); set_bit(BH_JWrite, &jh2bh(descriptor)->b_state); @@ -645,7 +644,7 @@ int journal_set_revoke(journal_t *journal, tid_t sequence) { struct jbd_revoke_record_s *record; - + record = find_revoke_record(journal, blocknr); if (record) { /* If we have multiple occurrences, only record the @@ -669,7 +668,7 @@ int journal_test_revoke(journal_t *journal, tid_t sequence) { struct jbd_revoke_record_s *record; - + record = find_revoke_record(journal, blocknr); if (!record) return 0; @@ -689,9 +688,9 @@ void journal_clear_revoke(journal_t *journal) struct list_head *hash_list; struct jbd_revoke_record_s *record; struct jbd_revoke_table_s *revoke; - + revoke = journal->j_revoke; - + for (i = 0; i < revoke->hash_size; i++) { hash_list = &revoke->hash_table[i]; while (!list_empty(hash_list)) { @@ -701,4 +700,3 @@ void journal_clear_revoke(journal_t *journal) } } } - diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index b9a23b8c7a59..54e16b97fdaa 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -57,7 +57,7 @@ get_transaction(journal_t *journal, transaction_t *transaction) /* Set up the commit timer for the new transaction. */ journal->j_commit_timer->expires = transaction->t_expires; add_timer(journal->j_commit_timer); - + J_ASSERT(journal->j_running_transaction == NULL); journal->j_running_transaction = transaction; @@ -130,7 +130,7 @@ repeat_locked: journal->j_barrier_count == 0); goto repeat; } - + if (!journal->j_running_transaction) { if (!new_transaction) { spin_unlock(&journal->j_state_lock); @@ -153,7 +153,7 @@ repeat_locked: transaction->t_state != T_LOCKED); goto repeat; } - + /* * If there is not enough space left in the log to write all potential * buffers requested by this operation, we need to stall pending a log @@ -210,7 +210,7 @@ repeat_locked: if (journal->j_committing_transaction) needed += journal->j_committing_transaction-> t_outstanding_credits; - + if (__log_space_left(journal) < needed) { jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); spin_unlock(&transaction->t_handle_lock); @@ -268,7 +268,7 @@ handle_t *journal_start(journal_t *journal, int nblocks) { handle_t *handle = journal_current_handle(); int err; - + if (!journal) return ERR_PTR(-EROFS); @@ -337,7 +337,7 @@ int journal_extend(handle_t *handle, int nblocks) spin_lock(&transaction->t_handle_lock); wanted = transaction->t_outstanding_credits + nblocks; - + if (wanted > journal->j_max_transaction_buffers) { jbd_debug(3, "denied handle %p %d blocks: " "transaction too large\n", handle, nblocks); @@ -349,7 +349,7 @@ int journal_extend(handle_t *handle, int nblocks) "insufficient log space\n", handle, nblocks); goto unlock; } - + handle->h_buffer_credits += nblocks; transaction->t_outstanding_credits += nblocks; result = 0; @@ -388,7 +388,7 @@ int journal_restart(handle_t *handle, int nblocks) * actually doing the restart! */ if (is_handle_aborted(handle)) return 0; - + /* * First unlink the handle from its current transaction, and start the * commit on that. @@ -496,7 +496,7 @@ static void jbd_unexpected_dirty_buffer(struct journal_head *jh) { struct buffer_head *bh = jh2bh(jh); int jlist; - + if (buffer_dirty(bh)) { /* If this buffer is one which might reasonably be dirty * --- ie. data, or not part of this journal --- then @@ -504,7 +504,7 @@ static void jbd_unexpected_dirty_buffer(struct journal_head *jh) * move the dirty bit to the journal's own internal * JBDDirty bit. */ jlist = jh->b_jlist; - + if (jlist == BJ_Metadata || jlist == BJ_Reserved || jlist == BJ_Shadow || jlist == BJ_Forget) { if (test_clear_buffer_dirty(jh2bh(jh))) { @@ -609,7 +609,7 @@ repeat: (*credits)++; goto done_locked; } - + /* Is there data here we need to preserve? */ if (jh->b_transaction && jh->b_transaction != transaction) { @@ -638,7 +638,7 @@ repeat: wait_event(*wqh, (jh->b_jlist != BJ_Shadow)); goto repeat; } - + /* Only do the copy if the currently-owning transaction * still needs it. If it is on the Forget list, the * committing transaction is past that stage. The @@ -697,7 +697,7 @@ repeat: JBUFFER_TRACE(jh, "file as BJ_Reserved"); __journal_file_buffer(jh, transaction, BJ_Reserved); } - + done_locked: spin_unlock(&journal->j_list_lock); if (need_copy) { @@ -778,13 +778,13 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh) journal_t *journal = transaction->t_journal; struct journal_head *jh = journal_add_journal_head(bh); int err; - + jbd_debug(5, "journal_head %p\n", jh); err = -EROFS; if (is_handle_aborted(handle)) goto out; err = 0; - + JBUFFER_TRACE(jh, "entry"); /* * The buffer may already belong to this transaction due to pre-zeroing @@ -932,7 +932,7 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh) if (is_handle_aborted(handle)) return 0; - + jh = journal_add_journal_head(bh); JBUFFER_TRACE(jh, "entry"); @@ -1098,7 +1098,7 @@ int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) JBUFFER_TRACE(jh, "entry"); if (is_handle_aborted(handle)) goto out; - + jbd_lock_bh_state(bh); /* @@ -1130,7 +1130,7 @@ int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) set_buffer_jbddirty(bh); J_ASSERT_JH(jh, jh->b_transaction != NULL); - + /* * Metadata already on the current transaction list doesn't * need to be filed. Metadata on another transaction's list must @@ -1272,7 +1272,6 @@ void journal_forget(handle_t *handle, struct buffer_head *bh) return; } } - } else if (jh->b_transaction) { J_ASSERT_JH(jh, (jh->b_transaction == journal->j_committing_transaction)); @@ -1346,18 +1345,18 @@ int journal_stop(handle_t *handle) transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; int old_handle_count, err; - + if (!handle) return 0; J_ASSERT(transaction->t_updates > 0); J_ASSERT(journal_current_handle() == handle); - + if (is_handle_aborted(handle)) err = -EIO; else err = 0; - + if (--handle->h_ref > 0) { jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, handle->h_ref); @@ -1413,7 +1412,7 @@ int journal_stop(handle_t *handle) * completes the commit thread, it just doesn't write * anything to disk. */ tid_t tid = transaction->t_tid; - + spin_unlock(&transaction->t_handle_lock); jbd_debug(2, "transaction too old, requesting commit for " "handle %p\n", handle); @@ -1563,7 +1562,7 @@ void __journal_unfile_buffer(struct journal_head *jh) list = &transaction->t_reserved_list; break; } - + __blist_del_buffer(list, jh); jh->b_jlist = BJ_None; if (test_clear_buffer_jbddirty(bh)) @@ -1811,7 +1810,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) JBUFFER_TRACE(jh, "not on any transaction: zap"); goto zap_buffer; } - + if (!buffer_dirty(bh)) { /* bdflush has written it. We can drop it now */ goto zap_buffer; @@ -1910,7 +1909,7 @@ int journal_invalidatepage(journal_t *journal, struct buffer_head *head, *bh, *next; unsigned int curr_off = 0; int may_free = 1; - + if (!PageLocked(page)) BUG(); if (!page_has_buffers(page)) @@ -1967,7 +1966,7 @@ void __journal_file_buffer(struct journal_head *jh, if (jh->b_transaction && jh->b_jlist == jlist) return; - + /* The following list of buffer states needs to be consistent * with __jbd_unexpected_dirty_buffer()'s handling of dirty * state. */ @@ -2055,7 +2054,7 @@ void __journal_refile_buffer(struct journal_head *jh) jh->b_transaction = NULL; return; } - + /* * It has been modified by a later transaction: add it to the new * transaction's metadata list. diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h index 02021676dd74..1a6a6c5922f7 100644 --- a/include/linux/ext3_fs_i.h +++ b/include/linux/ext3_fs_i.h @@ -66,7 +66,7 @@ struct ext3_inode_info { struct posix_acl *i_acl; struct posix_acl *i_default_acl; #endif - + struct list_head i_orphan; /* unlinked but open inodes */ /* -- cgit v1.2.3 From 3ea1af42b35c7d2e824fe6889dbe88e586b0fb42 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 20 Jun 2003 14:35:24 -0700 Subject: input: remove unused var from serio struct --- include/linux/serio.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/serio.h b/include/linux/serio.h index ae1a7f9bde2b..f1c67ff70f2a 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -26,7 +26,6 @@ struct serio { void *driver; char *name; char *phys; - int number; unsigned short idbus; unsigned short idvendor; -- cgit v1.2.3 From 2ce738e0a3fbee1dff6c132d180b4e33f56bfb88 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Fri, 20 Jun 2003 14:41:52 -0700 Subject: input: Add Logitech MX PS2++ support, move Logitech PS2++ code to a separate source file, always enable Synaptics support. Some more fixes in Synaptics code and documentation. --- drivers/input/mouse/Kconfig | 17 +-- drivers/input/mouse/Makefile | 5 +- drivers/input/mouse/logips2pp.c | 228 +++++++++++++++++++++++++++++++++++++ drivers/input/mouse/logips2pp.h | 17 +++ drivers/input/mouse/psmouse-base.c | 193 ++++++++++--------------------- drivers/input/mouse/psmouse.h | 2 + drivers/input/mouse/synaptics.c | 7 +- drivers/input/mouse/synaptics.h | 10 -- include/linux/input.h | 1 + 9 files changed, 315 insertions(+), 165 deletions(-) create mode 100644 drivers/input/mouse/logips2pp.c create mode 100644 drivers/input/mouse/logips2pp.h (limited to 'include/linux') diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 31de187d173d..a6b481994163 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -19,7 +19,9 @@ config MOUSE_PS2 Say Y here if you have a PS/2 mouse connected to your system. This includes the standard 2 or 3-button PS/2 mouse, as well as PS/2 mice with wheels and extra buttons, Microsoft, Logitech or Genius - compatible. + compatible. Support for Synaptics TouchPads is also included. + For Synaptics TouchPad support in XFree86 you'll need this XFree86 + driver: http://w1.894.telia.com/~u89404340/touchpad/index.html If unsure, say Y. @@ -28,19 +30,6 @@ config MOUSE_PS2 The module will be called psmouse. If you want to compile it as a module, say M here and read . -config MOUSE_PS2_SYNAPTICS - bool "Synaptics TouchPad" - default n - depends on INPUT && INPUT_MOUSE && SERIO && MOUSE_PS2 - ---help--- - Say Y here if you have a Synaptics TouchPad connected to your system. - This touchpad is found on many modern laptop computers. - Note that you also need a user space driver to interpret the data - generated by the kernel. A compatible driver for XFree86 is available - from http://... - - If unsure, say Y. - config MOUSE_SERIAL tristate "Serial mouse" depends on INPUT && INPUT_MOUSE && SERIO diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 6a52702cb1cc..8c1b90087721 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -14,7 +14,4 @@ obj-$(CONFIG_MOUSE_PC9800) += 98busmouse.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o -psmouse-objs := psmouse-base.o -ifeq ($(CONFIG_MOUSE_PS2_SYNAPTICS),y) - psmouse-objs += synaptics.o -endif +psmouse-objs := psmouse-base.o logips2pp.o synaptics.o diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c new file mode 100644 index 000000000000..0b7b154e7341 --- /dev/null +++ b/drivers/input/mouse/logips2pp.c @@ -0,0 +1,228 @@ +/* + * Logitech PS/2++ mouse driver + * + * Copyright (c) 1999-2003 Vojtech Pavlik + * Copyright (c) 2003 Eric Wong + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include "psmouse.h" +#include "logips2pp.h" + +/* + * Process a PS2++ or PS2T++ packet. + */ + +void ps2pp_process_packet(struct psmouse *psmouse) +{ + struct input_dev *dev = &psmouse->dev; + unsigned char *packet = psmouse->packet; + + if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) { + + switch ((packet[1] >> 4) | (packet[0] & 0x30)) { + + case 0x0d: /* Mouse extra info */ + + input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, + (int) (packet[2] & 8) - (int) (packet[2] & 7)); + input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); + input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); + + break; + + case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ + + input_report_key(dev, BTN_SIDE, (packet[2]) & 1); + input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1); + input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); + input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); + input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); + + break; + + case 0x0f: /* TouchPad extra info */ + + input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, + (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); + packet[0] = packet[2] | 0x08; + break; + +#ifdef DEBUG + default: + printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", + (packet[1] >> 4) | (packet[0] & 0x30)); +#endif + } + + packet[0] &= 0x0f; + packet[1] = 0; + packet[2] = 0; + + } +} + +/* + * ps2pp_cmd() sends a PS2++ command, sliced into two bit + * pieces through the SETRES command. This is needed to send extended + * commands to mice on notebooks that try to understand the PS/2 protocol + * Ugly. + */ + +static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) +{ + unsigned char d; + int i; + + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) + return -1; + + for (i = 6; i >= 0; i -= 2) { + d = (command >> i) & 3; + if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES)) + return -1; + } + + if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) + return -1; + + return 0; +} + +/* + * SmartScroll / CruiseControl for some newer Logitech mice Defaults to + * enabled if we do nothing to it. Of course I put this in because I want it + * disabled :P + * 1 - enabled (if previously disabled, also default) + * 0/2 - disabled + */ + +static void ps2pp_set_smartscroll(struct psmouse *psmouse) +{ + unsigned char param[4]; + + ps2pp_cmd(psmouse, param, 0x32); + + param[0] = 0; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + + if (psmouse_smartscroll == 1) + param[0] = 1; + else + if (psmouse_smartscroll > 2) + return; + + /* else leave param[0] == 0 to disable */ + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); +} + +/* + * Support 800 dpi resolution _only_ if the user wants it (there are good + * reasons to not use it even if the mouse supports it, and of course there are + * also good reasons to use it, let the user decide). + */ + +void ps2pp_set_800dpi(struct psmouse *psmouse) +{ + unsigned char param = 3; + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, ¶m, PSMOUSE_CMD_SETRES); +} + +/* + * Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or + * touchpad. + */ + +int ps2pp_detect_model(struct psmouse *psmouse, unsigned char param *param) +{ + int i; + static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 }; + static int logitech_wheel[] = { 52, 53, 75, 76, 80, 81, 83, 88, 112, -1 }; + static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75, + 76, 80, 81, 83, 88, 96, 97, 112, -1 }; + static int logitech_mx[] = { 112, -1 }; + + psmouse->vendor = "Logitech"; + psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); + + if (param[1] < 3) + clear_bit(BTN_MIDDLE, psmouse->dev.keybit); + if (param[1] < 2) + clear_bit(BTN_RIGHT, psmouse->dev.keybit); + + psmouse->type = PSMOUSE_PS2; + + for (i = 0; logitech_ps2pp[i] != -1; i++) + if (logitech_ps2pp[i] == psmouse->model) + psmouse->type = PSMOUSE_PS2PP; + + if (psmouse->type == PSMOUSE_PS2PP) { + + for (i = 0; logitech_4btn[i] != -1; i++) + if (logitech_4btn[i] == psmouse->model) + set_bit(BTN_SIDE, psmouse->dev.keybit); + + for (i = 0; logitech_wheel[i] != -1; i++) + if (logitech_wheel[i] == psmouse->model) { + set_bit(REL_WHEEL, psmouse->dev.relbit); + psmouse->name = "Wheel Mouse"; + } + + for (i = 0; logitech_mx[i] != -1; i++) + if (logitech_mx[i] == psmouse->model) { + set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_BACK, psmouse->dev.keybit); + set_bit(BTN_FORWARD, psmouse->dev.keybit); + set_bit(BTN_TASK, psmouse->dev.keybit); + psmouse->name = "MX Mouse"; + } + +/* + * Do Logitech PS2++ / PS2T++ magic init. + */ + + if (psmouse->model == 97) { /* TouchPad 3 */ + + set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(REL_HWHEEL, psmouse->dev.relbit); + + param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ + psmouse_command(psmouse, param, 0x30d1); + param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ + psmouse_command(psmouse, param, 0x30d1); + param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ + psmouse_command(psmouse, param, 0x30d1); + + param[0] = 0; + if (!psmouse_command(psmouse, param, 0x13d1) && + param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { + psmouse->name = "TouchPad 3"; + return PSMOUSE_PS2TPP; + } + + } else { + + param[0] = param[1] = param[2] = 0; + ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ + ps2pp_cmd(psmouse, param, 0xDB); + + if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && + (param[2] & 3) == ((param[1] >> 2) & 3)) { + ps2pp_set_smartscroll(psmouse); + return PSMOUSE_PS2PP; + } + } + } + + return 0; +} diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h new file mode 100644 index 000000000000..b3a8c2199aa9 --- /dev/null +++ b/drivers/input/mouse/logips2pp.h @@ -0,0 +1,17 @@ +/* + * Logitech PS/2++ mouse driver header + * + * Copyright (c) 2003 Vojtech Pavlik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifndef _LOGIPS2PP_H +#define _LOGIPS2PP_H +struct psmouse; +void ps2pp_process_packet(struct psmouse *psmouse); +void ps2pp_set_800dpi(struct psmouse *psmouse); +int ps2pp_detect_model(struct psmouse *psmouse); +#endif diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index e7d699c52fc5..030d23149e2e 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -19,13 +19,23 @@ #include #include "psmouse.h" #include "synaptics.h" +#include "logips2pp.h" MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PS/2 mouse driver"); MODULE_PARM(psmouse_noext, "1i"); +MODULE_PARM_DESC(psmouse_noext, "Disable any protocol extensions. Useful for KVM switches."); +MODULE_PARM(psmouse_resolution, "i"); +MODULE_PARM_DESC(psmouse_resolution, "Resolution, in dpi."); +MODULE_PARM(psmouse_smartscroll, "i"); +MODULE_PARM_DESC(psmouse_smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); MODULE_LICENSE("GPL"); +#define PSMOUSE_LOGITECH_SMARTSCROLL 1 + static int psmouse_noext; +int psmouse_resolution; +int psmouse_smartscroll = PSMOUSE_LOGITECH_SMARTSCROLL; static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"}; @@ -45,43 +55,8 @@ static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs * The PS2++ protocol is a little bit complex */ - if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) { - - if ((packet[0] & 0x40) == 0x40 && abs((int)packet[1] - (((int)packet[0] & 0x10) << 4)) > 191 ) { - - switch (((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0x0c)) { - - case 1: /* Mouse extra info */ - - input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, - (int) (packet[2] & 8) - (int) (packet[2] & 7)); - input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); - input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); - - break; - - case 3: /* TouchPad extra info */ - - input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, - (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); - packet[0] = packet[2] | 0x08; - - break; - -#ifdef DEBUG - default: - printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", - ((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0x0c)); -#endif - - } - - packet[0] &= 0x0f; - packet[1] = 0; - packet[2] = 0; - - } - } + if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) + ps2pp_process_packet(psmouse); /* * Scroll wheel on IntelliMice, scroll buttons on NetMice @@ -258,33 +233,6 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) return 0; } -/* - * psmouse_ps2pp_cmd() sends a PS2++ command, sliced into two bit - * pieces through the SETRES command. This is needed to send extended - * commands to mice on notebooks that try to understand the PS/2 protocol - * Ugly. - */ - -static int psmouse_ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) -{ - unsigned char d; - int i; - - if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) - return -1; - - for (i = 6; i >= 0; i -= 2) { - d = (command >> i) & 3; - if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES)) - return -1; - } - - if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) - return -1; - - return 0; -} - /* * psmouse_extensions() probes for any extensions to the basic PS/2 protocol * the mouse may have. @@ -353,73 +301,13 @@ static int psmouse_extensions(struct psmouse *psmouse) psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + param[1] = 0; psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); if (param[1]) { - - int i; - static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 }; - static int logitech_wheel[] = { 52, 53, 75, 76, 80, 81, 83, 88, -1 }; - static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75, - 76, 80, 81, 83, 88, 96, 97, -1 }; - psmouse->vendor = "Logitech"; - psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); - - if (param[1] < 3) - clear_bit(BTN_MIDDLE, psmouse->dev.keybit); - if (param[1] < 2) - clear_bit(BTN_RIGHT, psmouse->dev.keybit); - - psmouse->type = PSMOUSE_PS2; - - for (i = 0; logitech_ps2pp[i] != -1; i++) - if (logitech_ps2pp[i] == psmouse->model) - psmouse->type = PSMOUSE_PS2PP; - - if (psmouse->type == PSMOUSE_PS2PP) { - - for (i = 0; logitech_4btn[i] != -1; i++) - if (logitech_4btn[i] == psmouse->model) - set_bit(BTN_SIDE, psmouse->dev.keybit); - - for (i = 0; logitech_wheel[i] != -1; i++) - if (logitech_wheel[i] == psmouse->model) { - set_bit(REL_WHEEL, psmouse->dev.relbit); - psmouse->name = "Wheel Mouse"; - } - -/* - * Do Logitech PS2++ / PS2T++ magic init. - */ - - if (psmouse->model == 97) { /* TouchPad 3 */ - - set_bit(REL_WHEEL, psmouse->dev.relbit); - set_bit(REL_HWHEEL, psmouse->dev.relbit); - - param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ - psmouse_command(psmouse, param, 0x30d1); - param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ - psmouse_command(psmouse, param, 0x30d1); - param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ - psmouse_command(psmouse, param, 0x30d1); - - param[0] = 0; - if (!psmouse_command(psmouse, param, 0x13d1) && - param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) - return PSMOUSE_PS2TPP; - - } else { - param[0] = param[1] = param[2] = 0; - - psmouse_ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ - psmouse_ps2pp_cmd(psmouse, param, 0xDB); - - if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && - (param[2] & 3) == ((param[1] >> 2) & 3)) - return PSMOUSE_PS2PP; - } - } + int type = ps2pp_detect_model(psmouse, param); + if (type) + return type; } /* @@ -507,6 +395,31 @@ static int psmouse_probe(struct psmouse *psmouse) return psmouse->type = psmouse_extensions(psmouse); } +/* + * Here we set the mouse resolution. + */ + +static void psmouse_set_resolution(struct psmouse *psmouse) +{ + unsigned char param[1]; + + if (psmouse->type == PSMOUSE_PS2PP && psmouse_resolution > 400) { + ps2pp_set_800dpi(psmouse); + return; + } + + if (!psmouse_resolution || psmouse_resolution >= 200) + param[0] = 3; + else if (psmouse_resolution >= 100) + param[0] = 2; + else if (psmouse_resolution >= 50) + param[0] = 1; + else if (psmouse_resolution) + param[0] = 0; + + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); +} + /* * psmouse_initialize() initializes the mouse to a sane state. */ @@ -519,7 +432,6 @@ static void psmouse_initialize(struct psmouse *psmouse) * We set the mouse report rate to a highest possible value. * We try 100 first in case mouse fails to set 200. */ - param[0] = 100; psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); @@ -530,8 +442,7 @@ static void psmouse_initialize(struct psmouse *psmouse) * We also set the resolution and scaling. */ - param[0] = 3; - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_set_resolution(psmouse); psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); /* @@ -638,12 +549,28 @@ static struct serio_dev psmouse_dev = { }; #ifndef MODULE -static int __init psmouse_setup(char *str) +static int __init psmouse_noext_setup(char *str) { psmouse_noext = 1; return 1; } -__setup("psmouse_noext", psmouse_setup); + +static int __init psmouse_resolution_setup(char *str) +{ + get_option(&str, &psmouse_resolution); + return 1; +} + +static int __init psmouse_smartscroll_setup(char *str) +{ + get_option(&str, &psmouse_smartscroll); + return 1; +} + +__setup("psmouse_noext", psmouse_noext_setup); +__setup("psmouse_resolution=", psmouse_resolution_setup); +__setup("psmouse_smartscroll=", psmouse_smartscroll_setup); + #endif int __init psmouse_init(void) diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index f2e9baa53d3f..05a24de18d7d 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -46,4 +46,6 @@ struct psmouse { int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command); +extern int psmouse_smartscroll; + #endif /* _PSMOUSE_H */ diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 73ced749126a..5fa695eb774e 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -171,9 +171,9 @@ static void print_ident(struct synaptics_data *priv) static int query_hardware(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; - int retries = 3; + int retries = 0; - while ((retries++ <= 3) && synaptics_reset(psmouse)) + while ((retries++ < 3) && synaptics_reset(psmouse)) printk(KERN_ERR "synaptics reset failed\n"); if (synaptics_identify(psmouse, &priv->identity)) @@ -266,8 +266,7 @@ void synaptics_disconnect(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ -static void synaptics_parse_hw_state(struct synaptics_data *priv, - struct synaptics_hw_state *hw) +static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw) { unsigned char *buf = priv->proto_buf; diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 4acaff4ef070..6e3e029a3bdd 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -9,21 +9,11 @@ #ifndef _SYNAPTICS_H #define _SYNAPTICS_H -#ifdef CONFIG_MOUSE_PS2_SYNAPTICS extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs); extern int synaptics_init(struct psmouse *psmouse); extern void synaptics_disconnect(struct psmouse *psmouse); -#else - -static inline void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) {} -static inline int synaptics_init(struct psmouse *psmouse) { return -1; } -static inline void synaptics_disconnect(struct psmouse *psmouse) {} - -#endif - - /* synaptics queries */ #define SYN_QUE_IDENTIFY 0x00 #define SYN_QUE_MODES 0x01 diff --git a/include/linux/input.h b/include/linux/input.h index 20dfaad9fe4f..da49f7ee0f18 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -358,6 +358,7 @@ struct input_absinfo { #define BTN_EXTRA 0x114 #define BTN_FORWARD 0x115 #define BTN_BACK 0x116 +#define BTN_TASK 0x117 #define BTN_JOYSTICK 0x120 #define BTN_TRIGGER 0x120 -- cgit v1.2.3 From ae86fb4fb0a98bbb66461209710ceea881fcf0ec Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 20 Jun 2003 20:18:55 -0700 Subject: [PATCH] Remove spinlock workaround for pre 2.95 gccs Remove the empty initializer workaround that was added for egcs 1.1. Only 2.95+ is supported now, so all compilers should support empty structures. The if just checked for __GNUC__, which means that 2.95 got the workaround (and the incompatibility) too even though it didn't need it. Advantage is that gcc 2.95 and 3.x compiled kernels are now potentially binary compatible. Module loading still checks the compiler version, but it might be removable. --- include/linux/spinlock.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 148ea9d43873..4e2c1973ae67 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -146,13 +146,8 @@ typedef struct { /* * gcc versions before ~2.95 have a nasty bug with empty initializers. */ -#if (__GNUC__ > 2) - typedef struct { } spinlock_t; - #define SPIN_LOCK_UNLOCKED (spinlock_t) { } -#else - typedef struct { int gcc_is_buggy; } spinlock_t; - #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } -#endif +typedef struct { } spinlock_t; +#define SPIN_LOCK_UNLOCKED (spinlock_t) { } /* * If CONFIG_SMP is unset, declare the _raw_* definitions as nops -- cgit v1.2.3 From 7cd3f1998e71a77f74589940980a96c3caec7bca Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 20 Jun 2003 20:23:22 -0700 Subject: [PATCH] More care in sys_setaffinity We currently mask off offline CPUs in both set_cpus_allowed and sys_sched_setaffinity. This is firstly redundant, and secondly erroneous when more CPUs come online (eg. setting affinity to all 1s should mean all CPUs, including future ones). We mask with cpu_online_map() in sys_sched_getaffinity *anyway* (which is another issue, since this is not valid with changing of online cpus either), so userspace won't see any difference. This patch makes set_cpus_allowed() return -errno, and check that in sys_sched_setaffinity. --- Documentation/sched-coding.txt | 2 +- include/linux/sched.h | 7 +++++-- kernel/sched.c | 21 +++++++-------------- 3 files changed, 13 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/Documentation/sched-coding.txt b/Documentation/sched-coding.txt index 585b302beb9d..385f9eff6534 100644 --- a/Documentation/sched-coding.txt +++ b/Documentation/sched-coding.txt @@ -103,7 +103,7 @@ void set_user_nice(task_t *p, long nice) Sets the "nice" value of task p to the given value. int setscheduler(pid_t pid, int policy, struct sched_param *param) Sets the scheduling policy and parameters for the given pid. -void set_cpus_allowed(task_t *p, unsigned long new_mask) +int set_cpus_allowed(task_t *p, unsigned long new_mask) Sets a given task's CPU affinity and migrates it to a proper cpu. Callers must have a valid reference to the task and assure the task not exit prematurely. No locks can be held during the call. diff --git a/include/linux/sched.h b/include/linux/sched.h index f5cdfefc5b05..ca97376901b0 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -483,9 +483,12 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) #define PF_LESS_THROTTLE 0x01000000 /* Throttle me less: I clena memory */ #ifdef CONFIG_SMP -extern void set_cpus_allowed(task_t *p, unsigned long new_mask); +extern int set_cpus_allowed(task_t *p, unsigned long new_mask); #else -# define set_cpus_allowed(p, new_mask) do { } while (0) +static inline int set_cpus_allowed(task_t *p, unsigned long new_mask) +{ + return 0; +} #endif #ifdef CONFIG_NUMA diff --git a/kernel/sched.c b/kernel/sched.c index aa79183f1453..9566cd11de18 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1880,10 +1880,6 @@ asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) return -EFAULT; - new_mask &= cpu_online_map; - if (!new_mask) - return -EINVAL; - read_lock(&tasklist_lock); p = find_process_by_pid(pid); @@ -1905,8 +1901,7 @@ asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, !capable(CAP_SYS_NICE)) goto out_unlock; - retval = 0; - set_cpus_allowed(p, new_mask); + retval = set_cpus_allowed(p, new_mask); out_unlock: put_task_struct(p); @@ -2269,17 +2264,14 @@ typedef struct { * task must not exit() & deallocate itself prematurely. The * call is not atomic; no spinlocks may be held. */ -void set_cpus_allowed(task_t *p, unsigned long new_mask) +int set_cpus_allowed(task_t *p, unsigned long new_mask) { unsigned long flags; migration_req_t req; runqueue_t *rq; -#if 0 /* FIXME: Grab cpu_lock, return error on this case. --RR */ - new_mask &= cpu_online_map; - if (!new_mask) - BUG(); -#endif + if (any_online_cpu(new_mask) == NR_CPUS) + return -EINVAL; rq = task_rq_lock(p, &flags); p->cpus_allowed = new_mask; @@ -2289,7 +2281,7 @@ void set_cpus_allowed(task_t *p, unsigned long new_mask) */ if (new_mask & (1UL << task_cpu(p))) { task_rq_unlock(rq, &flags); - return; + return 0; } /* * If the task is not on a runqueue (and not running), then @@ -2298,7 +2290,7 @@ void set_cpus_allowed(task_t *p, unsigned long new_mask) if (!p->array && !task_running(rq, p)) { set_task_cpu(p, any_online_cpu(p->cpus_allowed)); task_rq_unlock(rq, &flags); - return; + return 0; } init_completion(&req.done); req.task = p; @@ -2308,6 +2300,7 @@ void set_cpus_allowed(task_t *p, unsigned long new_mask) wake_up_process(rq->migration_thread); wait_for_completion(&req.done); + return 0; } /* Move (not current) task off this cpu, onto dest cpu. */ -- cgit v1.2.3 From eb63bae150b444d67e7bbd4d61611112286388e5 Mon Sep 17 00:00:00 2001 From: "Andries E. Brouwer" Date: Sun, 22 Jun 2003 04:37:32 -0700 Subject: [PATCH] loop.c cleanups This does the following: - remove trailing spaces - make loop.h independent by including bio.h, blk.h, spinlock.h - replace the lock/unlock functions by module_get/module_put; in struct loop this is the change - void (*lock)(struct loop_device *); - void (*unlock)(struct loop_device *); + struct module *owner; - replace the integer lo_encrypt_type by the pointer lo_encryption; there was a race with loop_unregister_transfer - fixed an off-by-one in loop_register_transfer This is Step 1 of a series of half a dozen or so. Half of the above is from Jari. Anything that is wrong is mine. --- drivers/block/loop.c | 207 ++++++++++++++++++++++++++++----------------------- include/linux/loop.h | 13 ++-- 2 files changed, 121 insertions(+), 99 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b0fefe1460cc..5e08a760f1d9 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -2,7 +2,7 @@ * linux/drivers/block/loop.c * * Written by Theodore Ts'o, 3/29/93 - * + * * Copyright 1993 by Theodore Ts'o. Redistribution of this file is * permitted under the GNU General Public License. * @@ -21,12 +21,12 @@ * Loadable modules and other fixes by AK, 1998 * * Make real block number available to downstream transfer functions, enables - * CBC (and relatives) mode encryption requiring unique IVs per data block. + * CBC (and relatives) mode encryption requiring unique IVs per data block. * Reed H. Petty, rhp@draper.net * * Maximum number of loop devices now dynamic via max_loop module parameter. * Russell Kroll 19990701 - * + * * Maximum number of loop devices when compiled-in now selectable by passing * max_loop=<1-255> to the kernel on boot. * Erik I. Bolsų, , Oct 31, 1999 @@ -40,19 +40,19 @@ * Heinz Mauelshagen , Feb 2002 * * Still To Fix: - * - Advisory locking is ignored here. - * - Should use an own CAP_* category instead of CAP_SYS_ADMIN + * - Advisory locking is ignored here. + * - Should use an own CAP_* category instead of CAP_SYS_ADMIN * * WARNING/FIXME: * - The block number as IV passing to low level transfer functions is broken: * it passes the underlying device's block number instead of the - * offset. This makes it change for a given block when the file is - * moved/restored/copied and also doesn't work over NFS. + * offset. This makes it change for a given block when the file is + * moved/restored/copied and also doesn't work over NFS. * AV, Feb 12, 2000: we pass the logical block number now. It fixes the * problem above. Encryption modules that used to rely on the old scheme * should just call ->i_mapping->bmap() to calculate the physical block * number. - */ + */ #include #include @@ -60,12 +60,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -127,24 +125,25 @@ static int xor_status(struct loop_device *lo, const struct loop_info64 *info) return 0; } -struct loop_func_table none_funcs = { +struct loop_func_table none_funcs = { .number = LO_CRYPT_NONE, .transfer = transfer_none, }; -struct loop_func_table xor_funcs = { +struct loop_func_table xor_funcs = { .number = LO_CRYPT_XOR, .transfer = transfer_xor, .init = xor_status }; -/* xfer_funcs[0] is special - its release function is never called */ +/* xfer_funcs[0] is special - its release function is never called */ struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { &none_funcs, - &xor_funcs + &xor_funcs }; -static int figure_loop_size(struct loop_device *lo) +static int +figure_loop_size(struct loop_device *lo) { loff_t size = lo->lo_backing_file->f_dentry->d_inode->i_mapping->host->i_size; sector_t x; @@ -154,15 +153,17 @@ static int figure_loop_size(struct loop_device *lo) */ size = (size - lo->lo_offset) >> 9; x = (sector_t)size; + if ((loff_t)x != size) return -EFBIG; - set_capacity(disks[lo->lo_number], size); + set_capacity(disks[lo->lo_number], x); return 0; } -static inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf, - char *lbuf, int size, sector_t rblock) +static inline int +lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf, + char *lbuf, int size, sector_t rblock) { if (!lo->transfer) return 0; @@ -614,9 +615,12 @@ static int loop_thread(void *data) daemonize("loop%d", lo->lo_number); - current->flags |= PF_IOTHREAD; /* loop can be used in an encrypted device - hence, it mustn't be stopped at all because it could - be indirectly used during suspension */ + /* + * loop can be used in an encrypted device, + * hence, it mustn't be stopped at all + * because it could be indirectly used during suspension + */ + current->flags |= PF_IOTHREAD; set_user_nice(current, -20); @@ -771,36 +775,42 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, return error; } -static int loop_release_xfer(struct loop_device *lo) +static int +loop_release_xfer(struct loop_device *lo) { - int err = 0; - if (lo->lo_encrypt_type) { - struct loop_func_table *xfer= xfer_funcs[lo->lo_encrypt_type]; - if (xfer && xfer->release) - err = xfer->release(lo); - if (xfer && xfer->unlock) - xfer->unlock(lo); - lo->lo_encrypt_type = 0; + int err = 0; + struct loop_func_table *xfer = lo->lo_encryption; + + if (xfer) { + if (xfer->release) + err = xfer->release(lo); + lo->transfer = NULL; + lo->lo_encryption = NULL; + module_put(xfer->owner); } return err; } static int -loop_init_xfer(struct loop_device *lo, int type, const struct loop_info64 *i) +loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, + const struct loop_info64 *i) { - int err = 0; - if (type) { - struct loop_func_table *xfer = xfer_funcs[type]; + int err = 0; + + if (xfer) { + struct module *owner = xfer->owner; + + if (!try_module_get(owner)) + return -EINVAL; if (xfer->init) err = xfer->init(lo, i); - if (!err) { - lo->lo_encrypt_type = type; - if (xfer->lock) - xfer->lock(lo); - } + if (err) + module_put(owner); + else + lo->lo_encryption = xfer; } return err; -} +} static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) { @@ -809,9 +819,11 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) if (lo->lo_state != Lo_bound) return -ENXIO; + if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */ return -EBUSY; - if (filp==NULL) + + if (filp == NULL) return -EINVAL; spin_lock_irq(&lo->lo_lock); @@ -828,7 +840,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) lo->transfer = NULL; lo->ioctl = NULL; lo->lo_device = NULL; - lo->lo_encrypt_type = 0; + lo->lo_encryption = NULL; lo->lo_offset = 0; lo->lo_encrypt_key_size = 0; lo->lo_flags = 0; @@ -849,49 +861,55 @@ static int loop_set_status(struct loop_device *lo, const struct loop_info64 *info) { int err; - unsigned int type; - loff_t offset; + struct loop_func_table *xfer; - if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && + if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && !capable(CAP_SYS_ADMIN)) return -EPERM; if (lo->lo_state != Lo_bound) return -ENXIO; if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; - type = info->lo_encrypt_type; - if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL) - return -EINVAL; - if (type == LO_CRYPT_XOR && info->lo_encrypt_key_size == 0) - return -EINVAL; err = loop_release_xfer(lo); - if (!err) - err = loop_init_xfer(lo, type, info); + if (err) + return err; - offset = lo->lo_offset; - if (offset != info->lo_offset) { - lo->lo_offset = info->lo_offset; - if (figure_loop_size(lo)){ - err = -EFBIG; - lo->lo_offset = offset; - } - } + if (info->lo_encrypt_type) { + unsigned int type = info->lo_encrypt_type; + if (type >= MAX_LO_CRYPT) + return -EINVAL; + xfer = xfer_funcs[type]; + if (xfer == NULL) + return -EINVAL; + } else + xfer = NULL; + + err = loop_init_xfer(lo, xfer, info); if (err) - return err; + return err; + + if (lo->lo_offset != info->lo_offset) { + lo->lo_offset = info->lo_offset; + if (figure_loop_size(lo)) + return -EFBIG; + } strlcpy(lo->lo_name, info->lo_name, LO_NAME_SIZE); - lo->transfer = xfer_funcs[type]->transfer; - lo->ioctl = xfer_funcs[type]->ioctl; + if (!xfer) + xfer = &none_funcs; + lo->transfer = xfer->transfer; + lo->ioctl = xfer->ioctl; + lo->lo_encrypt_key_size = info->lo_encrypt_key_size; lo->lo_init[0] = info->lo_init[0]; lo->lo_init[1] = info->lo_init[1]; if (info->lo_encrypt_key_size) { - memcpy(lo->lo_encrypt_key, info->lo_encrypt_key, + memcpy(lo->lo_encrypt_key, info->lo_encrypt_key, info->lo_encrypt_key_size); - lo->lo_key_owner = current->uid; + lo->lo_key_owner = current->uid; } return 0; @@ -917,7 +935,8 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info) info->lo_offset = lo->lo_offset; info->lo_flags = lo->lo_flags; strlcpy(info->lo_name, lo->lo_name, LO_NAME_SIZE); - info->lo_encrypt_type = lo->lo_encrypt_type; + info->lo_encrypt_type = + lo->lo_encryption ? lo->lo_encryption->number : 0; if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) { info->lo_encrypt_key_size = lo->lo_encrypt_key_size; memcpy(info->lo_encrypt_key, lo->lo_encrypt_key, @@ -1060,30 +1079,22 @@ static int lo_ioctl(struct inode * inode, struct file * file, static int lo_open(struct inode *inode, struct file *file) { struct loop_device *lo = inode->i_bdev->bd_disk->private_data; - int type; down(&lo->lo_ctl_mutex); - - type = lo->lo_encrypt_type; - if (type && xfer_funcs[type] && xfer_funcs[type]->lock) - xfer_funcs[type]->lock(lo); lo->lo_refcnt++; up(&lo->lo_ctl_mutex); + return 0; } static int lo_release(struct inode *inode, struct file *file) { struct loop_device *lo = inode->i_bdev->bd_disk->private_data; - int type; down(&lo->lo_ctl_mutex); - type = lo->lo_encrypt_type; --lo->lo_refcnt; - if (xfer_funcs[type] && xfer_funcs[type]->unlock) - xfer_funcs[type]->unlock(lo); - up(&lo->lo_ctl_mutex); + return 0; } @@ -1103,34 +1114,41 @@ MODULE_LICENSE("GPL"); int loop_register_transfer(struct loop_func_table *funcs) { - if ((unsigned)funcs->number > MAX_LO_CRYPT || xfer_funcs[funcs->number]) + unsigned int n = funcs->number; + + if (n >= MAX_LO_CRYPT || xfer_funcs[n]) return -EINVAL; - xfer_funcs[funcs->number] = funcs; - return 0; + xfer_funcs[n] = funcs; + return 0; } int loop_unregister_transfer(int number) { - struct loop_device *lo; - - if ((unsigned)number >= MAX_LO_CRYPT) - return -EINVAL; - for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) { - int type = lo->lo_encrypt_type; - if (type == number) { - xfer_funcs[type]->release(lo); - lo->transfer = NULL; - lo->lo_encrypt_type = 0; - } + unsigned int n = number; + struct loop_device *lo; + struct loop_func_table *xfer; + + if (n == 0 || n >= MAX_LO_CRYPT || (xfer = xfer_funcs[n]) == NULL) + return -EINVAL; + + xfer_funcs[n] = NULL; + + for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) { + down(&lo->lo_ctl_mutex); + + if (lo->lo_encryption == xfer) + loop_release_xfer(lo); + + up(&lo->lo_ctl_mutex); } - xfer_funcs[number] = NULL; - return 0; + + return 0; } EXPORT_SYMBOL(loop_register_transfer); EXPORT_SYMBOL(loop_unregister_transfer); -int __init loop_init(void) +int __init loop_init(void) { int i; @@ -1190,9 +1208,10 @@ out_mem: return -ENOMEM; } -void loop_exit(void) +void loop_exit(void) { int i; + for (i = 0; i < max_loop; i++) { del_gendisk(disks[i]); put_disk(disks[i]); diff --git a/include/linux/loop.h b/include/linux/loop.h index 6f78f33cbac9..424ddff9b70a 100644 --- a/include/linux/loop.h +++ b/include/linux/loop.h @@ -14,6 +14,9 @@ #define LO_KEY_SIZE 32 #ifdef __KERNEL__ +#include +#include +#include /* Possible states of device */ enum { @@ -22,18 +25,20 @@ enum { Lo_rundown, }; +struct loop_func_table; + struct loop_device { int lo_number; int lo_refcnt; int lo_offset; - int lo_encrypt_type; - int lo_encrypt_key_size; int lo_flags; int (*transfer)(struct loop_device *, int cmd, char *raw_buf, char *loop_buf, int size, sector_t real_block); char lo_name[LO_NAME_SIZE]; char lo_encrypt_key[LO_KEY_SIZE]; + int lo_encrypt_key_size; + struct loop_func_table *lo_encryption; __u32 lo_init[2]; uid_t lo_key_owner; /* Who set the key */ int (*ioctl)(struct loop_device *, int cmd, @@ -129,9 +134,7 @@ struct loop_func_table { /* release is called from loop_unregister_transfer or clr_fd */ int (*release)(struct loop_device *); int (*ioctl)(struct loop_device *, int cmd, unsigned long arg); - /* lock and unlock manage the module use counts */ - void (*lock)(struct loop_device *); - void (*unlock)(struct loop_device *); + struct module *owner; }; int loop_register_transfer(struct loop_func_table *funcs); -- cgit v1.2.3 From d05828871c2f5a0475e6071363232c48ba43b2c8 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 23 Jun 2003 15:35:39 +0100 Subject: MTD driver cleanups... - Fix AFS partitioning oops when no partitions are found - Add missing spin_unlock, optimise buffer writes in Intel NOR driver - Fix DiskOnChip Millennium Plus register OutputControl register definition - Fix DiskOnChip drivers to indicate correct ECC type - Fix map drivers to use ARRAY_SIZE instead of redefining it. - Make uCLinux map driver depend on !MMU - Fix NAND write verify problem on some chips - Other trivia from Rusty. --- drivers/mtd/afs.c | 16 +++++---- drivers/mtd/chips/amd_flash.c | 3 +- drivers/mtd/chips/cfi_cmdset_0001.c | 47 ++++++++++++++++--------- drivers/mtd/devices/doc2000.c | 3 +- drivers/mtd/devices/doc2001.c | 5 +-- drivers/mtd/devices/doc2001plus.c | 3 +- drivers/mtd/inftlmount.c | 13 ++++--- drivers/mtd/maps/Kconfig | 4 +-- drivers/mtd/maps/arctic-mtd.c | 47 ++++++++++++++----------- drivers/mtd/maps/ebony.c | 8 ++--- drivers/mtd/maps/edb7312.c | 5 ++- drivers/mtd/maps/elan-104nc.c | 19 +++------- drivers/mtd/maps/impa7.c | 69 ++++++++++++++++--------------------- drivers/mtd/maps/iq80310.c | 6 ++-- drivers/mtd/maps/lubbock-flash.c | 6 ++-- drivers/mtd/maps/pb1xxx-flash.c | 7 ++-- drivers/mtd/maps/tqm8xxl.c | 8 ++--- drivers/mtd/mtdpart.c | 4 +-- drivers/mtd/nand/autcpu12.c | 3 +- drivers/mtd/nand/nand.c | 18 ++++++++-- include/linux/mtd/doc2000.h | 4 +-- 21 files changed, 152 insertions(+), 146 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 6640ebc8e994..527975d27176 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: afs.c,v 1.11 2003/05/16 17:08:24 dwmw2 Exp $ + $Id: afs.c,v 1.12 2003/06/13 15:31:06 rmk Exp $ ======================================================================*/ @@ -76,17 +76,19 @@ afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start, return ret; } + ret = 1; + /* * Does it contain the magic number? */ if (fs.signature != 0xa0ffff9f) - ret = 1; + ret = 0; /* * Don't touch the SIB. */ if (fs.type == 2) - ret = 1; + ret = 0; *iis_start = fs.image_info_base & mask; *img_start = fs.image_start & mask; @@ -96,14 +98,14 @@ afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start, * be located after the footer structure. */ if (*iis_start >= ptr) - ret = 1; + ret = 0; /* * Check the start of this image. The image * data can not be located after this block. */ if (*img_start > off) - ret = 1; + ret = 0; return ret; } @@ -152,7 +154,7 @@ static int parse_afs_partitions(struct mtd_info *mtd, ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask); if (ret < 0) break; - if (ret == 1) + if (ret == 0) continue; ret = afs_read_iis(mtd, &iis, iis_ptr); @@ -185,7 +187,7 @@ static int parse_afs_partitions(struct mtd_info *mtd, ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask); if (ret < 0) break; - if (ret == 1) + if (ret == 0) continue; /* Read the image info block */ diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c index 78cdbfa561b1..6021b8b3c1fb 100644 --- a/drivers/mtd/chips/amd_flash.c +++ b/drivers/mtd/chips/amd_flash.c @@ -3,7 +3,7 @@ * * Author: Jonas Holmberg * - * $Id: amd_flash.c,v 1.22 2003/05/28 13:47:19 dwmw2 Exp $ + * $Id: amd_flash.c,v 1.23 2003/06/12 09:24:13 dwmw2 Exp $ * * Copyright (c) 2001 Axis Communications AB * @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index e395f642b50a..82fb2a60808f 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.123 2003/05/28 12:51:48 dwmw2 Exp $ + * $Id: cfi_cmdset_0001.c,v 1.126 2003/06/23 07:45:48 dwmw2 Exp $ * * * 10/10/2000 Nicolas Pitre @@ -936,7 +936,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, struct cfi_private *cfi = map->fldrv_priv; cfi_word status, status_OK; unsigned long cmd_adr, timeo; - int wbufsize, z, ret=0; + int wbufsize, z, ret=0, bytes, words; wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize; adr += chip->start; @@ -995,10 +995,13 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, } /* Write length of data to come */ - cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr ); + bytes = len & (CFIDEV_BUSWIDTH-1); + words = len / CFIDEV_BUSWIDTH; + cfi_write(map, CMD(words - !bytes), cmd_adr ); /* Write data */ - for (z = 0; z < len; z += CFIDEV_BUSWIDTH) { + z = 0; + while(z < words * CFIDEV_BUSWIDTH) { if (cfi_buswidth_is_1()) { map_write8 (map, *((__u8*)buf)++, adr+z); } else if (cfi_buswidth_is_2()) { @@ -1011,6 +1014,26 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, ret = -EINVAL; goto out; } + z += CFIDEV_BUSWIDTH; + } + if (bytes) { + int i = 0, n = 0; + u_char tmp_buf[8], *tmp_p = tmp_buf; + + while (bytes--) + tmp_buf[i++] = buf[n++]; + while (i < CFIDEV_BUSWIDTH) + tmp_buf[i++] = 0xff; + if (cfi_buswidth_is_2()) { + map_write16 (map, *((__u16*)tmp_p)++, adr+z); + } else if (cfi_buswidth_is_4()) { + map_write32 (map, *((__u32*)tmp_p)++, adr+z); + } else if (cfi_buswidth_is_8()) { + map_write64 (map, *((__u64*)tmp_p)++, adr+z); + } else { + ret = -EINVAL; + goto out; + } } /* GO GO GO */ cfi_write(map, CMD(0xd0), cmd_adr); @@ -1119,12 +1142,12 @@ static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, } /* Write buffer is worth it only if more than one word to write... */ - while(len > CFIDEV_BUSWIDTH) { + while(len) { /* We must not cross write block boundaries */ int size = wbufsize - (ofs & (wbufsize-1)); if (size > len) - size = len & ~(CFIDEV_BUSWIDTH-1); + size = len; ret = do_write_buffer(map, &cfi->chips[chipnum], ofs, buf, size); if (ret) @@ -1142,17 +1165,6 @@ static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, return 0; } } - - /* ... and write the remaining bytes */ - if (len > 0) { - size_t local_retlen; - ret = cfi_intelext_write_words(mtd, ofs + (chipnum << cfi->chipshift), - len, &local_retlen, buf); - if (ret) - return ret; - (*retlen) += local_retlen; - } - return 0; } @@ -1423,6 +1435,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd) * with the chip now anyway. */ } + spin_unlock(chip->mutex); } /* Unlock the chips again */ diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 7365633bbb89..5cb921d2197a 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -4,7 +4,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse * - * $Id: doc2000.c,v 1.52 2003/05/20 21:03:07 dwmw2 Exp $ + * $Id: doc2000.c,v 1.53 2003/06/11 09:45:19 dwmw2 Exp $ */ #include @@ -553,6 +553,7 @@ static void DoC2k_init(struct mtd_info *mtd) mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; + mtd->ecctype = MTD_ECC_RS_DiskOnChip; mtd->size = 0; mtd->erasesize = 0; mtd->oobblock = 512; diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 6cd56efbaf5f..25eea68ad774 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -4,7 +4,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse * - * $Id: doc2001.c,v 1.40 2003/05/20 21:03:07 dwmw2 Exp $ + * $Id: doc2001.c,v 1.41 2003/06/11 09:45:19 dwmw2 Exp $ */ #include @@ -359,9 +359,10 @@ static void DoCMil_init(struct mtd_info *mtd) mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; + mtd->ecctype = MTD_ECC_RS_DiskOnChip; mtd->size = 0; - /* FIXME: erase size is not always 8kB */ + /* FIXME: erase size is not always 8KiB */ mtd->erasesize = 0x2000; mtd->oobblock = 512; diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index dca160a5842e..e5e5fdaeb32d 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -6,7 +6,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse * - * $Id: doc2001plus.c,v 1.4 2003/05/23 11:28:46 dwmw2 Exp $ + * $Id: doc2001plus.c,v 1.5 2003/06/11 09:45:19 dwmw2 Exp $ */ #include @@ -458,6 +458,7 @@ static void DoCMilPlus_init(struct mtd_info *mtd) mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; + mtd->ecctype = MTD_ECC_RS_DiskOnChip; mtd->size = 0; mtd->erasesize = 0; diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index abe3957c2f9d..042c4eeadf8e 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -8,7 +8,7 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: inftlmount.c,v 1.9 2003/05/23 11:35:07 dwmw2 Exp $ + * $Id: inftlmount.c,v 1.11 2003/06/23 07:39:21 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,7 +25,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define __NO_VERSION__ #include #include #include @@ -42,7 +41,7 @@ #include #include -char inftlmountrev[]="$Revision: 1.9 $"; +char inftlmountrev[]="$Revision: 1.11 $"; /* * find_boot_record: Find the INFTL Media Header and its Spare copy which @@ -242,7 +241,7 @@ static int find_boot_record(struct INFTLrecord *inftl) } if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) { printk(KERN_WARNING "INFTL: Media Header " - "Parition %d sanity check failed\n" + "Partition %d sanity check failed\n" " firstUnit %d : lastUnit %d > " "virtualUnits %d\n", i, ip->lastUnit, ip->firstUnit, ip->Reserved0); @@ -250,7 +249,7 @@ static int find_boot_record(struct INFTLrecord *inftl) } if (ip->Reserved1 != 0) { printk(KERN_WARNING "INFTL: Media Header " - "Parition %d sanity check failed: " + "Partition %d sanity check failed: " "Reserved1 %d != 0\n", i, ip->Reserved1); return -1; @@ -261,7 +260,7 @@ static int find_boot_record(struct INFTLrecord *inftl) } if (i >= 4) { - printk(KERN_WARNING "INFTL: Media Header Parition " + printk(KERN_WARNING "INFTL: Media Header Partition " "sanity check failed:\n No partition " "marked as Disk Partition\n"); return -1; @@ -630,7 +629,7 @@ int INFTL_mount(struct INFTLrecord *s) if (prev_block < s->nb_blocks) prev_block += s->firstEUN; - /* Already explored paritial chain? */ + /* Already explored partial chain? */ if (s->PUtable[block] != BLOCK_NOTEXPLORED) { /* Check if chain for this logical */ if (logical_block == first_logical_block) { diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index a0fc12a90d92..d73559084fb9 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.11 2003/05/28 15:16:56 dwmw2 Exp $ +# $Id: Kconfig,v 1.12 2003/06/23 07:38:11 dwmw2 Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -476,7 +476,7 @@ config MTD_PCMCIA config MTD_UCLINUX tristate "Generic uClinux RAM/ROM filesystem support" - depends on MTD_PARTITIONS + depends on MTD_PARTITIONS && !MMU help Map driver to support image based filesystems for uClinux. diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c index 974e7ceb94f8..c111b2d1f4c1 100644 --- a/drivers/mtd/maps/arctic-mtd.c +++ b/drivers/mtd/maps/arctic-mtd.c @@ -1,5 +1,5 @@ /* - * $Id: arctic-mtd.c,v 1.8 2003/05/21 12:45:17 dwmw2 Exp $ + * $Id: arctic-mtd.c,v 1.10 2003/06/02 16:37:59 trini Exp $ * * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for * IBM 405LP Arctic boards. @@ -45,18 +45,23 @@ #include /* - * fe000000 -- ff9fffff Arctic FFS (26MB) - * ffa00000 -- fff5ffff kernel (5.504MB) - * fff60000 -- ffffffff firmware (640KB) + * 0 : 0xFE00 0000 - 0xFEFF FFFF : Filesystem 1 (16MiB) + * 1 : 0xFF00 0000 - 0xFF4F FFFF : kernel (5.12MiB) + * 2 : 0xFF50 0000 - 0xFFF5 FFFF : Filesystem 2 (10.624MiB) (if non-XIP) + * 3 : 0xFFF6 0000 - 0xFFFF FFFF : PIBS Firmware (640KiB) */ -#define ARCTIC_FFS_SIZE 0x01a00000 /* 26 M */ -#define ARCTIC_FIRMWARE_SIZE 0x000a0000 /* 640K */ +#define FFS1_SIZE 0x01000000 /* 16MiB */ +#define KERNEL_SIZE 0x00500000 /* 5.12MiB */ +#define FFS2_SIZE 0x00a60000 /* 10.624MiB */ +#define FIRMWARE_SIZE 0x000a0000 /* 640KiB */ -#define NAME "Arctic Linux Flash" -#define PADDR SUBZERO_BOOTFLASH_PADDR -#define SIZE SUBZERO_BOOTFLASH_SIZE -#define BUSWIDTH 2 + +#define NAME "Arctic Linux Flash" +#define PADDR SUBZERO_BOOTFLASH_PADDR +#define BUSWIDTH 2 +#define SIZE SUBZERO_BOOTFLASH_SIZE +#define PARTITIONS 4 /* Flash memories on these boards are memory resources, accessed big-endian. */ @@ -73,17 +78,19 @@ static struct map_info arctic_mtd_map = { static struct mtd_info *arctic_mtd; -static struct mtd_partition arctic_partitions[3] = { - { .name = "Arctic FFS", - .size = ARCTIC_FFS_SIZE, +static struct mtd_partition arctic_partitions[PARTITIONS] = { + { .name = "Filesystem", + .size = FFS1_SIZE, .offset = 0,}, - { .name = "Kernel", - .size = SUBZERO_BOOTFLASH_SIZE - ARCTIC_FFS_SIZE - - ARCTIC_FIRMWARE_SIZE, - .offset = ARCTIC_FFS_SIZE,}, + { .name = "Kernel", + .size = KERNEL_SIZE, + .offset = FFS1_SIZE,}, + { .name = "Filesystem", + .size = FFS2_SIZE, + .offset = FFS1_SIZE + KERNEL_SIZE,}, { .name = "Firmware", - .size = ARCTIC_FIRMWARE_SIZE, - .offset = SUBZERO_BOOTFLASH_SIZE - ARCTIC_FIRMWARE_SIZE,}, + .size = FIRMWARE_SIZE, + .offset = SUBZERO_BOOTFLASH_SIZE - FIRMWARE_SIZE,}, }; static int __init @@ -107,7 +114,7 @@ init_arctic_mtd(void) arctic_mtd->owner = THIS_MODULE; - return add_mtd_partitions(arctic_mtd, arctic_partitions, 3); + return add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS); } static void __exit diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c index cb28518159b0..00e87e21138a 100644 --- a/drivers/mtd/maps/ebony.c +++ b/drivers/mtd/maps/ebony.c @@ -1,5 +1,5 @@ /* - * $Id: ebony.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $ + * $Id: ebony.c,v 1.8 2003/06/23 11:48:18 dwmw2 Exp $ * * Mapping for Ebony user flash * @@ -60,8 +60,6 @@ static struct mtd_partition ebony_large_partitions[] = { } }; -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - int __init init_ebony(void) { u8 fpga0_reg; @@ -109,7 +107,7 @@ int __init init_ebony(void) if (flash) { flash->owner = THIS_MODULE; add_mtd_partitions(flash, ebony_small_partitions, - NB_OF(ebony_small_partitions)); + ARRAY_SIZE(ebony_small_partitions)); } else { printk("map probe failed for flash\n"); return -ENXIO; @@ -131,7 +129,7 @@ int __init init_ebony(void) if (flash) { flash->owner = THIS_MODULE; add_mtd_partitions(flash, ebony_large_partitions, - NB_OF(ebony_large_partitions)); + ARRAY_SIZE(ebony_large_partitions)); } else { printk("map probe failed for flash\n"); return -ENXIO; diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index 346ae2e4dd95..0ecac2071062 100644 --- a/drivers/mtd/maps/edb7312.c +++ b/drivers/mtd/maps/edb7312.c @@ -1,5 +1,5 @@ /* - * $Id: edb7312.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $ + * $Id: edb7312.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $ * * Handle mapping of the NOR flash on Cogent EDB7312 boards * @@ -67,7 +67,6 @@ static struct mtd_partition static_partitions[3] = }, }; -#define NB_OF(x) (sizeof (x) / sizeof (x[0])) static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; #endif @@ -109,7 +108,7 @@ int __init init_edb7312nor(void) if (mtd_parts_nb == 0) { mtd_parts = static_partitions; - mtd_parts_nb = NB_OF(static_partitions); + mtd_parts_nb = ARRAY_SIZE(static_partitions); part_type = "static"; } #endif diff --git a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c index 6caf4f8f877a..fe0bfe0f18bc 100644 --- a/drivers/mtd/maps/elan-104nc.c +++ b/drivers/mtd/maps/elan-104nc.c @@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: elan-104nc.c,v 1.17 2003/05/21 15:15:07 dwmw2 Exp $ + $Id: elan-104nc.c,v 1.18 2003/06/23 07:37:02 dwmw2 Exp $ The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16 mode. This drivers uses the CFI probe and Intel Extended Command Set drivers. @@ -223,20 +223,13 @@ static void cleanup_elan_104nc(void) } iounmap((void *)iomapadr); - release_region(PAGE_IO,PAGE_IO_SIZE); } int __init init_elan_104nc(void) { - /* Urg! We use I/O port 0x22 without request_region()ing it */ - /* - if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) { - printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", - elan_104nc_map.name, - PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 ); - return -EAGAIN; - } - */ + /* Urg! We use I/O port 0x22 without request_region()ing it, + because it's already allocated to the PIC. */ + iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH); if (!iomapadr) { printk( KERN_ERR"%s: failed to ioremap memory region\n", @@ -244,10 +237,6 @@ int __init init_elan_104nc(void) return -EIO; } - /* - request_region( PAGE_IO, PAGE_IO_SIZE, "ELAN-104NC flash" ); - */ - printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", elan_104nc_map.name, PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 9c3785aa67c1..fdf0dca3fd16 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -1,5 +1,5 @@ /* - * $Id: impa7.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $ + * $Id: impa7.c,v 1.9 2003/06/23 11:47:43 dwmw2 Exp $ * * Handle mapping of the NOR flash on implementa A7 boards * @@ -66,12 +66,11 @@ static struct mtd_partition static_partitions[] = }, }; -#define NB_OF(x) (sizeof (x) / sizeof (x[0])) +static int mtd_parts_nb[NUM_FLASHBANKS]; +static struct mtd_partition *mtd_parts[NUM_FLASHBANKS]; #endif -static int mtd_parts_nb = 0; -static struct mtd_partition *mtd_parts = 0; static const char *probes[] = { "cmdlinepart", NULL }; int __init init_impa7(void) @@ -84,7 +83,6 @@ int __init init_impa7(void) { WINDOW_ADDR0, WINDOW_SIZE0 }, { WINDOW_ADDR1, WINDOW_SIZE1 }, }; - char mtdid[10]; int devicesfound = 0; for(i=0; iowner = THIS_MODULE; - add_mtd_device(impa7_mtd[i]); devicesfound++; #ifdef CONFIG_MTD_PARTITIONS - mtd_parts_nb = parse_mtd_partitions(impa7_mtd[i], - probes, - &mtd_parts, - 0); - if (mtd_parts_nb > 0) - part_type = "command line"; -#endif - if (mtd_parts_nb <= 0) - { - mtd_parts = static_partitions; - mtd_parts_nb = NB_OF(static_partitions); + mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], + probes, + &mtd_parts[i], + 0); + if (mtd_parts_nb[i] > 0) { + part_type = "command line"; + } else { + mtd_parts[i] = static_partitions; + mtd_parts_nb[i] = ARRAY_SIZE(static_partitions); part_type = "static"; } - if (mtd_parts_nb <= 0) - { - printk(KERN_NOTICE MSG_PREFIX - "no partition info available\n"); - } - else - { - printk(KERN_NOTICE MSG_PREFIX - "using %s partition definition\n", - part_type); - add_mtd_partitions(impa7_mtd[i], - mtd_parts, mtd_parts_nb); - } + + printk(KERN_NOTICE MSG_PREFIX + "using %s partition definition\n", + part_type); + add_mtd_partitions(impa7_mtd[i], + mtd_parts[i], mtd_parts_nb[i]); +#else + add_mtd_device(impa7_mtd[i]); + #endif } else - iounmap((void *)impa7_map[i].virt); + iounmap((void *)impa7_map[i].virt); } return devicesfound == 0 ? -ENXIO : 0; } @@ -150,15 +140,14 @@ int __init init_impa7(void) static void __exit cleanup_impa7(void) { int i; - for (i=0; i * - * $Id: pb1xxx-flash.c,v 1.8 2003/05/21 12:45:19 dwmw2 Exp $ + * $Id: pb1xxx-flash.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $ */ #include @@ -131,9 +131,6 @@ static struct mtd_partition pb1xxx_partitions[] = { #error Unsupported board #endif - -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - static struct mtd_partition *parsed_parts; static struct mtd_info *mymtd; @@ -151,7 +148,7 @@ int __init pb1xxx_mtd_init(void) */ part_type = "static"; parts = pb1xxx_partitions; - nb_parts = NB_OF(pb1xxx_partitions); + nb_parts = ARRAY_SIZE(pb1xxx_partitions); pb1xxx_map.size = flash_size; /* diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 1112440fc992..5607a29543cc 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c @@ -2,7 +2,7 @@ * Handle mapping of the flash memory access routines * on TQM8xxL based devices. * - * $Id: tqm8xxl.c,v 1.8 2003/05/21 12:45:20 dwmw2 Exp $ + * $Id: tqm8xxl.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $ * * based on rpxlite.c * @@ -110,8 +110,6 @@ static struct mtd_partition tqm8xxl_fs_partitions[] = { }; #endif -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - int __init init_tqm_mtd(void) { int idx = 0, ret = 0; @@ -198,11 +196,11 @@ int __init init_tqm_mtd(void) */ part_banks[0].mtd_part = tqm8xxl_partitions; part_banks[0].type = "Static image"; - part_banks[0].nums = NB_OF(tqm8xxl_partitions); + part_banks[0].nums = ARRAY_SIZE(tqm8xxl_partitions); part_banks[1].mtd_part = tqm8xxl_fs_partitions; part_banks[1].type = "Static file system"; - part_banks[1].nums = NB_OF(tqm8xxl_fs_partitions); + part_banks[1].nums = ARRAY_SIZE(tqm8xxl_fs_partitions); for(idx = 0; idx < num_banks ; idx++) { if (part_banks[idx].nums == 0) { diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index c0095f99d679..460d56f70bec 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $ + * $Id: mtdpart.c,v 1.41 2003/06/18 14:53:02 dwmw2 Exp $ * * 02-21-2002 Thomas Gleixner * added support for read_oob, write_oob @@ -120,7 +120,7 @@ static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t le size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->read_user_prot_reg (part->master, from, + return part->master->read_fact_prot_reg (part->master, from, len, retlen, buf); } diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index 5d928bfee613..2c149e94852c 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -6,7 +6,7 @@ * Derived from drivers/mtd/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: autcpu12.c,v 1.10 2003/04/20 07:24:40 gleixner Exp $ + * $Id: autcpu12.c,v 1.11 2003/06/04 17:04:09 gleixner Exp $ * * 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 @@ -28,6 +28,7 @@ */ #include +#include #include #include #include diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c index dc11ca9a6f8a..85cee7b17c8c 100644 --- a/drivers/mtd/nand/nand.c +++ b/drivers/mtd/nand/nand.c @@ -124,9 +124,15 @@ + a structure, which will be supplied by a filesystem driver * If NULL is given, then the defaults (none or defaults * supplied by ioctl (MEMSETOOBSEL) are used. - * For partitions the partition defaults are used (mtdpart.c) + * For partitions the partition defaults are used (mtdpart.c) + * + * 06-04-2003 tglx: fix compile errors and fix write verify problem for + * some chips, which need either a delay between the readback + * and the next write command or have the CE removed. The + * CE disable/enable is much faster than a 20us delay and + * it should work on all available chips. * - * $Id: nand.c,v 1.45 2003/05/20 21:01:30 dwmw2 Exp $ + * $Id: nand.c,v 1.46 2003/06/04 17:10:36 gleixner Exp $ * * 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 @@ -141,6 +147,7 @@ #include #include #include +#include #include #include @@ -510,6 +517,13 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa } } } + /* + * Terminate the read command. This is faster than sending a reset command or + * applying a 20us delay before issuing the next programm sequence. + * This is not a problem for all chips, but I have found a bunch of them. + */ + nand_deselect(); + nand_select(); #endif return 0; } diff --git a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h index c224985990b9..64465a963442 100644 --- a/include/linux/mtd/doc2000.h +++ b/include/linux/mtd/doc2000.h @@ -2,7 +2,7 @@ /* Linux driver for Disk-On-Chip 2000 */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse */ -/* $Id: doc2000.h,v 1.16 2003/05/23 11:29:33 dwmw2 Exp $ */ +/* $Id: doc2000.h,v 1.17 2003/06/12 01:20:46 gerg Exp $ */ #ifndef __MTD_DOC2000_H__ #define __MTD_DOC2000_H__ @@ -44,7 +44,7 @@ #define DoC_Mplus_AccessStatus 0x1008 #define DoC_Mplus_DeviceSelect 0x1008 #define DoC_Mplus_Configuration 0x100a -#define DoC_Mplus_OutputControl 0x1002 +#define DoC_Mplus_OutputControl 0x100c #define DoC_Mplus_FlashControl 0x1020 #define DoC_Mplus_FlashSelect 0x1022 #define DoC_Mplus_FlashCmd 0x1024 -- cgit v1.2.3 From 2588333601e4e50fe8bf29aadbc882d4c7ce25b7 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 23 Jun 2003 15:40:56 +0100 Subject: Replace mtd_blktrans ->ioctl() method with ->getgeo() and ->flush() ... and also fix the embarrassing bug where NFTL and INFTL will barf and exit if the add_mtd_blktrans_dev() function _exists_, rather than actually calling it and barfing if it returns non-zero :) --- drivers/mtd/ftl.c | 41 +++++++++---------------------- drivers/mtd/inftlcore.c | 31 +++++++---------------- drivers/mtd/mtd_blkdevs.c | 50 +++++++++++++++++++++++++------------- drivers/mtd/mtdblock.c | 58 ++++++++++++++++++-------------------------- drivers/mtd/mtdblock_ro.c | 3 ++- drivers/mtd/nftlcore.c | 30 +++++++---------------- include/linux/mtd/blktrans.h | 17 ++++++------- 7 files changed, 96 insertions(+), 134 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index a2ef3efb88f6..67649391125c 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1,5 +1,5 @@ /* This version ported to the Linux-MTD system by dwmw2@infradead.org - * $Id: ftl.c,v 1.50 2003/05/21 10:49:47 dwmw2 Exp $ + * $Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $ * * Fixes: Arnaldo Carvalho de Melo * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups @@ -984,37 +984,20 @@ static int ftl_write(partition_t *part, caddr_t buffer, return 0; } /* ftl_write */ -/*====================================================================== - - IOCTL calls for getting device parameters. - -======================================================================*/ - -static int ftl_ioctl(struct mtd_blktrans_dev *dev, struct inode *inode, - struct file *file, u_int cmd, u_long arg) +static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) { - struct hd_geometry *geo = (struct hd_geometry *)arg; - partition_t *part = (void *)dev; - u_long sect; + partition_t *part = (void *)dev; + u_long sect; - switch (cmd) { - case HDIO_GETGEO: - /* Sort of arbitrary: round size down to 4K boundary */ + /* Sort of arbitrary: round size down to 4KiB boundary */ sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE; - if (put_user(1, (char *)&geo->heads) || - put_user(8, (char *)&geo->sectors) || - put_user((sect>>3), (short *)&geo->cylinders) || - put_user(0, (u_long *)&geo->start)) - return -EFAULT; - - case BLKFLSBUF: - return 0; - } - return -ENOTTY; -} /* ftl_ioctl */ + geo->heads = 1; + geo->sectors = 8; + geo->cylinders = sect >> 3; -/*======================================================================*/ + return 0; +} static int ftl_readsect(struct mtd_blktrans_dev *dev, unsigned long block, char *buf) @@ -1102,7 +1085,7 @@ struct mtd_blktrans_ops ftl_tr = { .part_bits = PART_BITS, .readsect = ftl_readsect, .writesect = ftl_writesect, - .ioctl = ftl_ioctl, + .getgeo = ftl_getgeo, .add_mtd = ftl_add_mtd, .remove_dev = ftl_remove_dev, .owner = THIS_MODULE, @@ -1110,7 +1093,7 @@ struct mtd_blktrans_ops ftl_tr = { int init_ftl(void) { - DEBUG(0, "$Id: ftl.c,v 1.50 2003/05/21 10:49:47 dwmw2 Exp $\n"); + DEBUG(0, "$Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $\n"); return register_mtd_blktrans(&ftl_tr); } diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index f9e4eca258d8..f12d676f67e1 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -7,7 +7,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * Author: David Woodhouse * - * $Id: inftlcore.c,v 1.9 2003/05/23 11:41:47 dwmw2 Exp $ + * $Id: inftlcore.c,v 1.11 2003/06/23 12:00:08 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -113,7 +113,7 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) (long)inftl->sectors ); } - if (add_mtd_blktrans_dev) { + if (add_mtd_blktrans_dev(&inftl->mbd)) { if (inftl->PUtable) kfree(inftl->PUtable); if (inftl->VUtable) @@ -835,35 +835,22 @@ foundit: return 0; } - -static int inftl_ioctl(struct mtd_blktrans_dev *dev, - struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int inftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) { struct NFTLrecord *nftl = (void *)dev; - switch (cmd) { - case HDIO_GETGEO: { - struct hd_geometry g; - - g.heads = nftl->heads; - g.sectors = nftl->sectors; - g.cylinders = nftl->cylinders; - g.start = 0; - return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; - } + geo->heads = nftl->heads; + geo->sectors = nftl->sectors; + geo->cylinders = nftl->cylinders; - default: - return -ENOTTY; - } + return 0; } - struct mtd_blktrans_ops inftl_tr = { .name = "inftl", .major = INFTL_MAJOR, .part_bits = INFTL_PARTN_BITS, - .ioctl = inftl_ioctl, + .getgeo = inftl_getgeo, .readsect = inftl_readblock, .writesect = inftl_writeblock, .add_mtd = inftl_add_mtd, @@ -875,7 +862,7 @@ extern char inftlmountrev[]; int __init init_inftl(void) { - printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.9 $, " + printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.11 $, " "inftlmount.c %s\n", inftlmountrev); return register_mtd_blktrans(&inftl_tr); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 0cc4998ba441..1a32b8e96b75 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -1,5 +1,5 @@ /* - * $Id: mtd_blkdevs.c,v 1.12 2003/05/21 01:00:59 dwmw2 Exp $ + * $Id: mtd_blkdevs.c,v 1.15 2003/06/23 12:00:08 dwmw2 Exp $ * * (C) 2003 David Woodhouse * @@ -18,8 +18,10 @@ #include #include #include +#include #include #include +#include #include static LIST_HEAD(blktrans_majors); @@ -46,7 +48,7 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, nsect = req->current_nr_sectors; buf = req->buffer; - if (!req->flags & REQ_CMD) + if (!(req->flags & REQ_CMD)) return 0; if (block + nsect > get_capacity(req->rq_disk)) @@ -93,14 +95,14 @@ static int mtd_blktrans_thread(void *arg) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + spin_lock_irq(rq->queue_lock); + while (!tr->blkcore_priv->exiting) { struct request *req; struct mtd_blktrans_dev *dev; int res = 0; DECLARE_WAITQUEUE(wait, current); - spin_lock_irq(rq->queue_lock); - req = elv_next_request(rq); if (!req) { @@ -112,6 +114,8 @@ static int mtd_blktrans_thread(void *arg) schedule(); remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait); + spin_lock_irq(rq->queue_lock); + continue; } @@ -159,7 +163,7 @@ int blktrans_open(struct inode *i, struct file *f) dev->mtd->usecount++; ret = 0; - if (tr->open && (ret = tr->open(dev, i, f))) { + if (tr->open && (ret = tr->open(dev))) { dev->mtd->usecount--; module_put(dev->mtd->owner); out_tr: @@ -179,7 +183,7 @@ int blktrans_release(struct inode *i, struct file *f) tr = dev->tr; if (tr->release) - ret = tr->release(dev, i, f); + ret = tr->release(dev); if (!ret) { dev->mtd->usecount--; @@ -194,21 +198,33 @@ int blktrans_release(struct inode *i, struct file *f) static int blktrans_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct mtd_blktrans_dev *dev; - struct mtd_blktrans_ops *tr; - int ret = -ENOTTY; + struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; + struct mtd_blktrans_ops *tr = dev->tr; - dev = inode->i_bdev->bd_disk->private_data; - tr = dev->tr; + switch (cmd) { + case BLKFLSBUF: + if (tr->flush) + return tr->flush(dev); + /* The core code did the work, we had nothing to do. */ + return 0; - if (tr->ioctl) - ret = tr->ioctl(dev, inode, file, cmd, arg); + case HDIO_GETGEO: + if (tr->getgeo) { + struct hd_geometry g; - if (ret == -ENOTTY && (cmd == BLKROSET || cmd == BLKFLSBUF)) { - /* The core code did the work, we had nothing to do. */ - ret = 0; + memset(&g, 0, sizeof(g)); + int ret = tr->getgeo(dev, &g); + if (ret) + return ret; + + g.start = get_start_sect(inode->i_bdev); + if (copy_to_user((void *)arg, &g, sizeof(g))) + return -EFAULT; + return 0; + } /* else */ + default: + return -ENOTTY; } - return ret; } struct block_device_operations mtd_blktrans_ops = { diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index d4dc3b67807a..965c5954d728 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -1,7 +1,7 @@ /* * Direct MTD block device access * - * $Id: mtdblock.c,v 1.61 2003/05/21 10:49:38 dwmw2 Exp $ + * $Id: mtdblock.c,v 1.63 2003/06/23 12:00:08 dwmw2 Exp $ * * (C) 2000-2003 Nicolas Pitre * (C) 1999-2003 David Woodhouse @@ -248,11 +248,19 @@ static int mtdblock_writesect(struct mtd_blktrans_dev *dev, unsigned long block, char *buf) { struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; + if (unlikely(!mtdblk->cache_data)) { + mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize); + if (!mtdblk->cache_data) + return -EINTR; + /* -EINTR is not really correct, but it is the best match + * documented in man 2 write for all cases. We could also + * return -EAGAIN sometimes, but why bother? + */ + } return do_cached_write(mtdblk, block<<9, 512, buf); } -static int mtdblock_open(struct mtd_blktrans_dev *mbd, - struct inode *inode, struct file *file) +static int mtdblock_open(struct mtd_blktrans_dev *mbd) { struct mtdblk_dev *mtdblk; struct mtd_info *mtd = mbd->mtd; @@ -279,11 +287,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd, if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM && mtdblk->mtd->erasesize) { mtdblk->cache_size = mtdblk->mtd->erasesize; - mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize); - if (!mtdblk->cache_data) { - kfree(mtdblk); - return -ENOMEM; - } + mtdblk->cache_data = NULL; } mtdblks[dev] = mtdblk; @@ -293,17 +297,13 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd, return 0; } -static int mtdblock_release(struct mtd_blktrans_dev *mbd, - struct inode *inode, struct file *file) +static int mtdblock_release(struct mtd_blktrans_dev *mbd) { - int dev; - struct mtdblk_dev *mtdblk; + int dev = mbd->devnum; + struct mtdblk_dev *mtdblk = mtdblks[dev]; DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); - dev = minor(inode->i_rdev); - mtdblk = mtdblks[dev]; - down(&mtdblk->cache_sem); write_cached_data(mtdblk); up(&mtdblk->cache_sem); @@ -321,27 +321,17 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd, return 0; } - -static int mtdblock_ioctl(struct mtd_blktrans_dev *dev, - struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static int mtdblock_flush(struct mtd_blktrans_dev *dev) { - struct mtdblk_dev *mtdblk; - - mtdblk = mtdblks[minor(inode->i_rdev)]; + struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; - switch (cmd) { - case BLKFLSBUF: - down(&mtdblk->cache_sem); - write_cached_data(mtdblk); - up(&mtdblk->cache_sem); - if (mtdblk->mtd->sync) - mtdblk->mtd->sync(mtdblk->mtd); - return 0; + down(&mtdblk->cache_sem); + write_cached_data(mtdblk); + up(&mtdblk->cache_sem); - default: - return -ENOTTY; - } + if (mtdblk->mtd->sync) + mtdblk->mtd->sync(mtdblk->mtd); + return 0; } static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) @@ -376,7 +366,7 @@ struct mtd_blktrans_ops mtdblock_tr = { .major = 31, .part_bits = 0, .open = mtdblock_open, - .ioctl = mtdblock_ioctl, + .flush = mtdblock_flush, .release = mtdblock_release, .readsect = mtdblock_readsect, .writesect = mtdblock_writesect, diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index e9133d25f6f2..cdd4ce1df205 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -1,11 +1,12 @@ /* - * $Id: mtdblock_ro.c,v 1.17 2003/05/18 19:27:27 dwmw2 Exp $ + * $Id: mtdblock_ro.c,v 1.18 2003/06/23 12:00:08 dwmw2 Exp $ * * (C) 2003 David Woodhouse * * Simple read-only (writable only for RAM) mtdblock driver */ +#include #include #include #include diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 13cd52025caf..ea709d7cf463 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -1,7 +1,7 @@ /* Linux driver for NAND Flash Translation Layer */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse */ -/* $Id: nftlcore.c,v 1.92 2003/05/23 11:41:47 dwmw2 Exp $ */ +/* $Id: nftlcore.c,v 1.94 2003/06/23 12:00:08 dwmw2 Exp $ */ /* The contents of this file are distributed under the GNU General @@ -101,7 +101,7 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) (long)nftl->sectors ); } - if (add_mtd_blktrans_dev) { + if (add_mtd_blktrans_dev(&nftl->mbd)) { if (nftl->ReplUnitTable) kfree(nftl->ReplUnitTable); if (nftl->EUNtable) @@ -699,29 +699,17 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, return 0; } -static int nftl_ioctl(struct mtd_blktrans_dev *dev, - struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static int nftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) { struct NFTLrecord *nftl = (void *)dev; - switch (cmd) { - case HDIO_GETGEO: { - struct hd_geometry g; + geo->heads = nftl->heads; + geo->sectors = nftl->sectors; + geo->cylinders = nftl->cylinders; - g.heads = nftl->heads; - g.sectors = nftl->sectors; - g.cylinders = nftl->cylinders; - g.start = 0; - return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; - } - - default: - return -ENOTTY; - } + return 0; } - /**************************************************************************** * * Module stuff @@ -733,7 +721,7 @@ struct mtd_blktrans_ops nftl_tr = { .name = "nftl", .major = NFTL_MAJOR, .part_bits = NFTL_PARTN_BITS, - .ioctl = nftl_ioctl, + .getgeo = nftl_getgeo, .readsect = nftl_readblock, #ifdef CONFIG_NFTL_RW .writesect = nftl_writeblock, @@ -747,7 +735,7 @@ extern char nftlmountrev[]; int __init init_nftl(void) { - printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.92 $, nftlmount.c %s\n", nftlmountrev); + printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.94 $, nftlmount.c %s\n", nftlmountrev); return register_mtd_blktrans(&nftl_tr); } diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h index ab9639b36e25..4ebc2e5a16e2 100644 --- a/include/linux/mtd/blktrans.h +++ b/include/linux/mtd/blktrans.h @@ -1,5 +1,5 @@ /* - * $Id: blktrans.h,v 1.4 2003/05/21 01:01:32 dwmw2 Exp $ + * $Id: blktrans.h,v 1.5 2003/06/23 12:00:08 dwmw2 Exp $ * * (C) 2003 David Woodhouse * @@ -12,6 +12,7 @@ #include +struct hd_geometry; struct mtd_info; struct mtd_blktrans_ops; struct file; @@ -42,17 +43,13 @@ struct mtd_blktrans_ops { int (*writesect)(struct mtd_blktrans_dev *dev, unsigned long block, char *buffer); - /* HDIO_GETGEO and HDIO_GETGEO_BIG are the only non-private - ioctls which are expected to be passed through */ - int (*ioctl)(struct mtd_blktrans_dev *dev, - struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg); + /* Block layer ioctls */ + int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo); + int (*flush)(struct mtd_blktrans_dev *dev); /* Called with mtd_table_mutex held; no race with add/remove */ - int (*open)(struct mtd_blktrans_dev *dev, - struct inode *i, struct file *f); - int (*release)(struct mtd_blktrans_dev *dev, - struct inode *i, struct file *f); + int (*open)(struct mtd_blktrans_dev *dev); + int (*release)(struct mtd_blktrans_dev *dev); /* Called on {de,}registration and on subsequent addition/removal of devices, with mtd_table_mutex held. */ -- cgit v1.2.3