diff -Nru a/Documentation/driver-model/binding.txt b/Documentation/driver-model/binding.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/driver-model/binding.txt Fri Sep 20 08:20:49 2002 @@ -0,0 +1,102 @@ + +Driver Binding + +Driver binding is the process of associating a device with a device +driver that can control it. Bus drivers have typically handled this +because there have been bus-specific structures to represent the +devices and the drivers. With generic device and device driver +structures, most of the binding can take place using common code. + + +Bus +~~~ + +The bus type structure contains a list of all devices that on that bus +type in the system. When device_register is called for a device, it is +inserted into the end of this list. The bus object also contains a +list of all drivers of that bus type. When driver_register is called +for a driver, it is inserted into the end of this list. These are the +two events which trigger driver binding. + + +device_register +~~~~~~~~~~~~~~~ + +When a new device is added, the bus's list of drivers is iterated over +to find one that supports it. In order to determine that, the device +ID of the device must match one of the device IDs that the driver +supports. The format and semantics for comparing IDs is bus-specific. +Instead of trying to derive a complex state machine and matching +algorithm, it is up to the bus driver to provide a callback to compare +a device against the IDs of a driver. The bus returns 1 if a match was +found; 0 otherwise. + +int match(struct device * dev, struct device_driver * drv); + +If a match is found, the device's driver field is set to the driver +and the driver's probe callback is called. This gives the driver a +chance to verify that it really does support the hardware, and that +it's in a working state. + +Device Class +~~~~~~~~~~~~ + +Upon the successful completion of probe, the device is registered with +the class to which it belongs. Device drivers belong to one and only +class, and that is set in the driver's devclass field. +devclass_add_device is called to enumerate the device within the class +and actually register it with the class, which happens with the +class's register_dev callback. + +NOTE: The device class structures and core routines to manipulate them +are not in the mainline kernel, so the discussion is still a bit +speculative. + + +Driver +~~~~~~ + +When a driver is attached to a device, the device is inserted into the +driver's list of devices. + + +driverfs +~~~~~~~~ + +A symlink is created in the bus's 'devices' directory that points to +the device's directory in the physical hierarchy. + +A symlink is created in the driver's 'devices' directory that points +to the device's directory in the physical hierarchy. + +A directory for the device is created in the class's directory. A +symlink is created in that directory that points to the device's +physical location in the driverfs tree. + +A symlink can be created (though this isn't done yet) in the device's +physical directory to either its class directory, or the class's +top-level directory. One can also be created to point to its driver's +directory also. + + +driver_register +~~~~~~~~~~~~~~~ + +The process is almost identical for when a new driver is added. +The bus's list of devices is iterated over to find a match. Devices +that already have a driver are skipped. All the devices are iterated +over, to bind as many devices as possible to the driver. + + +Removal +~~~~~~~ + +When a device is removed, the reference count for it will eventually +go to 0. When it does, the remove callback of the driver is called. It +is removed from the driver's list of devices and the reference count +of the driver is decremented. All symlinks between the two are removed. + +When a driver is removed, the list of devices that it supports is +iterated over, and the driver's remove callback is called for each +one. The device is removed from that list and the symlinks removed. + diff -Nru a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/driver-model/bus.txt Fri Sep 20 08:20:49 2002 @@ -0,0 +1,192 @@ + +Bus Types + +Definition +~~~~~~~~~~ + +struct bus_type { + char * name; + rwlock_t lock; + atomic_t refcount; + + struct list_head node; + struct list_head devices; + struct list_head drivers; + + struct driver_dir_entry dir; + struct driver_dir_entry device_dir; + struct driver_dir_entry driver_dir; + + int (*match) (struct device * dev, struct device_driver * drv); + struct device (*add) (struct device * parent, char * bus_id); +}; + +int bus_register(struct bus_type * bus); + + +Declaration +~~~~~~~~~~~ + +Each bus type in the kernel (PCI, USB, etc) should declare one static +object of this type. They must initialize the name field, and may +optionally initialize the match callback. + +struct bus_type pci_bus_type = { + name: "pci", + match: pci_bus_match, +}; + +The structure should be exported to drivers in a header file: + +extern struct bus_type pci_bus_type; + + +Registration +~~~~~~~~~~~~ + +When a bus driver is initialized, it calls bus_register. This +initializes the rest of the fields in the bus object and inserts it +into a global list of bus types. Once the bus object is registered, +the fields in it (e.g. the rwlock_t) are usable by the bus driver. + + +Callbacks +~~~~~~~~~ + +match(): Attaching Drivers to Devices +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The format of device ID structures and the semantics for comparing +them are inherently bus-specific. Drivers typically declare an array +of device IDs of device they support that reside in a bus-specific +driver structure. + +The purpose of the match callback is provide the bus an opportunity to +determine if a particular driver supports a particular device by +comparing the device IDs the driver supports with the device ID of a +particular device, without sacrificing bus-specific functionality or +type-safety. + +When a driver is registered with the bus, the bus's list of devices is +iterated over, and the match callback is called for each device that +does not have a driver associated with it. + +add(): Adding a child device +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The add callback is available to notify the bus about a child device +at a particular location. + +The parent parameter is the parent device of the child to be added. If +parent == NULL, the bus should add the device as a child of a default +parent device or as a child of the root. This policy decision is up to +the bus driver. + +The format of the bus_id field should be consistent with the format of +the bus_id field of the rest of the devices on the bus. This requires +the caller to know the format. + +On return, the bus driver should return a pointer to the device that +was created. If the device was not created, the bus driver should +return an appropriate error code. Refer to include/linux/err.h for +helper functions to encode errors. Some sample code: + +struct device * pci_bus_add(struct device * parent, char * bus_id) +{ + ... + /* the device already exists */ + return ERR_PTR(-EEXIST); + ... +} + +The caller can check the return value using IS_ERR(): + + struct device * newdev = pci_bus_type.add(parent,bus_id); + if (IS_ERR(newdev)) { + ... + } + + +Device and Driver Lists +~~~~~~~~~~~~~~~~~~~~~~~ + +The lists of devices and drivers are intended to replace the local +lists that many buses keep. They are lists of struct devices and +struct device_drivers, respectively. Bus drivers are free to use the +lists as they please, but conversion to the bus-specific type may be +necessary. + +The LDM core provides helper functions for iterating over each list. + +int bus_for_each_dev(struct bus_type * bus, void * data, + int (*callback)(struct device * dev, void * data)); +int bus_for_each_drv(struct bus_type * bus, void * data, + int (*callback)(struct device_driver * drv, void * data)); + +These helpers iterate over the respective list, and call the callback +for each device or driver in the list. All list accesses are +synchronized by taking the bus's lock (read currently). The reference +count on each object in the list is incremented before the callback is +called; it is decremented after the next object has been obtained. The +lock is not held when calling the callback. + + +driverfs +~~~~~~~~ +There is a top-level directory named 'bus'. + +Each bus gets a directory in the bus directory, along with two default +directories: + + /sys/bus/pci/ + |-- devices + `-- drivers + +Drivers registered with the bus get a directory in the bus's drivers +directory: + + /sys/bus/pci/ + |-- devices + `-- drivers + |-- Intel ICH + |-- Intel ICH Joystick + |-- agpgart + `-- e100 + +Each device that is discovered a bus of that type gets a symlink in +the bus's devices directory to the device's directory in the physical +hierarchy: + + /sys/bus/pci/ + |-- devices + | |-- 00:00.0 -> ../../../root/pci0/00:00.0 + | |-- 00:01.0 -> ../../../root/pci0/00:01.0 + | `-- 00:02.0 -> ../../../root/pci0/00:02.0 + `-- drivers + + +Exporting Attributes +~~~~~~~~~~~~~~~~~~~~ +struct bus_attribute { + struct attribute attr; + ssize_t (*show)(struct bus_type *, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off); +}; + +Bus drivers can export attributes using the BUS_ATTR macro that works +similarly to the DEVICE_ATTR macro for devices. For example, a definition +like this: + +static BUS_ATTR(debug,0644,show_debug,store_debug); + +is equivalent to declaring: + +static bus_attribute bus_attr_debug; + +This can then be used to add and remove the attribute from the bus's +driverfs directory using: + +int bus_create_file(struct bus_type *, struct bus_attribute *); +void bus_remove_file(struct bus_type *, struct bus_attribute *); + + diff -Nru a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/driver-model/class.txt Fri Sep 20 08:20:49 2002 @@ -0,0 +1,162 @@ + +Device Classes + + +Introduction +~~~~~~~~~~~~ +A device class describes a type of device, like an audio or network +device. The following device classes have been identified: + + + + +Each device class defines a set of semantics and a programming interface +that devices of that class adhere to. Device drivers are the +implemention of that programming interface for a particular device on +a particular bus. + +Device classes are agnostic with respect to what bus a device resides +on. + + +Programming Interface +~~~~~~~~~~~~~~~~~~~~~ +The device class structure looks like: + + +typedef int (*devclass_add)(struct device *); +typedef void (*devclass_remove)(struct device *); + +struct device_class { + char * name; + rwlock_t lock; + u32 devnum; + struct list_head node; + + struct list_head drivers; + struct list_head intf_list; + + struct driver_dir_entry dir; + struct driver_dir_entry device_dir; + struct driver_dir_entry driver_dir; + + devclass_add add_device; + devclass_remove remove_device; +}; + +A typical device class definition would look like: + +struct device_class input_devclass = { + .name = "input", + .add_device = input_add_device, + .remove_device = input_remove_device, +}; + +Each device class structure should be exported in a header file so it +can be used by drivers, extensions and interfaces. + +Device classes are registered and unregistered with the core using: + +int devclass_register(struct device_class * cls); +void devclass_unregister(struct device_class * cls); + + +Devices +~~~~~~~ +As devices are bound to drivers, they are added to the device class +that the driver belongs to. Before the driver model core, this would +typically happen during the driver's probe() callback, once the device +has been initialized. It now happens after the probe() callback +finishes from the core. + +The device is enumerated in the class. Each time a device is added to +the class, the class's devnum field is incremented and assigned to the +device. The field is never decremented, so if the device is removed +from the class and re-added, it will receive a different enumerated +value. + +The class is allowed to create a class-specific structure for the +device and store it in the device's class_data pointer. + +There is no list of devices in the device class. Each driver has a +list of devices that it supports. The device class has a list of +drivers of that particular class. To access all of the devices in the +class, iterate over the device lists of each driver in the class. + + +Device Drivers +~~~~~~~~~~~~~~ +Device drivers are added to device classes when they are registered +with the core. A driver specifies the class it belongs to by setting +the struct device_driver::devclass field. + + +driverfs directory structure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +There is a top-level driverfs directory named 'class'. + +Each class gets a directory in the class directory, along with two +default subdirectories: + + class/ + `-- input + |-- devices + `-- drivers + + +Drivers registered with the class get a symlink in the drivers/ directory +that points the driver's directory (under its bus directory): + + class/ + `-- input + |-- devices + `-- drivers + `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/ + + +Each device gets a symlink in the devices/ directory that points to the +device's directory in the physical hierarchy: + + class/ + `-- input + |-- devices + | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ + `-- drivers + + +Exporting Attributes +~~~~~~~~~~~~~~~~~~~~ +struct devclass_attribute { + struct attribute attr; + ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off); +}; + +Class drivers can export attributes using the DEVCLASS_ATTR macro that works +similarly to the DEVICE_ATTR macro for devices. For example, a definition +like this: + +static DEVCLASS_ATTR(debug,0644,show_debug,store_debug); + +is equivalent to declaring: + +static devclass_attribute devclass_attr_debug; + +The bus driver can add and remove the attribute from the class's +driverfs directory using: + +int devclass_create_file(struct device_class *, struct devclass_attribute *); +void devclass_remove_file(struct device_class *, struct devclass_attribute *); + +In the example above, the file will be named 'debug' in placed in the +class's directory in driverfs. + + +Interfaces +~~~~~~~~~~ +There may exist multiple mechanisms for accessing the same device of a +particular class type. Device interfaces describe these mechanisms. + +When a device is added to a device class, the core attempts to add it +to every interface that is registered with the device class. + diff -Nru a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/driver-model/device.txt Fri Sep 20 08:20:49 2002 @@ -0,0 +1,152 @@ + +The Basic Device Structure +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +struct device { + struct list_head g_list; + struct list_head node; + struct list_head bus_list; + struct list_head driver_list; + struct list_head intf_list; + struct list_head children; + struct device * parent; + + char name[DEVICE_NAME_SIZE]; + char bus_id[BUS_ID_SIZE]; + + spinlock_t lock; + atomic_t refcount; + + struct bus_type * bus; + struct driver_dir_entry dir; + + u32 class_num; + + struct device_driver *driver; + void *driver_data; + void *platform_data; + + u32 current_state; + unsigned char *saved_state; + + void (*release)(struct device * dev); +}; + +Fields +~~~~~~ +g_list: Node in the global device list. + +node: Node in device's parent's children list. + +bus_list: Node in device's bus's devices list. + +driver_list: Node in device's driver's devices list. + +intf_list: List of intf_data. There is one structure allocated for + each interface that the device supports. + +children: List of child devices. + +name: ASCII description of device. + Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]" + +bus_id: ASCII representation of device's bus position. This + field should a name unique across all devices on the + bus type the device belongs to. + + Example: PCI bus_ids are in the form of + :. + This name is unique across all PCI devices in the system. + +lock: Spinlock for the device. + +refcount: Reference count on the device. + +bus: Pointer to struct bus_type that device belongs to. + +dir: Device's driverfs directory. + +driver: Pointer to struct device_driver that controls the device. + +driver_data: Driver-specific data. + +class_num: Class-enumerated value of the device. + +platform_data: Platform data specific to the device. + +current_state: Current power state of the device. + +saved_state: Pointer to saved state of the device. This is usable by + the device driver controlling the device. + +release: Callback to free the device after all references have + gone away. This should be set by the allocator of the + device (i.e. the bus driver that discovered the device). + + +Programming Interface +~~~~~~~~~~~~~~~~~~~~~ +The bus driver that discovers the device uses this to register the +device with the core: + +int device_register(struct device * dev); + +The bus should initialize the following fields: + + - parent + - name + - bus_id + - bus + +A device is removed from the core when its reference count goes to +0. The reference count can be adjusted using: + +struct device * get_device(struct device * dev); +void put_device(struct device * dev); + +get_device() will return a pointer to the struct device passed to it +if the reference is not already 0 (if it's in the process of being +removed already). + +A driver can take use the lock in the device structure using: + +void lock_device(struct device * dev); +void unlock_device(struct device * dev); + + +Attributes +~~~~~~~~~~ +struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); +}; + +Attributes of devices can be exported via drivers using a simple +procfs-like interface. + +Please see Documentation/filesystems/driverfs.txt for more information +on how driverfs works. + +Attributes are declared using a macro called DEVICE_ATTR: + +#define DEVICE_ATTR(name,mode,show,store) + +Example: + +DEVICE_ATTR(power,0644,show_power,store_power); + +This declares a structure of type struct device_attribute named +'dev_attr_power'. This can then be added and removed to the device's +directory using: + +int device_create_file(struct device *device, struct device_attribute * entry); +void device_remove_file(struct device * dev, struct device_attribute * attr); + +Example: + +device_create_file(dev,&dev_attr_power); +device_remove_file(dev,&dev_attr_power); + +The file name will be 'power' with a mode of 0644 (-rw-r--r--). + diff -Nru a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/driver-model/driver.txt Fri Sep 20 08:20:49 2002 @@ -0,0 +1,287 @@ + +Device Drivers + +struct device_driver { + char * name; + struct bus_type * bus; + + rwlock_t lock; + atomic_t refcount; + + list_t bus_list; + list_t devices; + + struct driver_dir_entry dir; + + int (*probe) (struct device * dev); + int (*remove) (struct device * dev); + + int (*suspend) (struct device * dev, u32 state, u32 level); + int (*resume) (struct device * dev, u32 level); + + void (*release) (struct device_driver * drv); +}; + + + +Allocation +~~~~~~~~~~ + +Device drivers are statically allocated structures. Though there may +be multiple devices in a system that a driver supports, struct +device_driver represents the driver as a whole (not a particular +device instance). + +Initialization +~~~~~~~~~~~~~~ + +The driver must initialize at least the name and bus fields. It should +also initalize the devclass field (when it arrives), so it may obtain +the proper linkage internally. It should also initialize as many of +the callbacks as possible, though each is optional. + +Declaration +~~~~~~~~~~~ + +As stated above, struct device_driver objects are statically +allocated. Below is an example declaration of the eepro100 +driver. This declaration is hypothetical only; it relies on the driver +being converted completely to the new model. + +static struct device_driver eepro100_driver = { + name: "eepro100", + bus: &pci_bus_type, + devclass: ðernet_devclass, /* when it's implemented */ + + probe: eepro100_probe, + remove: eepro100_remove, + suspend: eepro100_suspend, + resume: eepro100_resume, +}; + +Most drivers will not be able to be converted completely to the new +model because the bus they belong to has a bus-specific structure with +bus-specific fields that cannot be generalized. + +The most common example this are device ID structures. A driver +typically defines an array of device IDs that it supports. The format +of this structure and the semantics for comparing device IDs is +completely bus-specific. Defining them as bus-specific entities would +sacrifice type-safety, so we keep bus-specific structures around. + +Bus-specific drivers should include a generic struct device_driver in +the definition of the bus-specific driver. Like this: + +struct pci_driver { + const struct pci_device_id *id_table; + struct device_driver driver; +}; + +A definition that included bus-specific fields would look something +like (using the eepro100 driver again): + +static struct pci_driver eepro100_driver = { + id_table: eepro100_pci_tbl, + driver: { + name: "eepro100", + bus: &pci_bus_type, + devclass: ðernet_devclass, /* when it's implemented */ + probe: eepro100_probe, + remove: eepro100_remove, + suspend: eepro100_suspend, + resume: eepro100_resume, + }, +}; + +Some may find the syntax of embedded struct intialization awkward or +even a bit ugly. So far, it's the best way we've found to do what we want... + +Registration +~~~~~~~~~~~~ + +int driver_register(struct device_driver * drv); + +The driver registers the structure on startup. For drivers that have +no bus-specific fields (i.e. don't have a bus-specific driver +structure), they would use driver_register and pass a pointer to their +struct device_driver object. + +Most drivers, however, will have a bus-specific structure and will +need to register with the bus using something like pci_driver_register. + +It is important that drivers register their drivers as early as +possible. Registration with the core initializes several fields in the +struct device_driver object, including the reference count and the +lock. These fields are assumed to be valid at all times and may be +used by the device model core or the bus driver. + + +Transition Bus Drivers +~~~~~~~~~~~~~~~~~~~~~~ + +By defining wrapper functions, the transition to the new model can be +made easier. Drivers can ignore the generic structure altogether and +let the bus wrapper fill in the fields. For the callbacks, the bus can +define generic callbacks that forward the call to the bus-specific +callbacks of the drivers. + +This solution is intended to be only temporary. In order to get class +information in the driver, the drivers must be modified anyway. Since +converting drivers to the new model should reduce some infrastructural +complexity and code size, it is recommended that they are converted as +class information is added. + +Access +~~~~~~ + +Once the object has been registered, it may access the common fields of +the object, like the lock and the list of devices. + +int driver_for_each_dev(struct device_driver * drv, void * data, + int (*callback)(struct device * dev, void * data)); + +The devices field is a list of all the devices that have been bound to +the driver. The LDM core provides a helper function to operate on all +the devices a driver controls. This helper locks the driver on each +node access, and does proper reference counting on each device as it +accesses it. + + +driverfs +~~~~~~~~ + +When a driver is registered, a driverfs directory is created in its +bus's directory. In this directory, the driver can export an interface +to userspace to control operation of the driver on a global basis; +e.g. toggling debugging output in the driver. + +A future feature of this directory will be a 'devices' directory. This +directory will contain symlinks to the directories of devices it +supports. + + + +Callbacks +~~~~~~~~~ + + int (*probe) (struct device * dev); + +probe is called to verify the existence of a certain type of +hardware. This is called during the driver binding process, after the +bus has verified that the device ID of a device matches one of the +device IDs supported by the driver. + +This callback only verifies that there actually is supported hardware +present. It may allocate a driver-specific structure, but it should +not do any initialization of the hardware itself. The device-specific +structure may be stored in the device's driver_data field. + + int (*init) (struct device * dev); + +init is called during the binding stage. It is called after probe has +successfully returned and the device has been registered with its +class. It is responsible for initializing the hardware. + + int (*remove) (struct device * dev); + +remove is called to dissociate a driver with a device. This may be +called if a device is physically removed from the system, if the +driver module is being unloaded, or during a reboot sequence. + +It is up to the driver to determine if the device is present or +not. It should free any resources allocated specifically for the +device; i.e. anything in the device's driver_data field. + +If the device is still present, it should quiesce the device and place +it into a supported low-power state. + + int (*suspend) (struct device * dev, u32 state, u32 level); + +suspend is called to put the device in a low power state. There are +several stages to sucessfully suspending a device, which is denoted in +the @level parameter. Breaking the suspend transition into several +stages affords the platform flexibility in performing device power +management based on the requirements of the system and the +user-defined policy. + +SUSPEND_NOTIFY notifies the device that a suspend transition is about +to happen. This happens on system power state transition to verify +that all devices can sucessfully suspend. + +A driver may choose to fail on this call, which should cause the +entire suspend transition to fail. A driver should fail only if it +knows that the device will not be able to be resumed properly when the +system wakes up again. It could also fail if it somehow determines it +is in the middle of an operation too important to stop. + +SUSPEND_DISABLE tells the device to stop I/O transactions. When it +stops transactions, or what it should do with unfinished transactions +is a policy of the driver. After this call, the driver should not +accept any other I/O requests. + +SUSPEND_SAVE_STATE tells the device to save the context of the +hardware. This includes any bus-specific hardware state and +device-specific hardware state. A pointer to this saved state can be +stored in the device's saved_state field. + +SUSPEND_POWER_DOWN tells the driver to place the device in the low +power state requested. + +Whether suspend is called with a given level is a policy of the +platform. Some levels may be omitted; drivers must not assume the +reception of any level. However, all levels must be called in the +order above; i.e. notification will always come before disabling; +disabling the device will come before suspending the device. + +All calls are made with interrupts enabled, except for the +SUSPEND_POWER_DOWN level. + + int (*resume) (struct device * dev, u32 level); + +Resume is used to bring a device back from a low power state. Like the +suspend transition, it happens in several stages. + +RESUME_POWER_ON tells the driver to set the power state to the state +before the suspend call (The device could have already been in a low +power state before the suspend call to put in a lower power state). + +RESUME_RESTORE_STATE tells the driver to restore the state saved by +the SUSPEND_SAVE_STATE suspend call. + +RESUME_ENABLE tells the driver to start accepting I/O transactions +again. Depending on driver policy, the device may already have pending +I/O requests. + +RESUME_POWER_ON is called with interrupts disabled. The other resume +levels are called with interrupts enabled. + +As with the various suspend stages, the driver must not assume that +any other resume calls have been or will be made. Each call should be +self-contained and not dependent on any external state. + + +Attributes +~~~~~~~~~~ +struct driver_attribute { + struct attribute attr; + ssize_t (*show)(struct device_driver *, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off); +}; + +Device drivers can export attributes via their driverfs directories. +Drivers can declare attributes using a DRIVER_ATTR macro that works +identically to the DEVICE_ATTR macro. + +Example: + +DRIVER_ATTR(debug,0644,show_debug,store_debug); + +This is equivalent to declaring: + +struct driver_attribute driver_attr_debug; + +This can then be used to add and remove the attribute from the +driver's directory using: + +int driver_create_file(struct device_driver *, struct driver_attribute *); +void driver_remove_file(struct device_driver *, struct driver_attribute *); diff -Nru a/Documentation/driver-model/interface.txt b/Documentation/driver-model/interface.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/driver-model/interface.txt Fri Sep 20 08:20:49 2002 @@ -0,0 +1,129 @@ + +Device Interfaces + +Introduction +~~~~~~~~~~~~ + +Device interfaces are the logical interfaces of device classes that correlate +directly to userspace interfaces, like device nodes. + +Each device class may have multiple interfaces through which you can +access the same device. An input device may support the mouse interface, +the 'evdev' interface, and the touchscreen interface. A SCSI disk would +support the disk interface, the SCSI generic interface, and possibly a raw +device interface. + +Device interfaces are registered with the class they belong to. As devices +are added to the class, they are added to each interface registered with +the class. The interface is responsible for determining whether the device +supports the interface or not. + + +Programming Interface +~~~~~~~~~~~~~~~~~~~~~ + +struct device_interface { + char * name; + rwlock_t lock; + u32 devnum; + struct device_class * devclass; + + struct list_head node; + struct driver_dir_entry dir; + + int (*add_device)(struct device *); + int (*add_device)(struct intf_data *); +}; + +int interface_register(struct device_interface *); +void interface_unregister(struct device_interface *); + + +An interface must specify the device class it belongs to. It is added +to that class's list of interfaces on registration. + + +Interfaces can be added to a device class at any time. Whenever it is +added, each device in the class is passed to the interface's +add_device callback. When an interface is removed, each device is +removed from the interface. + + +Devices +~~~~~~~ +Once a device is added to a device class, it is added to each +interface that is registered with the device class. The class +is expected to place a class-specific data structure in +struct device::class_data. The interface can use that (along with +other fields of struct device) to determine whether or not the driver +and/or device support that particular interface. + + +Data +~~~~ + +struct intf_data { + struct list_head node; + struct device_interface * intf; + struct device * dev; + u32 intf_num; +}; + +int interface_add_data(struct interface_data *); + +The interface is responsible for allocating and initializing a struct +intf_data and calling interface_add_data() to add it to the device's list +of interfaces it belongs to. This list will be iterated over when the device +is removed from the class (instead of all possible interfaces for a class). +This structure should probably be embedded in whatever per-device data +structure the interface is allocating anyway. + +Devices are enumerated within the interface. This happens in interface_add_data() +and the enumerated value is stored in the struct intf_data for that device. + +driverfs +~~~~~~~~ +Each interface is given a directory in the directory of the device +class it belongs to: + +Interfaces get a directory in the class's directory as well: + + class/ + `-- input + |-- devices + |-- drivers + |-- mouse + `-- evdev + +When a device is added to the interface, a symlink is created that points +to the device's directory in the physical hierarchy: + + class/ + `-- input + |-- devices + | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ + |-- drivers + | `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/ + |-- mouse + | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ + `-- evdev + `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ + + +Future Plans +~~~~~~~~~~~~ +A device interface is correlated directly with a userspace interface +for a device, specifically a device node. For instance, a SCSI disk +exposes at least two interfaces to userspace: the standard SCSI disk +interface and the SCSI generic interface. It might also export a raw +device interface. + +Many interfaces have a major number associated with them and each +device gets a minor number. Or, multiple interfaces might share one +major number, and each get receive a range of minor numbers (like in +the case of input devices). + +These major and minor numbers could be stored in the interface +structure. Major and minor allocation could happen when the interface +is registered with the class, or via a helper function. + diff -Nru a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/driver-model/overview.txt Fri Sep 20 08:20:44 2002 @@ -0,0 +1,114 @@ +The Linux Kernel Device Model + +Patrick Mochel + +26 August 2002 + + +Overview +~~~~~~~~ + +This driver model is a unification of all the current, disparate driver models +that are currently in the kernel. It is intended is to augment the +bus-specific drivers for bridges and devices by consolidating a set of data +and operations into globally accessible data structures. + +Current driver models implement some sort of tree-like structure (sometimes +just a list) for the devices they control. But, there is no linkage between +the different bus types. + +A common data structure can provide this linkage with little overhead: when a +bus driver discovers a particular device, it can insert it into the global +tree as well as its local tree. In fact, the local tree becomes just a subset +of the global tree. + +Common data fields can also be moved out of the local bus models into the +global model. Some of the manipulation of these fields can also be +consolidated. Most likely, manipulation functions will become a set +of helper functions, which the bus drivers wrap around to include any +bus-specific items. + +The common device and bridge interface currently reflects the goals of the +modern PC: namely the ability to do seamless Plug and Play, power management, +and hot plug. (The model dictated by Intel and Microsoft (read: ACPI) ensures +us that any device in the system may fit any of these criteria.) + +In reality, not every bus will be able to support such operations. But, most +buses will support a majority of those operations, and all future buses will. +In other words, a bus that doesn't support an operation is the exception, +instead of the other way around. + + + +Downstream Access +~~~~~~~~~~~~~~~~~ + +Common data fields have been moved out of individual bus layers into a common +data structure. But, these fields must still be accessed by the bus layers, +and sometimes by the device-specific drivers. + +Other bus layers are encouraged to do what has been done for the PCI layer. +struct pci_dev now looks like this: + +struct pci_dev { + ... + + struct device device; +}; + +Note first that it is statically allocated. This means only one allocation on +device discovery. Note also that it is at the _end_ of struct pci_dev. This is +to make people think about what they're doing when switching between the bus +driver and the global driver; and to prevent against mindless casts between +the two. + +The PCI bus layer freely accesses the fields of struct device. It knows about +the structure of struct pci_dev, and it should know the structure of struct +device. PCI devices that have been converted generally do not touch the fields +of struct device. More precisely, device-specific drivers should not touch +fields of struct device unless there is a strong compelling reason to do so. + +This abstraction is prevention of unnecessary pain during transitional phases. +If the name of the field changes or is removed, then every downstream driver +will break. On the other hand, if only the bus layer (and not the device +layer) accesses struct device, it is only those that need to change. + + +User Interface +~~~~~~~~~~~~~~ + +By virtue of having a complete hierarchical view of all the devices in the +system, exporting a complete hierarchical view to userspace becomes relatively +easy. This has been accomplished by implementing a special purpose virtual +file system named driverfs. It is hence possible for the user to mount the +whole driverfs filesystem anywhere in userspace. + +This can be done permanently by providing the following entry into the +/etc/fstab (under the provision that the mount point does exist, of course): + +none /devices driverfs defaults 0 0 + +Or by hand on the command line: + +~: mount -t driverfs none /devices + +Whenever a device is inserted into the tree, a directory is created for it. +This directory may be populated at each layer of discovery - the global layer, +the bus layer, or the device layer. + +The global layer currently creates two files - name and 'power'. The +former only reports the name of the device. The latter reports the +current power state of the device. It also be used to set the current +power state. + +The bus layer may also create files for the devices it finds while probing the +bus. For example, the PCI layer currently creates 'irq' and 'resource' files +for each PCI device. + +A device-specific driver may also export files in its directory to expose +device-specific data or tunable interfaces. + +More information about the driverfs directory layout can be found in +the other documents in this directory and in the file +Documentation/filesystems/driverfs.txt. + diff -Nru a/Documentation/driver-model/platform.txt b/Documentation/driver-model/platform.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/driver-model/platform.txt Fri Sep 20 08:20:49 2002 @@ -0,0 +1,99 @@ +Platform Devices and Drivers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Platform devices +~~~~~~~~~~~~~~~~ +Platform devices are devices that typically appear as autonomous +entities in the system. This includes legacy port-based devices and +host bridges to peripheral buses. + + +Platform drivers +~~~~~~~~~~~~~~~~ +Drivers for platform devices have typically very simple and +unstructured. Either the device was present at a particular I/O port +and the driver was loaded, or there was not. There was no possibility +of hotplugging or alternative discovery besides probing at a specific +I/O address and expecting a specific response. + + +Other Architectures, Modern Firmware, and new Platforms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These devices are not always at the legacy I/O ports. This is true on +other architectures and on some modern architectures. In most cases, +the drivers are modified to discover the devices at other well-known +ports for the given platform. However, the firmware in these systems +does usually know where exactly these devices reside, and in some +cases, it's the only way of discovering them. + + +The Platform Bus +~~~~~~~~~~~~~~~~ +A platform bus has been created to deal with these issues. First and +foremost, it groups all the legacy devices under a common bus, and +gives them a common parent if they don't already have one. + +But, besides the organizational benefits, the platform bus can also +accomodate firmware-based enumeration. + + +Device Discovery +~~~~~~~~~~~~~~~~ +The platform bus has no concept of probing for devices. Devices +discovery is left up to either the legacy drivers or the +firmware. These entities are expected to notify the platform of +devices that it discovers via the bus's add() callback: + + platform_bus.add(parent,bus_id). + + +Bus IDs +~~~~~~~ +Bus IDs are the canonical name for the device. There is no globally +standard addressing mechanism for legacy devices. In the IA-32 world, +we have Pnp IDs to use, as well as the legacy I/O ports. However, +neither tell what the device really is or have any meaning on other +platforms. + +Since both PnP IDs and the legacy I/O ports (and other standard I/O +ports for specific devices) have a 1:1 mapping, we map the +platform-specific name or identifier to a generic name (at least +within the scope of the kernel). + +For example, a serial driver might find a device at I/O 0x3f8. The +ACPI firmware might also discover a device with PnP ID (_HID) +PNP0501. Both correspond to the same device should be mapped to the +canonical name 'serial'. + +The bus_id field should be a concatenation of the canonical name and +the instance of that type of device. For example, the device at I/O +port 0x3f8 should have a bus_id of "serial0". This places the +responsibility of enumerating devices of a particular type up to the +discovery mechanism. But, they are the entity that should know best +(as opposed to the platform bus driver). + + +Drivers +~~~~~~~ +Drivers for platform devices should have a name that is the same as +the canonical name of the devices they support. This allows the +platform bus driver to do simple matching with the basic data +structures to determine if a driver supports a certain device. + +For example, a legacy serial driver should have a name of 'serial' and +register itself with the platform bus. + + +Driver Binding +~~~~~~~~~~~~~~ +Legacy drivers assume they are bound to the device once they start up +and probe an I/O port. Divorcing them from this will be a difficult +process. However, that shouldn't prevent us from impelementing +firmware-based enumeration. + +The firmware should notify the platform bus about devices before the +legacy drivers have had a chance to load. Once the drivers are loaded, +they driver model core will attempt to bind the driver to any +previously-discovered devices. Once that has happened, it will be free +to discover any other devices it pleases. + diff -Nru a/Documentation/driver-model.txt b/Documentation/driver-model.txt --- a/Documentation/driver-model.txt Fri Sep 20 08:20:44 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,624 +0,0 @@ -The (New) Linux Kernel Driver Model - -Version 0.04 - -Patrick Mochel - -03 December 2001 - - -Overview -~~~~~~~~ - -This driver model is a unification of all the current, disparate driver models -that are currently in the kernel. It is intended is to augment the -bus-specific drivers for bridges and devices by consolidating a set of data -and operations into globally accessible data structures. - -Current driver models implement some sort of tree-like structure (sometimes -just a list) for the devices they control. But, there is no linkage between -the different bus types. - -A common data structure can provide this linkage with little overhead: when a -bus driver discovers a particular device, it can insert it into the global -tree as well as its local tree. In fact, the local tree becomes just a subset -of the global tree. - -Common data fields can also be moved out of the local bus models into the -global model. Some of the manipulation of these fields can also be -consolidated. Most likely, manipulation functions will become a set -of helper functions, which the bus drivers wrap around to include any -bus-specific items. - -The common device and bridge interface currently reflects the goals of the -modern PC: namely the ability to do seamless Plug and Play, power management, -and hot plug. (The model dictated by Intel and Microsoft (read: ACPI) ensures -us that any device in the system may fit any of these criteria.) - -In reality, not every bus will be able to support such operations. But, most -buses will support a majority of those operations, and all future buses will. -In other words, a bus that doesn't support an operation is the exception, -instead of the other way around. - - -Drivers -~~~~~~~ - -The callbacks for bridges and devices are intended to be singular for a -particular type of bus. For each type of bus that has support compiled in the -kernel, there should be one statically allocated structure with the -appropriate callbacks that each device (or bridge) of that type share. - -Each bus layer should implement the callbacks for these drivers. It then -forwards the calls on to the device-specific callbacks. This means that -device-specific drivers must still implement callbacks for each operation. -But, they are not called from the top level driver layer. [So for example -PCI devices will not call device_register but pci_device_register.] - -This does add another layer of indirection for calling one of these functions, -but there are benefits that are believed to outweigh this slowdown. - -First, it prevents device-specific drivers from having to know about the -global device layer. This speeds up integration time incredibly. It also -allows drivers to be more portable across kernel versions. Note that the -former was intentional, the latter is an added bonus. - -Second, this added indirection allows the bus to perform any additional logic -necessary for its child devices. A bus layer may add additional information to -the call, or translate it into something meaningful for its children. - -This could be done in the driver, but if it happens for every object of a -particular type, it is best done at a higher level. - -Recap -~~~~~ - -Instances of devices and bridges are allocated dynamically as the system -discovers their existence. Their fields describe the individual object. -Drivers - in the global sense - are statically allocated and singular for a -particular type of bus. They describe a set of operations that every type of -bus could implement, the implementation following the bus's semantics. - - -Downstream Access -~~~~~~~~~~~~~~~~~ - -Common data fields have been moved out of individual bus layers into a common -data structure. But, these fields must still be accessed by the bus layers, -and sometimes by the device-specific drivers. - -Other bus layers are encouraged to do what has been done for the PCI layer. -struct pci_dev now looks like this: - -struct pci_dev { - ... - - struct device device; -}; - -Note first that it is statically allocated. This means only one allocation on -device discovery. Note also that it is at the _end_ of struct pci_dev. This is -to make people think about what they're doing when switching between the bus -driver and the global driver; and to prevent against mindless casts between -the two. - -The PCI bus layer freely accesses the fields of struct device. It knows about -the structure of struct pci_dev, and it should know the structure of struct -device. PCI devices that have been converted generally do not touch the fields -of struct device. More precisely, device-specific drivers should not touch -fields of struct device unless there is a strong compelling reason to do so. - -This abstraction is prevention of unnecessary pain during transitional phases. -If the name of the field changes or is removed, then every downstream driver -will break. On the other hand, if only the bus layer (and not the device -layer) accesses struct device, it is only those that need to change. - - -User Interface -~~~~~~~~~~~~~~ - -By virtue of having a complete hierarchical view of all the devices in the -system, exporting a complete hierarchical view to userspace becomes relatively -easy. This has been accomplished by implementing a special purpose virtual -file system named driverfs. It is hence possible for the user to mount the -whole driverfs on a particular mount point in the unified UNIX file hierarchy. - -This can be done permanently by providing the following entry into the -/dev/fstab (under the provision that the mount point does exist, of course): - -none /devices driverfs defaults 0 0 - -Or by hand on the command line: - -~: mount -t driverfs none /devices - -Whenever a device is inserted into the tree, a directory is created for it. -This directory may be populated at each layer of discovery - the global layer, -the bus layer, or the device layer. - -The global layer currently creates two files - 'status' and 'power'. The -former only reports the name of the device and its bus ID. The latter reports -the current power state of the device. It also be used to set the current -power state. - -The bus layer may also create files for the devices it finds while probing the -bus. For example, the PCI layer currently creates 'wake' and 'resource' files -for each PCI device. - -A device-specific driver may also export files in its directory to expose -device-specific data or tunable interfaces. - -These features were initially implemented using procfs. However, after one -conversation with Linus, a new filesystem - driverfs - was created to -implement these features. It is an in-memory filesystem, based heavily off of -ramfs, though it uses procfs as inspiration for its callback functionality. - -Each struct device has a 'struct driver_dir_entry' which encapsulates the -device's directory and the files within. - -Device Structures -~~~~~~~~~~~~~~~~~ - -struct device { - struct list_head bus_list; - struct iobus *parent; - struct iobus *subordinate; - - char name[DEVICE_NAME_SIZE]; - char bus_id[BUS_ID_SIZE]; - - struct driver_dir_entry * dir; - - spinlock_t lock; - atomic_t refcount; - - struct device_driver *driver; - void *driver_data; - void *platform_data; - - u32 current_state; - unsigned char *saved_state; -}; - -bus_list: - List of all devices on a particular bus; i.e. the device's siblings - -parent: - The parent bridge for the device. - -subordinate: - If the device is a bridge itself, this points to the struct io_bus that is - created for it. - -name: - Human readable (descriptive) name of device. E.g. "Intel EEPro 100" - -bus_id: - Parsable (yet ASCII) bus id. E.g. "00:04.00" (PCI Bus 0, Device 4, Function - 0). It is necessary to have a searchable bus id for each device; making it - ASCII allows us to use it for its directory name without translating it. - -dir: - Driver's driverfs directory. - -lock: - Driver specific lock. - -refcount: - Driver's usage count. - When this goes to 0, the device is assumed to be removed. It will be removed - from its parent's list of children. It's remove() callback will be called to - inform the driver to clean up after itself. - -driver: - Pointer to a struct device_driver, the common operations for each device. See - next section. - -driver_data: - Private data for the driver. - Much like the PCI implementation of this field, this allows device-specific - drivers to keep a pointer to a device-specific data. - -platform_data: - Data that the platform (firmware) provides about the device. - For example, the ACPI BIOS or EFI may have additional information about the - device that is not directly mappable to any existing kernel data structure. - It also allows the platform driver (e.g. ACPI) to a driver without the driver - having to have explicit knowledge of (atrocities like) ACPI. - -current_state: - Current power state of the device. For PCI and other modern devices, this is - 0-3, though it's not necessarily limited to those values. - -saved_state: - Pointer to driver-specific set of saved state. - Having it here allows modules to be unloaded on system suspend and reloaded - on resume and maintain state across transitions. - It also allows generic drivers to maintain state across system state - transitions. - (I've implemented a generic PCI driver for devices that don't have a - device-specific driver. Instead of managing some vector of saved state - for each device the generic driver supports, it can simply store it here.) - - - -struct device_driver { - int (*probe) (struct device *dev); - int (*remove) (struct device *dev); - - int (*suspend) (struct device *dev, u32 state, u32 level); - int (*resume) (struct device *dev, u32 level); -} - -probe: - Check for device existence and associate driver with it. In case of device - insertion, *all* drivers are called. Struct device has parent and bus_id - valid at this point. probe() may only be called from process context. Returns - 0 if it handles that device, -ESRCH if this driver does not know how to handle - this device, valid error otherwise. - -remove: - Dissociate driver with device. Releases device so that it could be used by - another driver. Also, if it is a hotplug device (hotplug PCI, Cardbus), an - ejection event could take place here. remove() can be called from interrupt - context. [Fixme: Is that good?] Returns 0 on success. [Can we recover from - failed remove or should I define that remove() never fails?] - -suspend: - Perform one step of the device suspend process. Returns 0 on success. - -resume: - Perform one step of the device resume process. Returns 0 on success. - -The probe() and remove() callbacks are intended to be much simpler than the -current PCI correspondents. - -probe() should do the following only: - -- Check if hardware is present -- Register device interface -- Disable DMA/interrupts, etc, just in case. - -Some device initialisation was done in probe(). This should not be the case -anymore. All initialisation should take place in the open() call for the -device. [FIXME: How do you "open" uhci?] - -Breaking initialisation code out must also be done for the resume() callback, -as most devices will have to be completely reinitialised when coming back from -a suspend state. - -remove() should simply unregister the device interface. - - -Device power management can be quite complicated, based exactly what is -desired to be done. Four operations sum up most of it: - -- OS directed power management. - The OS takes care of notifying all drivers that a suspend is requested, - saving device state, and powering devices down. -- Firmware controlled power management. - The OS only wants to notify devices that a suspend is requested. -- Device power management. - A user wants to place only one device in a low power state, and maybe save - state. -- System reboot. - The system wants to place devices in a quiescent state before the system is - reset. - -In an attempt to please all of these scenarios, the power management -transition for any device is broken up into several stages - notify, save -state, and power down. The disable stage, which should happen after notify and -before save state has been considered and may be implemented in the future. - -Depending on what the system-wide policy is (usually dictated by the power -management scheme present), each driver's suspend callback may be called -multiple times, each with a different stage. - -On all power management transitions, the stages should be called sequentially -(notify before save state; save state before power down). However, drivers -should not assume that any stage was called before hand. (If a driver gets a -power down call, it shouldn't assume notify or save state was called first.) -This allows the framework to be used seamlessly by all power management -actions. Hopefully. - -Resume transitions happen in a similar manner. They are broken up into two -stages currently (power on and restore state), though a third stage (enable) -may be added later. - -For suspend and resume transitions, the following values are defined to denote -the stage: - -enum{ - SUSPEND_NOTIFY, - SUSPEND_DISABLE, - SUSPEND_SAVE_STATE, - SUSPEND_POWER_DOWN, -}; - -enum { - RESUME_POWER_ON, - RESUME_RESTORE_STATE, - RESUME_ENABLE, -}; - - -During a system power transition, the device tree must be walked in order, -calling the suspend() or resume() callback for each node. This may happen -several times. - -Initially, this was done in kernel space. However, it has occurred to me that -doing recursion to a non-bounded depth is dangerous, and that there are a lot -of inherent race conditions in such an operation. - -Non-recursive walking of the device tree is possible. However, this makes for -convoluted code. - -No matter what, if the transition happens in kernel space, it is difficult to -gracefully recover from errors or to implement a policy that prevents one from -shutting down the device(s) you want to save state to. - -Instead, the walking of the device tree has been moved to userspace. When a -user requests the system to suspend, it will walk the device tree, as exported -via driverfs, and tell each device to go to sleep. It will do this multiple -times based on what the system policy is. [Not possible. Take ACPI enabled -system, with battery critically low. In such state, you want to suspend-to-disk, -*fast*. User maybe is not even running powerd (think system startup)!] - -Device resume should happen in the same manner when the system awakens. - -Each suspend stage is described below: - -SUSPEND_NOTIFY: - -This level to notify the driver that it is going to sleep. If it knows that it -cannot resume the hardware from the requested level, or it feels that it is -too important to be put to sleep, it should return an error from this function. - -It does not have to stop I/O requests or actually save state at this point. Called -from process context. - -SUSPEND_DISABLE: - -The driver should stop taking I/O requests at this stage. Because the save -state stage happens afterwards, the driver may not want to physically disable -the device; only mark itself unavailable if possible. Called from process -context. - -SUSPEND_SAVE_STATE: - -The driver should allocate memory and save any device state that is relevant -for the state it is going to enter. Called from process context. - -SUSPEND_POWER_DOWN: - -The driver should place the device in the power state requested. May be called -from interrupt context. - - -For resume, the stages are defined as follows: - -RESUME_POWER_ON: - -Devices should be powered on and reinitialised to some known working state. -Called from process context. - -RESUME_RESTORE_STATE: - -The driver should restore device state to its pre-suspend state and free any -memory allocated for its saved state. Called from process context. - -RESUME_ENABLE: - -The device should start taking I/O requests again. Called from process context. - - -Each driver does not have to implement each stage. But, it if it does -implement a stage, it should do what is described above. It should not assume -that it performed any stage previously, or that it will perform any stage -later. [Really? It makes sense to support SAVE_STATE only after DISABLE]. - -It is quite possible that a driver can fail during the suspend process, for -whatever reason. In this event, the calling process must gracefully recover -and restore everything to their states before the suspend transition began. -[Suspend may not fail, think battery low.] - -If a driver knows that it cannot suspend or resume properly, it should fail -during the notify stage. Properly implemented power management schemes should -make sure that this is the first stage that is called. - -If a driver gets a power down request, it should obey it, as it may very -likely be during a reboot. - - -Bus Structures -~~~~~~~~~~~~~~ - -struct iobus { - struct list_head node; - struct iobus *parent; - struct list_head children; - struct list_head devices; - - struct list_head bus_list; - - spinlock_t lock; - atomic_t refcount; - - struct device *self; - struct driver_dir_entry * dir; - - char name[DEVICE_NAME_SIZE]; - char bus_id[BUS_ID_SIZE]; - - struct bus_driver *driver; -}; - -node: - Bus's node in sibling list (its parent's list of child buses). - -parent: - Pointer to parent bridge. - -children: - List of subordinate buses. - In the children, this correlates to their 'node' field. - -devices: - List of devices on the bus this bridge controls. - This field corresponds to the 'bus_list' field in each child device. - -bus_list: - Each type of bus keeps a list of all bridges that it finds. This is the - bridges entry in that list. - -self: - Pointer to the struct device for this bridge. - -lock: - Lock for the bus. - -refcount: - Usage count for the bus. - -dir: - Driverfs directory. - -name: - Human readable ASCII name of bus. - -bus_id: - Machine readable (though ASCII) description of position on parent bus. - -driver: - Pointer to operations for bus. - - -struct iobus_driver { - char name[16]; - struct list_head node; - - int (*scan) (struct io_bus*); - int (*add_device) (struct io_bus*, char*); -}; - -name: - ASCII name of bus. - -node: - List of buses of this type in system. - -scan: - Search the bus for new devices. This may happen either at boot - where every - device discovered will be new - or later on - in which there may only be a few - (or no) new devices. - -add_device: - Trigger a device insertion at a particular location. - - - -The API -~~~~~~~ - -There are several functions exported by the global device layer, including -several optional helper functions, written solely to try and make your life -easier. - -void device_init_dev(struct device * dev); - -Initialise a device structure. It first zeros the device, the initialises all -of the lists. (Note that this would have been called device_init(), but that -name was already taken. :/) - - -struct device * device_alloc(void) - -Allocate memory for a device structure and initialise it. -First, allocates memory, then calls device_init_dev() with the new pointer. - - -int device_register(struct device * dev); - -Register a device with the global device layer. -The bus layer should call this function upon device discovery, e.g. when -probing the bus. -dev should be fully initialised when this is called. -If dev->parent is not set, it sets its parent to be the device root. -It then does the following: - - inserts it into its parent's list of children - - creates a driverfs directory for it - - creates a set of default files for the device in its directory - - calls platform_notify() to notify the firmware driver of its existence. - - -void get_device(struct device * dev); - -Increment the refcount for a device. - - -int valid_device(struct device * dev); - -Check if reference count is positive for a device (it's not waiting to be -freed). If it is positive, it increments the reference count for the device. -It returns whether or not the device is usable. - - -void put_device(struct device * dev); - -Decrement the reference count for the device. If it hits 0, it removes the -device from its parent's list of children and calls the remove() callback for -the device. - - -void lock_device(struct device * dev); - -Take the spinlock for the device. - - -void unlock_device(struct device * dev); - -Release the spinlock for the device. - - - -void iobus_init(struct iobus * iobus); -struct iobus * iobus_alloc(void); -int iobus_register(struct iobus * iobus); -void get_iobus(struct iobus * iobus); -int valid_iobus(struct iobus * iobus); -void put_iobus(struct iobus * iobus); -void lock_iobus(struct iobus * iobus); -void unlock_iobus(struct iobus * iobus); - -These functions provide the same functionality as the device_* -counterparts, only operating on a struct iobus. One important thing to note, -though is that iobus_register() and iobus_unregister() operate recursively. It -is possible to add an entire tree in one call. - - - -int device_driver_init(void); - -Main initialisation routine. - -This makes sure driverfs is up and running and initialises the device tree. - - -void device_driver_exit(void); - -This frees up the device tree. - - - - -Credits -~~~~~~~ - -The following people have been extremely helpful in solidifying this document -and the driver model. - -Randy Dunlap rddunlap@osdl.org -Jeff Garzik jgarzik@mandrakesoft.com -Ben Herrenschmidt benh@kernel.crashing.org - - diff -Nru a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt --- a/Documentation/filesystems/proc.txt Fri Sep 20 08:20:44 2002 +++ b/Documentation/filesystems/proc.txt Fri Sep 20 08:20:44 2002 @@ -963,13 +963,6 @@ a process which is generating disk writes will itself start writing out dirty data. -dirty_sync_ratio ----------------- - -Contains, as a percentage of total system memory, the number of pages at which -a process which is generating disk writes will itself start writing out dirty -data and waiting upon completion of that writeout. - dirty_writeback_centisecs ------------------------- diff -Nru a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt --- a/Documentation/sysctl/vm.txt Fri Sep 20 08:20:47 2002 +++ b/Documentation/sysctl/vm.txt Fri Sep 20 08:20:47 2002 @@ -21,13 +21,12 @@ - dirty_async_ratio - dirty_background_ratio - dirty_expire_centisecs -- dirty_sync_ratio - dirty_writeback_centisecs ============================================================== dirty_async_ratio, dirty_background_ratio, dirty_expire_centisecs, -dirty_sync_ratio dirty_writeback_centisecs: +dirty_writeback_centisecs: See Documentation/filesystems/proc.txt diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Fri Sep 20 08:20:47 2002 +++ b/MAINTAINERS Fri Sep 20 08:20:47 2002 @@ -240,8 +240,8 @@ S: Maintained AX.25 NETWORK LAYER -P: Matthias Welwarsky -M: dg2fef@afthd.tu-darmstadt.de +P: Ralf Baechle +M: ralf@linux-mips.org L: linux-hams@vger.kernel.org S: Maintained @@ -531,6 +531,14 @@ L: linux-eata@i-connect.net, linux-scsi@vger.kernel.org S: Maintained +EBTABLES +P: Bart De Schuymer +M: bart.de.schuymer@pandora.be +L: ebtables-user@lists.sourceforge.net +L: ebtables-devel@lists.sourceforge.net +W: http://ebtables.sourceforge.net/ +S: Maintained + EEPRO100 NETWORK DRIVER P: Andrey V. Savochkin M: saw@saw.sw.com.sg @@ -733,12 +741,9 @@ S: Supported IDE DRIVER [GENERAL] -P: Martin Dalecki -M: martin@dalecki.de -I: pl_PL.ISO8859-2, de_DE.ISO8859-15, (en_US.ISO8859-1) L: linux-kernel@vger.kernel.org -W: http://www.dalecki.de -S: Developement +L: linux-ide@vger.kernel.org +S: Maintained IDE/ATAPI CDROM DRIVER P: Jens Axboe @@ -912,8 +917,6 @@ S: Maintained KERNEL BUILD (Makefile, Rules.make, scripts/*) -P: Keith Owens -M: kaos@ocs.com.au P: Michael Elizabeth Chastain M: mec@shout.net L: kbuild-devel@lists.sourceforge.net @@ -1056,12 +1059,6 @@ L: linux-kernel@vger.kernel.org S: Maintained -MODULE SUPPORT [GENERAL], KMOD -P: Keith Owens -M: kaos@ocs.com.au -L: linux-kernel@vger.kernel.org -S: Maintained - MOUSE AND MISC DEVICES [GENERAL] P: Alessandro Rubini M: rubini@ipvvis.unipv.it @@ -1113,8 +1110,8 @@ S: Supported NETROM NETWORK LAYER -P: Tomi Manninen -M: Tomi.Manninen@hut.fi +P: Ralf Baechle +M: ralf@linux-mips.org L: linux-hams@vger.kernel.org S: Maintained @@ -1363,8 +1360,8 @@ S: Supported ROSE NETWORK LAYER -P: Jean-Paul Roubelat -M: jpr@f6fbb.org +P: Ralf Baechle +M: ralf@linux-mips.org L: linux-hams@vger.kernel.org S: Maintained diff -Nru a/Makefile b/Makefile --- a/Makefile Fri Sep 20 08:20:41 2002 +++ b/Makefile Fri Sep 20 08:20:41 2002 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 36 +SUBLEVEL = 37 EXTRAVERSION = # *DOCUMENTATION* @@ -162,8 +162,6 @@ export srctree objtree -SUBDIRS := init kernel mm fs ipc lib drivers sound net security - # The temporary file to save gcc -MD generated dependencies must not # contain a comma depfile = $(subst $(comma),_,$(@D)/.$(@F).d) @@ -246,15 +244,33 @@ # Link components for vmlinux # --------------------------------------------------------------------------- -INIT := init/init.o -CORE_FILES := kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o security/built-in.o -LIBS := lib/lib.a -DRIVERS := drivers/built-in.o sound/sound.o -NETWORKS := net/network.o +init-y := init/ +drivers-y := drivers/ sound/ +networks-y := net/ +libs-y := lib/ + +CORE_FILES := kernel/built-in.o mm/built-in.o fs/built-in.o \ + ipc/built-in.o security/built-in.o +SUBDIRS += kernel mm fs ipc security include arch/$(ARCH)/Makefile -export NETWORKS DRIVERS LIBS HEAD LDFLAGS MAKEBOOT ASFLAGS +SUBDIRS += $(patsubst %/,%,$(filter %/, $(init-y) $(init-m))) +INIT += $(patsubst %/, %/built-in.o, $(init-y)) + +SUBDIRS += $(patsubst %/,%,$(filter %/, $(core-y) $(core-m))) +CORE_FILES := $(patsubst %/, %/built-in.o, $(core-y)) $(CORE_FILES) + +SUBDIRS += $(patsubst %/,%,$(filter %/, $(drivers-y) $(drivers-m))) +DRIVERS += $(patsubst %/, %/built-in.o, $(drivers-y)) + +SUBDIRS += $(patsubst %/,%,$(filter %/, $(networks-y) $(networks-m))) +NETWORKS += $(patsubst %/, %/built-in.o, $(networks-y)) + +SUBDIRS += $(patsubst %/,%,$(filter %/, $(libs-y) $(libs-m))) +LIBS += $(patsubst %/, %/lib.a, $(libs-y)) + +export NETWORKS DRIVERS LIBS HEAD LDFLAGS MAKEBOOT # boot target # --------------------------------------------------------------------------- diff -Nru a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c --- a/arch/alpha/mm/numa.c Fri Sep 20 08:20:41 2002 +++ b/arch/alpha/mm/numa.c Fri Sep 20 08:20:41 2002 @@ -286,7 +286,6 @@ for (nid = 0; nid < numnodes; nid++) { unsigned long start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT; unsigned long end_pfn = plat_node_bdata[nid].node_low_pfn; - unsigned long lmax_mapnr; if (dma_local_pfn >= end_pfn - start_pfn) zones_size[ZONE_DMA] = end_pfn - start_pfn; @@ -295,11 +294,6 @@ zones_size[ZONE_NORMAL] = (end_pfn - start_pfn) - dma_local_pfn; } free_area_init_node(nid, NODE_DATA(nid), NULL, zones_size, start_pfn, NULL); - lmax_mapnr = PLAT_NODE_DATA_STARTNR(nid) + PLAT_NODE_DATA_SIZE(nid); - if (lmax_mapnr > max_mapnr) { - max_mapnr = lmax_mapnr; - DBGDCONT("Grow max_mapnr to %ld\n", max_mapnr); - } } /* Initialize the kernel's ZERO_PGE. */ diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile --- a/arch/i386/Makefile Fri Sep 20 08:20:44 2002 +++ b/arch/i386/Makefile Fri Sep 20 08:20:44 2002 @@ -85,22 +85,21 @@ CFLAGS += -march=i586 endif -HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o - -SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib +ifdef CONFIG_VISWS +MACHINE := mach-visws +else +MACHINE := mach-generic +endif -CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) -LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a +HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o -ifdef CONFIG_MATH_EMULATION -SUBDIRS += arch/i386/math-emu -DRIVERS += arch/i386/math-emu/math.o -endif +libs-y += arch/i386/lib/ +core-y += arch/i386/kernel/ arch/i386/mm/ arch/i386/$(MACHINE)/ +drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/ +drivers-$(CONFIG_PCI) += arch/i386/pci/ -ifdef CONFIG_PCI -SUBDIRS += arch/i386/pci -DRIVERS += arch/i386/pci/pci.o -endif +CFLAGS += -I$(TOPDIR)/arch/i386/$(MACHINE) +AFLAGS += -I$(TOPDIR)/arch/i386/$(MACHINE) MAKEBOOT = +$(MAKE) -C arch/$(ARCH)/boot diff -Nru a/arch/i386/config.in b/arch/i386/config.in --- a/arch/i386/config.in Fri Sep 20 08:20:44 2002 +++ b/arch/i386/config.in Fri Sep 20 08:20:44 2002 @@ -154,7 +154,7 @@ define_bool CONFIG_X86_OOSTORE y fi -bool 'IA-32 Huge TLB Page Support (if available on processor)' CONFIG_HUGETLB_PAGE +bool 'Huge TLB Page Support' CONFIG_HUGETLB_PAGE bool 'Symmetric multi-processing support' CONFIG_SMP bool 'Preemptible Kernel' CONFIG_PREEMPT @@ -260,6 +260,7 @@ if [ "$CONFIG_SMP" = "y" ]; then define_bool CONFIG_X86_IO_APIC y define_bool CONFIG_X86_LOCAL_APIC y + define_bool CONFIG_X86_MPPARSE y fi bool 'PCI support' CONFIG_PCI if [ "$CONFIG_PCI" = "y" ]; then @@ -437,7 +438,19 @@ fi fi +if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then + define_bool CONFIG_X86_EXTRA_IRQS y + define_bool CONFIG_X86_FIND_SMP_CONFIG y +fi + endmenu source security/Config.in source lib/Config.in + +if [ "$CONFIG_SMP" = "y" ]; then + define_bool CONFIG_X86_SMP y + define_bool CONFIG_X86_HT y +fi + +define_bool CONFIG_X86_BIOS_REBOOT y diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile --- a/arch/i386/kernel/Makefile Fri Sep 20 08:20:43 2002 +++ b/arch/i386/kernel/Makefile Fri Sep 20 08:20:43 2002 @@ -2,9 +2,7 @@ # Makefile for the linux kernel. # -EXTRA_TARGETS := kernel.o head.o init_task.o - -O_TARGET := kernel.o +EXTRA_TARGETS := head.o init_task.o export-objs := mca.o i386_ksyms.o time.o @@ -14,6 +12,7 @@ bootflag.o obj-y += cpu/ +obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o @@ -21,15 +20,12 @@ obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_ACPI) += acpi.o obj-$(CONFIG_ACPI_SLEEP) += acpi_wakeup.o -obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o -obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o +obj-$(CONFIG_X86_SMP) += smp.o smpboot.o trampoline.o +obj-$(CONFIG_X86_MPPARSE) += mpparse.o +obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o obj-$(CONFIG_X86_NUMAQ) += numaq.o -ifdef CONFIG_VISWS -obj-y += setup-visws.o -obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o -endif EXTRA_AFLAGS := -traditional diff -Nru a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c --- a/arch/i386/kernel/acpi.c Fri Sep 20 08:20:47 2002 +++ b/arch/i386/kernel/acpi.c Fri Sep 20 08:20:47 2002 @@ -47,6 +47,7 @@ #define PREFIX "ACPI: " +extern int acpi_disabled; /* -------------------------------------------------------------------------- Boot-time Configuration @@ -56,42 +57,40 @@ #ifdef CONFIG_ACPI_BOOT /* - * Use reserved fixmap pages for physical-to-virtual mappings of ACPI tables. - * Note that the same range is used for each table, so tables that need to - * persist should be memcpy'd. + * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, + * to map the target physical address. The problem is that set_fixmap() + * provides a single page, and it is possible that the page is not + * sufficient. + * By using this area, we can map up to MAX_IO_APICS pages temporarily, + * i.e. until the next __va_range() call. + * + * Important Safety Note: The fixed I/O APIC page numbers are *subtracted* + * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and + * count idx down while incrementing the phys address. */ -char * -__acpi_map_table ( - unsigned long phys_addr, - unsigned long size) -{ - unsigned long base = 0; - unsigned long mapped_phys = phys_addr; - unsigned long offset = phys_addr & (PAGE_SIZE - 1); - unsigned long mapped_size = PAGE_SIZE - offset; - unsigned long avail_size = mapped_size + (PAGE_SIZE * FIX_ACPI_PAGES); - int idx = FIX_ACPI_BEGIN; - - if (!phys_addr || !size) - return NULL; - - base = fix_to_virt(FIX_ACPI_BEGIN); +char *__acpi_map_table(unsigned long phys, unsigned long size) +{ + unsigned long base, offset, mapped_size; + int idx; - set_fixmap(idx, mapped_phys); + if (phys + size < 8*1024*1024) + return __va(phys); - if (size > avail_size) - return NULL; + offset = phys & (PAGE_SIZE - 1); + mapped_size = PAGE_SIZE - offset; + set_fixmap(FIX_ACPI_END, phys); + base = fix_to_virt(FIX_ACPI_END); - /* If the table doesn't map completely into the fist page... */ - if (size > mapped_size) { - do { - /* Make sure we don't go past our range */ - if (idx++ == FIX_ACPI_END) - return NULL; - mapped_phys = mapped_phys + PAGE_SIZE; - set_fixmap(idx, mapped_phys); - mapped_size = mapped_size + PAGE_SIZE; - } while (mapped_size < size); + /* + * Most cases can be covered by the below. + */ + idx = FIX_ACPI_END; + while (mapped_size < size) { + if (--idx < FIX_ACPI_BEGIN) + return 0; /* cannot handle this */ + phys += PAGE_SIZE; + set_fixmap(idx, phys); + mapped_size += PAGE_SIZE; } return ((unsigned char *) base + offset); @@ -317,6 +316,14 @@ result = acpi_table_init(cmdline); if (result) return result; + + result = acpi_blacklisted(); + if (result) { + acpi_disabled = 1; + return result; + } + else + printk(KERN_NOTICE PREFIX "BIOS passes blacklist\n"); #ifdef CONFIG_X86_LOCAL_APIC diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c --- a/arch/i386/kernel/apic.c Fri Sep 20 08:20:48 2002 +++ b/arch/i386/kernel/apic.c Fri Sep 20 08:20:48 2002 @@ -29,6 +29,21 @@ #include #include #include +#include +#include + +void __init apic_intr_init(void) +{ +#ifdef CONFIG_SMP + smp_intr_init(); +#endif + /* self generated IPI for local APIC timer */ + set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); + + /* IPI vectors for APIC spurious and error interrupts */ + set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); + set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); +} /* Using APIC to generate smp_local_timer_interrupt? */ int using_apic_timer = 0; diff -Nru a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c --- a/arch/i386/kernel/cpu/amd.c Fri Sep 20 08:20:48 2002 +++ b/arch/i386/kernel/cpu/amd.c Fri Sep 20 08:20:48 2002 @@ -25,7 +25,7 @@ static void __init init_amd(struct cpuinfo_x86 *c) { u32 l, h; - int mbytes = max_mapnr >> (20-PAGE_SHIFT); + int mbytes = num_physpages >> (20-PAGE_SHIFT); int r; /* diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c --- a/arch/i386/kernel/cpu/intel.c Fri Sep 20 08:20:44 2002 +++ b/arch/i386/kernel/cpu/intel.c Fri Sep 20 08:20:44 2002 @@ -257,7 +257,7 @@ if ( p ) strcpy(c->x86_model_id, p); -#ifdef CONFIG_SMP +#ifdef CONFIG_X86_HT if (test_bit(X86_FEATURE_HT, c->x86_capability) && !disable_P4_HT) { extern int phys_proc_id[NR_CPUS]; diff -Nru a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h --- a/arch/i386/kernel/cpu/mtrr/mtrr.h Fri Sep 20 08:20:43 2002 +++ b/arch/i386/kernel/cpu/mtrr/mtrr.h Fri Sep 20 08:20:43 2002 @@ -96,4 +96,7 @@ extern unsigned int num_var_ranges; +void finalize_mtrr_state(void); +void mtrr_state_warn(void); + extern char * mtrr_if_name[]; diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S --- a/arch/i386/kernel/entry.S Fri Sep 20 08:20:44 2002 +++ b/arch/i386/kernel/entry.S Fri Sep 20 08:20:44 2002 @@ -47,7 +47,7 @@ #include #include #include -#include +#include "irq_vectors.h" EBX = 0x00 ECX = 0x04 @@ -344,34 +344,8 @@ call smp_/**/name; \ jmp ret_from_intr; -/* - * The following vectors are part of the Linux architecture, there - * is no hardware IRQ pin equivalent for them, they are triggered - * through the ICC by us (IPIs) - */ -#ifdef CONFIG_SMP -BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) -BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) -BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) -#endif - -/* - * every pentium local APIC has two 'local interrupts', with a - * soft-definable vector attached to both interrupts, one of - * which is a timer interrupt, the other one is error counter - * overflow. Linux uses the local APIC timer interrupt to get - * a much simpler SMP time architecture: - */ -#ifdef CONFIG_X86_LOCAL_APIC -BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) -BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) -BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) - -#ifdef CONFIG_X86_MCE_P4THERMAL -BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) -#endif - -#endif +/* The include is where all of the SMP etc. interrupts come from */ +#include "entry_arch.h" ENTRY(divide_error) pushl $0 # no error code diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c --- a/arch/i386/kernel/i386_ksyms.c Fri Sep 20 08:20:46 2002 +++ b/arch/i386/kernel/i386_ksyms.c Fri Sep 20 08:20:46 2002 @@ -58,7 +58,11 @@ EXPORT_SYMBOL(EISA_bus); #endif EXPORT_SYMBOL(MCA_bus); -#ifdef CONFIG_MULTIQUAD +#ifdef CONFIG_DISCONTIGMEM +EXPORT_SYMBOL(node_data); +EXPORT_SYMBOL(pfn_to_nid); +#endif +#ifdef CONFIG_X86_NUMAQ EXPORT_SYMBOL(xquad_portio); #endif EXPORT_SYMBOL(__verify_write); diff -Nru a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c --- a/arch/i386/kernel/i8259.c Fri Sep 20 08:20:47 2002 +++ b/arch/i386/kernel/i8259.c Fri Sep 20 08:20:47 2002 @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -332,15 +333,6 @@ */ static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL }; -/* - * IRQ2 is cascade interrupt to second interrupt controller - */ - -#ifndef CONFIG_VISWS -static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; -#endif - - void __init init_ISA_irqs (void) { int i; @@ -373,11 +365,9 @@ { int i; -#ifndef CONFIG_X86_VISWS_APIC - init_ISA_irqs(); -#else - init_VISWS_APIC_irqs(); -#endif + /* all the set up before the call gates are initialised */ + pre_intr_init_hook(); + /* * Cover the whole vector space, no vector can escape * us. (some of these will be overridden and become @@ -389,39 +379,9 @@ set_intr_gate(vector, interrupt[i]); } -#ifdef CONFIG_SMP - /* - * IRQ0 must be given a fixed assignment and initialized, - * because it's used before the IO-APIC is set up. - */ - set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]); - - /* - * The reschedule interrupt is a CPU-to-CPU reschedule-helper - * IPI, driven by wakeup. - */ - set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); - - /* IPI for invalidation */ - set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); - - /* IPI for generic function call */ - set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); -#endif - -#ifdef CONFIG_X86_LOCAL_APIC - /* self generated IPI for local APIC timer */ - set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); - - /* IPI vectors for APIC spurious and error interrupts */ - set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); - set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); - - /* thermal monitor LVT interrupt */ -#ifdef CONFIG_X86_MCE_P4THERMAL - set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); -#endif -#endif + /* setup after call gates are initialised (usually add in + * the architecture specific gates */ + intr_init_hook(); /* * Set the clock to HZ Hz, we already have a valid @@ -430,10 +390,6 @@ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ outb_p(LATCH & 0xff , 0x40); /* LSB */ outb(LATCH >> 8 , 0x40); /* MSB */ - -#ifndef CONFIG_VISWS - setup_irq(2, &irq2); -#endif /* * External FPU? Set up irq13 if so, for diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c --- a/arch/i386/kernel/io_apic.c Fri Sep 20 08:20:44 2002 +++ b/arch/i386/kernel/io_apic.c Fri Sep 20 08:20:44 2002 @@ -1885,7 +1885,7 @@ io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); spin_unlock_irqrestore(&ioapic_lock, flags); - return entry.vector; + return 0; } #endif /*CONFIG_ACPI_BOOT*/ diff -Nru a/arch/i386/kernel/mca.c b/arch/i386/kernel/mca.c --- a/arch/i386/kernel/mca.c Fri Sep 20 08:20:43 2002 +++ b/arch/i386/kernel/mca.c Fri Sep 20 08:20:43 2002 @@ -52,6 +52,7 @@ #include #include #include +#include /* This structure holds MCA information. Each (plug-in) adapter has * eight POS registers. Then the machine may have integrated video and @@ -379,12 +380,7 @@ } } - /* If I recall correctly, there's a whole bunch of other things that - * we can do to check for NMI problems, but that's all I know about - * at the moment. - */ - - printk("NMI generated from unknown source!\n"); + mca_nmi_hook(); } /* mca_handle_nmi */ /*--------------------------------------------------------------------*/ diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c --- a/arch/i386/kernel/mpparse.c Fri Sep 20 08:20:44 2002 +++ b/arch/i386/kernel/mpparse.c Fri Sep 20 08:20:44 2002 @@ -73,7 +73,7 @@ * Intel MP BIOS table parsing routines: */ -#ifndef CONFIG_X86_VISWS_APIC + /* * Checksum an MP configuration block. */ @@ -737,7 +737,7 @@ return 0; } -void __init find_intel_smp (void) +void __init find_smp_config (void) { unsigned int address; @@ -777,40 +777,6 @@ printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n"); } -#else - -/* - * The Visual Workstation is Intel MP compliant in the hardware - * sense, but it doesn't have a BIOS(-configuration table). - * No problem for Linux. - */ -void __init find_visws_smp(void) -{ - smp_found_config = 1; - - phys_cpu_present_map |= 2; /* or in id 1 */ - apic_version[1] |= 0x10; /* integrated APIC */ - apic_version[0] |= 0x10; - - mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; -} - -#endif - -/* - * - Intel MP Configuration Table - * - or SGI Visual Workstation configuration - */ -void __init find_smp_config (void) -{ -#ifdef CONFIG_X86_LOCAL_APIC - find_intel_smp(); -#endif -#ifdef CONFIG_VISWS - find_visws_smp(); -#endif -} - /* -------------------------------------------------------------------------- ACPI-based MP Configuration @@ -976,7 +942,7 @@ intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; /* APIC ID */ intsrc.mpc_dstirq = pin; /* INTIN# */ - Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n", + Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n", intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3, (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq); @@ -1049,8 +1015,20 @@ if (++mp_irq_entries == MAX_IRQ_SOURCES) panic("Max # of irq sources exceeded!\n"); } +} - return; +/* Ensure the ACPI SCI interrupt level is active low, edge-triggered */ + +void __init mp_config_ioapic_for_sci(int irq) +{ + int ioapic; + int ioapic_pin; + + ioapic = mp_find_ioapic(irq); + + ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; + + io_apic_set_pci_routing(ioapic, ioapic_pin, irq); } #ifdef CONFIG_ACPI_PCI @@ -1059,7 +1037,6 @@ { struct list_head *node = NULL; struct acpi_prt_entry *entry = NULL; - int vector = 0; int ioapic = -1; int ioapic_pin = 0; int irq = 0; @@ -1104,14 +1081,13 @@ mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<irq = irq; - printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> vector 0x%02x" - " -> IRQ %d\n", entry->id.segment, entry->id.bus, + printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n", + entry->id.segment, entry->id.bus, entry->id.device, ('A' + entry->pin), - mp_ioapic_routing[ioapic].apic_id, ioapic_pin, vector, + mp_ioapic_routing[ioapic].apic_id, ioapic_pin, entry->irq); } diff -Nru a/arch/i386/kernel/numaq.c b/arch/i386/kernel/numaq.c --- a/arch/i386/kernel/numaq.c Fri Sep 20 08:20:43 2002 +++ b/arch/i386/kernel/numaq.c Fri Sep 20 08:20:43 2002 @@ -82,27 +82,19 @@ */ int physnode_map[MAX_ELEMENTS] = { [0 ... (MAX_ELEMENTS - 1)] = -1}; -#define MB_TO_ELEMENT(x) (x >> ELEMENT_REPRESENTS) -#define PA_TO_MB(pa) (pa >> 20) /* assumption: a physical address is in bytes */ +#define PFN_TO_ELEMENT(pfn) (pfn / PAGES_PER_ELEMENT) +#define PA_TO_ELEMENT(pa) (PFN_TO_ELEMENT(pa >> PAGE_SHIFT)) -int pa_to_nid(u64 pa) +int pfn_to_nid(unsigned long pfn) { - int nid; - - nid = physnode_map[MB_TO_ELEMENT(PA_TO_MB(pa))]; + int nid = physnode_map[PFN_TO_ELEMENT(pfn)]; - /* the physical address passed in is not in the map for the system */ if (nid == -1) - BUG(); + BUG(); /* address is not present */ return nid; } -int pfn_to_nid(unsigned long pfn) -{ - return pa_to_nid(((u64)pfn) << PAGE_SHIFT); -} - /* * for each node mark the regions * TOPOFMEM = hi_shrd_mem_start + hi_shrd_mem_size @@ -132,7 +124,7 @@ topofmem = eq->hi_shrd_mem_start + eq->hi_shrd_mem_size; while (cur < topofmem) { physnode_map[cur >> 8] = nid; - cur += (ELEMENT_REPRESENTS - 1); + cur ++; } } } diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c --- a/arch/i386/kernel/process.c Fri Sep 20 08:20:41 2002 +++ b/arch/i386/kernel/process.c Fri Sep 20 08:20:41 2002 @@ -66,11 +66,6 @@ */ void (*pm_idle)(void); -/* - * Power off function, if any - */ -void (*pm_power_off)(void); - void disable_hlt(void) { hlt_counter++; @@ -159,282 +154,6 @@ } __setup("idle=", idle_setup); - -static long no_idt[2]; -static int reboot_mode; -int reboot_thru_bios; - -#ifdef CONFIG_SMP -int reboot_smp = 0; -static int reboot_cpu = -1; -/* shamelessly grabbed from lib/vsprintf.c for readability */ -#define is_digit(c) ((c) >= '0' && (c) <= '9') -#endif -static int __init reboot_setup(char *str) -{ - while(1) { - switch (*str) { - case 'w': /* "warm" reboot (no memory testing etc) */ - reboot_mode = 0x1234; - break; - case 'c': /* "cold" reboot (with memory testing etc) */ - reboot_mode = 0x0; - break; - case 'b': /* "bios" reboot by jumping through the BIOS */ - reboot_thru_bios = 1; - break; - case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */ - reboot_thru_bios = 0; - break; -#ifdef CONFIG_SMP - case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ - reboot_smp = 1; - if (is_digit(*(str+1))) { - reboot_cpu = (int) (*(str+1) - '0'); - if (is_digit(*(str+2))) - reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); - } - /* we will leave sorting out the final value - when we are ready to reboot, since we might not - have set up boot_cpu_id or smp_num_cpu */ - break; -#endif - } - if((str = strchr(str,',')) != NULL) - str++; - else - break; - } - return 1; -} - -__setup("reboot=", reboot_setup); - -/* The following code and data reboots the machine by switching to real - mode and jumping to the BIOS reset entry point, as if the CPU has - really been reset. The previous version asked the keyboard - controller to pulse the CPU reset line, which is more thorough, but - doesn't work with at least one type of 486 motherboard. It is easy - to stop this code working; hence the copious comments. */ - -static unsigned long long -real_mode_gdt_entries [3] = -{ - 0x0000000000000000ULL, /* Null descriptor */ - 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ - 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ -}; - -static struct -{ - unsigned short size __attribute__ ((packed)); - unsigned long long * base __attribute__ ((packed)); -} -real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, -real_mode_idt = { 0x3ff, 0 }; - -/* This is 16-bit protected mode code to disable paging and the cache, - switch to real mode and jump to the BIOS reset code. - - The instruction that switches to real mode by writing to CR0 must be - followed immediately by a far jump instruction, which set CS to a - valid value for real mode, and flushes the prefetch queue to avoid - running instructions that have already been decoded in protected - mode. - - Clears all the flags except ET, especially PG (paging), PE - (protected-mode enable) and TS (task switch for coprocessor state - save). Flushes the TLB after paging has been disabled. Sets CD and - NW, to disable the cache on a 486, and invalidates the cache. This - is more like the state of a 486 after reset. I don't know if - something else should be done for other chips. - - More could be done here to set up the registers as if a CPU reset had - occurred; hopefully real BIOSs don't assume much. */ - -static unsigned char real_mode_switch [] = -{ - 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ - 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ - 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ - 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ - 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ - 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ - 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ - 0x74, 0x02, /* jz f */ - 0x0f, 0x08, /* invd */ - 0x24, 0x10, /* f: andb $0x10,al */ - 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ -}; -static unsigned char jump_to_bios [] = -{ - 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ -}; - -static inline void kb_wait(void) -{ - int i; - - for (i=0; i<0x10000; i++) - if ((inb_p(0x64) & 0x02) == 0) - break; -} - -/* - * Switch to real mode and then execute the code - * specified by the code and length parameters. - * We assume that length will aways be less that 100! - */ -void machine_real_restart(unsigned char *code, int length) -{ - unsigned long flags; - - local_irq_disable(); - - /* Write zero to CMOS register number 0x0f, which the BIOS POST - routine will recognize as telling it to do a proper reboot. (Well - that's what this book in front of me says -- it may only apply to - the Phoenix BIOS though, it's not clear). At the same time, - disable NMIs by setting the top bit in the CMOS address register, - as we're about to do peculiar things to the CPU. I'm not sure if - `outb_p' is needed instead of just `outb'. Use it to be on the - safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) - */ - - spin_lock_irqsave(&rtc_lock, flags); - CMOS_WRITE(0x00, 0x8f); - spin_unlock_irqrestore(&rtc_lock, flags); - - /* Remap the kernel at virtual address zero, as well as offset zero - from the kernel segment. This assumes the kernel segment starts at - virtual address PAGE_OFFSET. */ - - memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, - sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); - - /* - * Use `swapper_pg_dir' as our page directory. - */ - load_cr3(swapper_pg_dir); - - /* Write 0x1234 to absolute memory location 0x472. The BIOS reads - this on booting to tell it to "Bypass memory test (also warm - boot)". This seems like a fairly standard thing that gets set by - REBOOT.COM programs, and the previous reset routine did this - too. */ - - *((unsigned short *)0x472) = reboot_mode; - - /* For the switch to real mode, copy some code to low memory. It has - to be in the first 64k because it is running in 16-bit mode, and it - has to have the same physical and virtual address, because it turns - off paging. Copy it near the end of the first page, out of the way - of BIOS variables. */ - - memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), - real_mode_switch, sizeof (real_mode_switch)); - memcpy ((void *) (0x1000 - 100), code, length); - - /* Set up the IDT for real mode. */ - - __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); - - /* Set up a GDT from which we can load segment descriptors for real - mode. The GDT is not used in real mode; it is just needed here to - prepare the descriptors. */ - - __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt)); - - /* Load the data segment registers, and thus the descriptors ready for - real mode. The base address of each segment is 0x100, 16 times the - selector value being loaded here. This is so that the segment - registers don't have to be reloaded after switching to real mode: - the values are consistent for real mode operation already. */ - - __asm__ __volatile__ ("movl $0x0010,%%eax\n" - "\tmovl %%eax,%%ds\n" - "\tmovl %%eax,%%es\n" - "\tmovl %%eax,%%fs\n" - "\tmovl %%eax,%%gs\n" - "\tmovl %%eax,%%ss" : : : "eax"); - - /* Jump to the 16-bit code that we copied earlier. It disables paging - and the cache, switches to real mode, and jumps to the BIOS reset - entry point. */ - - __asm__ __volatile__ ("ljmp $0x0008,%0" - : - : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); -} - -void machine_restart(char * __unused) -{ -#if CONFIG_SMP - int cpuid; - - cpuid = GET_APIC_ID(apic_read(APIC_ID)); - - if (reboot_smp) { - - /* check to see if reboot_cpu is valid - if its not, default to the BSP */ - if ((reboot_cpu == -1) || - (reboot_cpu > (NR_CPUS -1)) || - !(phys_cpu_present_map & (1< + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MATH_EMULATION +#include +#endif + +#include +#include + +/* + * Power off function, if any + */ +void (*pm_power_off)(void); + +static long no_idt[2]; +static int reboot_mode; +int reboot_thru_bios; + +#ifdef CONFIG_SMP +int reboot_smp = 0; +static int reboot_cpu = -1; +/* shamelessly grabbed from lib/vsprintf.c for readability */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') +#endif +static int __init reboot_setup(char *str) +{ + while(1) { + switch (*str) { + case 'w': /* "warm" reboot (no memory testing etc) */ + reboot_mode = 0x1234; + break; + case 'c': /* "cold" reboot (with memory testing etc) */ + reboot_mode = 0x0; + break; + case 'b': /* "bios" reboot by jumping through the BIOS */ + reboot_thru_bios = 1; + break; + case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */ + reboot_thru_bios = 0; + break; +#ifdef CONFIG_SMP + case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ + reboot_smp = 1; + if (is_digit(*(str+1))) { + reboot_cpu = (int) (*(str+1) - '0'); + if (is_digit(*(str+2))) + reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); + } + /* we will leave sorting out the final value + when we are ready to reboot, since we might not + have set up boot_cpu_id or smp_num_cpu */ + break; +#endif + } + if((str = strchr(str,',')) != NULL) + str++; + else + break; + } + return 1; +} + +__setup("reboot=", reboot_setup); + +/* The following code and data reboots the machine by switching to real + mode and jumping to the BIOS reset entry point, as if the CPU has + really been reset. The previous version asked the keyboard + controller to pulse the CPU reset line, which is more thorough, but + doesn't work with at least one type of 486 motherboard. It is easy + to stop this code working; hence the copious comments. */ + +static unsigned long long +real_mode_gdt_entries [3] = +{ + 0x0000000000000000ULL, /* Null descriptor */ + 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ + 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ +}; + +static struct +{ + unsigned short size __attribute__ ((packed)); + unsigned long long * base __attribute__ ((packed)); +} +real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, +real_mode_idt = { 0x3ff, 0 }; + +/* This is 16-bit protected mode code to disable paging and the cache, + switch to real mode and jump to the BIOS reset code. + + The instruction that switches to real mode by writing to CR0 must be + followed immediately by a far jump instruction, which set CS to a + valid value for real mode, and flushes the prefetch queue to avoid + running instructions that have already been decoded in protected + mode. + + Clears all the flags except ET, especially PG (paging), PE + (protected-mode enable) and TS (task switch for coprocessor state + save). Flushes the TLB after paging has been disabled. Sets CD and + NW, to disable the cache on a 486, and invalidates the cache. This + is more like the state of a 486 after reset. I don't know if + something else should be done for other chips. + + More could be done here to set up the registers as if a CPU reset had + occurred; hopefully real BIOSs don't assume much. */ + +static unsigned char real_mode_switch [] = +{ + 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ + 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ + 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ + 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ + 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ + 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ + 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ + 0x74, 0x02, /* jz f */ + 0x0f, 0x08, /* invd */ + 0x24, 0x10, /* f: andb $0x10,al */ + 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ +}; +static unsigned char jump_to_bios [] = +{ + 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ +}; + +static inline void kb_wait(void) +{ + int i; + + for (i=0; i<0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +/* + * Switch to real mode and then execute the code + * specified by the code and length parameters. + * We assume that length will aways be less that 100! + */ +void machine_real_restart(unsigned char *code, int length) +{ + unsigned long flags; + + local_irq_disable(); + + /* Write zero to CMOS register number 0x0f, which the BIOS POST + routine will recognize as telling it to do a proper reboot. (Well + that's what this book in front of me says -- it may only apply to + the Phoenix BIOS though, it's not clear). At the same time, + disable NMIs by setting the top bit in the CMOS address register, + as we're about to do peculiar things to the CPU. I'm not sure if + `outb_p' is needed instead of just `outb'. Use it to be on the + safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) + */ + + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(0x00, 0x8f); + spin_unlock_irqrestore(&rtc_lock, flags); + + /* Remap the kernel at virtual address zero, as well as offset zero + from the kernel segment. This assumes the kernel segment starts at + virtual address PAGE_OFFSET. */ + + memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, + sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + + /* + * Use `swapper_pg_dir' as our page directory. + */ + load_cr3(swapper_pg_dir); + + /* Write 0x1234 to absolute memory location 0x472. The BIOS reads + this on booting to tell it to "Bypass memory test (also warm + boot)". This seems like a fairly standard thing that gets set by + REBOOT.COM programs, and the previous reset routine did this + too. */ + + *((unsigned short *)0x472) = reboot_mode; + + /* For the switch to real mode, copy some code to low memory. It has + to be in the first 64k because it is running in 16-bit mode, and it + has to have the same physical and virtual address, because it turns + off paging. Copy it near the end of the first page, out of the way + of BIOS variables. */ + + memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), + real_mode_switch, sizeof (real_mode_switch)); + memcpy ((void *) (0x1000 - 100), code, length); + + /* Set up the IDT for real mode. */ + + __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); + + /* Set up a GDT from which we can load segment descriptors for real + mode. The GDT is not used in real mode; it is just needed here to + prepare the descriptors. */ + + __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt)); + + /* Load the data segment registers, and thus the descriptors ready for + real mode. The base address of each segment is 0x100, 16 times the + selector value being loaded here. This is so that the segment + registers don't have to be reloaded after switching to real mode: + the values are consistent for real mode operation already. */ + + __asm__ __volatile__ ("movl $0x0010,%%eax\n" + "\tmovl %%eax,%%ds\n" + "\tmovl %%eax,%%es\n" + "\tmovl %%eax,%%fs\n" + "\tmovl %%eax,%%gs\n" + "\tmovl %%eax,%%ss" : : : "eax"); + + /* Jump to the 16-bit code that we copied earlier. It disables paging + and the cache, switches to real mode, and jumps to the BIOS reset + entry point. */ + + __asm__ __volatile__ ("ljmp $0x0008,%0" + : + : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); +} + +void machine_restart(char * __unused) +{ +#if CONFIG_SMP + int cpuid; + + cpuid = GET_APIC_ID(apic_read(APIC_ID)); + + if (reboot_smp) { + + /* check to see if reboot_cpu is valid + if its not, default to the BSP */ + if ((reboot_cpu == -1) || + (reboot_cpu > (NR_CPUS -1)) || + !(phys_cpu_present_map & (1< - -char visws_board_type = -1; -char visws_board_rev = -1; - -#define PIIX_PM_START 0x0F80 - -#define SIO_GPIO_START 0x0FC0 - -#define SIO_PM_START 0x0FC8 - -#define PMBASE PIIX_PM_START -#define GPIREG0 (PMBASE+0x30) -#define GPIREG(x) (GPIREG0+((x)/8)) -#define PIIX_GPI_BD_ID1 18 -#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1) - -#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8) - -#define SIO_INDEX 0x2e -#define SIO_DATA 0x2f - -#define SIO_DEV_SEL 0x7 -#define SIO_DEV_ENB 0x30 -#define SIO_DEV_MSB 0x60 -#define SIO_DEV_LSB 0x61 - -#define SIO_GP_DEV 0x7 - -#define SIO_GP_BASE SIO_GPIO_START -#define SIO_GP_MSB (SIO_GP_BASE>>8) -#define SIO_GP_LSB (SIO_GP_BASE&0xff) - -#define SIO_GP_DATA1 (SIO_GP_BASE+0) - -#define SIO_PM_DEV 0x8 - -#define SIO_PM_BASE SIO_PM_START -#define SIO_PM_MSB (SIO_PM_BASE>>8) -#define SIO_PM_LSB (SIO_PM_BASE&0xff) -#define SIO_PM_INDEX (SIO_PM_BASE+0) -#define SIO_PM_DATA (SIO_PM_BASE+1) - -#define SIO_PM_FER2 0x1 - -#define SIO_PM_GP_EN 0x80 - -void __init visws_get_board_type_and_rev(void) -{ - int raw; - - visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) - >> PIIX_GPI_BD_SHIFT; -/* - * Get Board rev. - * First, we have to initialize the 307 part to allow us access - * to the GPIO registers. Let's map them at 0x0fc0 which is right - * after the PIIX4 PM section. - */ - outb_p(SIO_DEV_SEL, SIO_INDEX); - outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */ - - outb_p(SIO_DEV_MSB, SIO_INDEX); - outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */ - - outb_p(SIO_DEV_LSB, SIO_INDEX); - outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */ - - outb_p(SIO_DEV_ENB, SIO_INDEX); - outb_p(1, SIO_DATA); /* Enable GPIO registers. */ - -/* - * Now, we have to map the power management section to write - * a bit which enables access to the GPIO registers. - * What lunatic came up with this shit? - */ - outb_p(SIO_DEV_SEL, SIO_INDEX); - outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */ - - outb_p(SIO_DEV_MSB, SIO_INDEX); - outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */ - - outb_p(SIO_DEV_LSB, SIO_INDEX); - outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */ - - outb_p(SIO_DEV_ENB, SIO_INDEX); - outb_p(1, SIO_DATA); /* Enable PM registers. */ - -/* - * Now, write the PM register which enables the GPIO registers. - */ - outb_p(SIO_PM_FER2, SIO_PM_INDEX); - outb_p(SIO_PM_GP_EN, SIO_PM_DATA); - -/* - * Now, initialize the GPIO registers. - * We want them all to be inputs which is the - * power on default, so let's leave them alone. - * So, let's just read the board rev! - */ - raw = inb_p(SIO_GP_DATA1); - raw &= 0x7f; /* 7 bits of valid board revision ID. */ - - if (visws_board_type == VISWS_320) { - if (raw < 0x6) { - visws_board_rev = 4; - } else if (raw < 0xc) { - visws_board_rev = 5; - } else { - visws_board_rev = 6; - } - } else if (visws_board_type == VISWS_540) { - visws_board_rev = 2; - } else { - visws_board_rev = raw; - } - - printk(KERN_INFO "Silicon Graphics %s (rev %d)\n", - visws_board_type == VISWS_320 ? "320" : - (visws_board_type == VISWS_540 ? "540" : - "unknown"), visws_board_rev); - } -} diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Fri Sep 20 08:20:46 2002 +++ b/arch/i386/kernel/setup.c Fri Sep 20 08:20:46 2002 @@ -37,6 +37,10 @@ #include #include #include +#include +#include "setup_arch_pre.h" + +static inline char * __init machine_specific_memory_setup(void); /* * Machine setup.. @@ -470,31 +474,8 @@ static void __init setup_memory_region(void) { - char *who = "BIOS-e820"; + char *who = machine_specific_memory_setup(); - /* - * Try to copy the BIOS-supplied E820-map. - * - * Otherwise fake a memory map; one section from 0k->640k, - * the next section from 1mb->appropriate_mem_k - */ - sanitize_e820_map(E820_MAP, &E820_MAP_NR); - if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { - unsigned long mem_size; - - /* compare results from other methods and take the greater */ - if (ALT_MEM_K < EXT_MEM_K) { - mem_size = EXT_MEM_K; - who = "BIOS-88"; - } else { - mem_size = ALT_MEM_K; - who = "BIOS-e801"; - } - - e820.nr_map = 0; - add_memory_region(0, LOWMEMSIZE(), E820_RAM); - add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); - } printk(KERN_INFO "BIOS-provided physical RAM map:\n"); print_memory_map(who); } /* setup_memory_region */ @@ -757,7 +738,7 @@ */ acpi_reserve_bootmem(); #endif -#ifdef CONFIG_X86_LOCAL_APIC +#ifdef CONFIG_X86_FIND_SMP_CONFIG /* * Find and reserve possible boot-time SMP configuration: */ @@ -838,12 +819,9 @@ { unsigned long max_low_pfn; + pre_setup_arch_hook(); early_cpu_init(); -#ifdef CONFIG_VISWS - visws_get_board_type_and_rev(); -#endif - ROOT_DEV = ORIG_ROOT_DEV; drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; @@ -863,6 +841,7 @@ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif + ARCH_SETUP setup_memory_region(); if (!MOUNT_ROOT_RDONLY) @@ -922,6 +901,8 @@ } __setup("nohighio", highio_setup); + +#include "setup_arch_post.h" /* * Local Variables: * mode:c diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c --- a/arch/i386/kernel/smpboot.c Fri Sep 20 08:20:46 2002 +++ b/arch/i386/kernel/smpboot.c Fri Sep 20 08:20:46 2002 @@ -48,6 +48,9 @@ #include #include #include +#include +#include +#include "smpboot_hooks.h" /* Set if we find a B stepping CPU */ static int __initdata smp_b_stepping; @@ -1003,9 +1006,7 @@ */ if (!smp_found_config) { printk(KERN_NOTICE "SMP motherboard not detected.\n"); -#ifndef CONFIG_VISWS - io_apic_irqs = 0; -#endif + smpboot_clear_io_apic_irqs(); phys_cpu_present_map = 1; if (APIC_init_uniprocessor()) printk(KERN_NOTICE "Local APIC not detected." @@ -1032,9 +1033,7 @@ printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", boot_cpu_physical_apicid); printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); -#ifndef CONFIG_VISWS - io_apic_irqs = 0; -#endif + smpboot_clear_io_apic_irqs(); phys_cpu_present_map = 1; return; } @@ -1047,9 +1046,7 @@ if (!max_cpus) { smp_found_config = 0; printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); -#ifndef CONFIG_VISWS - io_apic_irqs = 0; -#endif + smpboot_clear_io_apic_irqs(); phys_cpu_present_map = 1; return; } @@ -1106,22 +1103,7 @@ /* * Cleanup possible dangling ends... */ -#ifndef CONFIG_VISWS - { - /* - * Install writable page 0 entry to set BIOS data area. - */ - local_flush_tlb(); - - /* - * Paranoid: Set warm reset code and vector here back - * to default values. - */ - CMOS_WRITE(0, 0xf); - - *((volatile long *) phys_to_virt(0x467)) = 0; - } -#endif + smpboot_setup_warm_reset_vector(); /* * Allow the user to impress friends. @@ -1173,15 +1155,8 @@ } } } - -#ifndef CONFIG_VISWS - /* - * Here we can be sure that there is an IO-APIC in the system. Let's - * go and set it up: - */ - if (!skip_ioapic_setup && nr_ioapics) - setup_IO_APIC(); -#endif + + smpboot_setup_io_apic(); setup_boot_APIC_clock(); @@ -1219,4 +1194,30 @@ void __init smp_cpus_done(unsigned int max_cpus) { zap_low_mappings(); +} + +void __init smp_intr_init() +{ + /* + * IRQ0 must be given a fixed assignment and initialized, + * because it's used before the IO-APIC is set up. + */ + set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]); + + /* + * The reschedule interrupt is a CPU-to-CPU reschedule-helper + * IPI, driven by wakeup. + */ + set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); + + /* IPI for invalidation */ + set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); + + /* IPI for generic function call */ + set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); + + /* thermal monitor LVT interrupt */ +#ifdef CONFIG_X86_MCE_P4THERMAL + set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); +#endif } diff -Nru a/arch/i386/kernel/suspend.c b/arch/i386/kernel/suspend.c --- a/arch/i386/kernel/suspend.c Fri Sep 20 08:20:47 2002 +++ b/arch/i386/kernel/suspend.c Fri Sep 20 08:20:47 2002 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c --- a/arch/i386/kernel/time.c Fri Sep 20 08:20:46 2002 +++ b/arch/i386/kernel/time.c Fri Sep 20 08:20:46 2002 @@ -57,8 +57,11 @@ #include #include -#include -#include +#include + +extern spinlock_t i8259A_lock; + +#include "do_timer.h" /* * for x86_do_profile() @@ -120,8 +123,6 @@ spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; EXPORT_SYMBOL(i8253_lock); -extern spinlock_t i8259A_lock; - #ifndef CONFIG_X86_TSC /* This function must be called with interrupts disabled @@ -202,47 +203,11 @@ * (see c't 95/10 page 335 for Neptun bug.) */ -/* you can safely undefine this if you don't have the Neptune chipset */ - -#define BUGGY_NEPTUN_TIMER if( jiffies_t == jiffies_p ) { if( count > count_p ) { /* the nutcase */ - - int i; - - spin_lock(&i8259A_lock); - /* - * This is tricky when I/O APICs are used; - * see do_timer_interrupt(). - */ - i = inb(0x20); - spin_unlock(&i8259A_lock); - - /* assumption about timer being IRQ0 */ - if (i & 0x01) { - /* - * We cannot detect lost timer interrupts ... - * well, that's why we call them lost, don't we? :) - * [hmm, on the Pentium and Alpha we can ... sort of] - */ - count -= LATCH; - } else { -#ifdef BUGGY_NEPTUN_TIMER - /* - * for the Neptun bug we know that the 'latch' - * command doesnt latch the high and low value - * of the counter atomically. Thus we have to - * substract 256 from the counter - * ... funny, isnt it? :) - */ - - count -= 256; -#else - printk("do_slow_gettimeoffset(): hardware timer problem?\n"); -#endif - } + count = do_timer_overflow(count); } } else jiffies_p = jiffies_t; @@ -413,23 +378,7 @@ } #endif -#ifdef CONFIG_VISWS - /* Clear the interrupt */ - co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR); -#endif - do_timer(regs); -/* - * In the SMP case we use the local APIC timer interrupt to do the - * profiling, except when we simulate SMP mode on a uniprocessor - * system, in that case we have to call the local interrupt handler. - */ -#ifndef CONFIG_X86_LOCAL_APIC - if (!user_mode(regs)) - x86_do_profile(regs->eip); -#else - if (!using_apic_timer) - smp_local_timer_interrupt(regs); -#endif + do_timer_interrupt_hook(regs); /* * If we have an externally synchronized Linux clock, then update @@ -470,7 +419,7 @@ * Time Stamp Counter value at the time of the timer interrupt, so that * we later on can estimate the time of day more exactly. */ -static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int count; @@ -560,8 +509,6 @@ return mktime(year, mon, day, hour, min, sec); } -static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; - /* ------ Calibrate the TSC ------- * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). * Too much 64-bit arithmetic here to do this cleanly in C, and for @@ -574,6 +521,7 @@ #define CALIBRATE_LATCH (5 * LATCH) #define CALIBRATE_TIME (5 * 1000020/HZ) +#ifdef CONFIG_X86_TSC static unsigned long __init calibrate_tsc(void) { /* Set the Gate high, disable speaker */ @@ -638,6 +586,7 @@ bad_ctc: return 0; } +#endif /* CONFIG_X86_TSC */ static struct device device_i8253 = { .name = "i8253", @@ -653,7 +602,9 @@ void __init time_init(void) { +#ifdef CONFIG_X86_TSC extern int x86_udelay_tsc; +#endif xtime.tv_sec = get_cmos_time(); xtime.tv_nsec = 0; @@ -672,6 +623,7 @@ * to disk; this won't break the kernel, though, 'cuz we're * smart. See arch/i386/kernel/apm.c. */ +#ifdef CONFIG_X86_TSC /* * Firstly we have to do a CPU check for chips with * a potentially buggy TSC. At this point we haven't run @@ -712,22 +664,7 @@ } } } +#endif /* CONFIG_X86_TSC */ -#ifdef CONFIG_VISWS - printk("Starting Cobalt Timer system clock\n"); - - /* Set the countdown value */ - co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ); - - /* Start the timer */ - co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN); - - /* Enable (unmask) the timer interrupt */ - co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); - - /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ - setup_irq(CO_IRQ_TIMER, &irq0); -#else - setup_irq(0, &irq0); -#endif + time_init_hook(); } diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Fri Sep 20 08:20:43 2002 +++ b/arch/i386/kernel/traps.c Fri Sep 20 08:20:43 2002 @@ -43,12 +43,7 @@ #include #include - -#ifdef CONFIG_X86_VISWS_APIC -#include -#include -#include -#endif +#include #include #include @@ -840,96 +835,6 @@ _set_gate(a,12,3,addr); } -#ifdef CONFIG_X86_VISWS_APIC - -/* - * On Rev 005 motherboards legacy device interrupt lines are wired directly - * to Lithium from the 307. But the PROM leaves the interrupt type of each - * 307 logical device set appropriate for the 8259. Later we'll actually use - * the 8259, but for now we have to flip the interrupt types to - * level triggered, active lo as required by Lithium. - */ - -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ - -static void -superio_outb(int dev, int reg, int val) -{ - outb(DEV, REG); - outb(dev, VAL); - outb(reg, REG); - outb(val, VAL); -} - -static int __attribute__ ((unused)) -superio_inb(int dev, int reg) -{ - outb(DEV, REG); - outb(dev, VAL); - outb(reg, REG); - return inb(VAL); -} - -#define FLOP 3 /* floppy logical device */ -#define PPORT 4 /* parallel logical device */ -#define UART5 5 /* uart2 logical device (not wired up) */ -#define UART6 6 /* uart1 logical device (THIS is the serial port!) */ -#define IDEST 0x70 /* int. destination (which 307 IRQ line) reg. */ -#define ITYPE 0x71 /* interrupt type register */ - -/* interrupt type bits */ -#define LEVEL 0x01 /* bit 0, 0 == edge triggered */ -#define ACTHI 0x02 /* bit 1, 0 == active lo */ - -static void -superio_init(void) -{ - if (visws_board_type == VISWS_320 && visws_board_rev == 5) { - superio_outb(UART6, IDEST, 0); /* 0 means no intr propagated */ - printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n"); - } -} - -static void -lithium_init(void) -{ - set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS); - printk("Lithium PCI Bridge A, Bus Number: %d\n", - li_pcia_read16(LI_PCI_BUSNUM) & 0xff); - set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS); - printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n", - li_pcib_read16(LI_PCI_BUSNUM) & 0xff); - - /* XXX blindly enables all interrupts */ - li_pcia_write16(LI_PCI_INTEN, 0xffff); - li_pcib_write16(LI_PCI_INTEN, 0xffff); -} - -static void -cobalt_init(void) -{ - /* - * On normal SMP PC this is used only with SMP, but we have to - * use it and set it up here to start the Cobalt clock - */ - set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); - printk("Local APIC ID %lx\n", apic_read(APIC_ID)); - printk("Local APIC Version %lx\n", apic_read(APIC_LVR)); - - set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); - printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV)); - - set_fixmap(FIX_CO_APIC, CO_APIC_PHYS); - printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID)); - - /* Enable Cobalt APIC being careful to NOT change the ID! */ - co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE); - - printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID)); -} -#endif #ifdef CONFIG_EISA int EISA_bus; @@ -985,9 +890,5 @@ */ cpu_init(); -#ifdef CONFIG_X86_VISWS_APIC - superio_init(); - lithium_init(); - cobalt_init(); -#endif + trap_init_hook(); } diff -Nru a/arch/i386/kernel/visws_apic.c b/arch/i386/kernel/visws_apic.c --- a/arch/i386/kernel/visws_apic.c Fri Sep 20 08:20:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,410 +0,0 @@ -/* - * linux/arch/i386/kernel/visws_apic.c - * - * Copyright (C) 1999 Bent Hagemark, Ingo Molnar - * - * SGI Visual Workstation interrupt controller - * - * The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC - * which serves as the main interrupt controller in the system. Non-legacy - * hardware in the system uses this controller directly. Legacy devices - * are connected to the PIIX4 which in turn has its 8259(s) connected to - * a of the Cobalt APIC entry. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -/* - * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt - * -- not the manner expected by the normal 8259 code in irq.c. - * - * there is a 'master' physical interrupt source that gets sent to - * the CPU. But in the chipset there are various 'virtual' interrupts - * waiting to be handled. We represent this to Linux through a 'master' - * interrupt controller type, and through a special virtual interrupt- - * controller. Device drivers only see the virtual interrupt sources. - */ - -#define CO_IRQ_BASE 0x20 /* This is the 0x20 in init_IRQ()! */ - -static void startup_piix4_master_irq(unsigned int irq); -static void shutdown_piix4_master_irq(unsigned int irq); -static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs); -#define enable_piix4_master_irq startup_piix4_master_irq -#define disable_piix4_master_irq shutdown_piix4_master_irq - -static struct hw_interrupt_type piix4_master_irq_type = { - "PIIX4-master", - startup_piix4_master_irq, - shutdown_piix4_master_irq, - do_piix4_master_IRQ, - enable_piix4_master_irq, - disable_piix4_master_irq -}; - -static void enable_piix4_virtual_irq(unsigned int irq); -static void disable_piix4_virtual_irq(unsigned int irq); -#define startup_piix4_virtual_irq enable_piix4_virtual_irq -#define shutdown_piix4_virtual_irq disable_piix4_virtual_irq - -static struct hw_interrupt_type piix4_virtual_irq_type = { - "PIIX4-virtual", - startup_piix4_virtual_irq, - shutdown_piix4_virtual_irq, - 0, /* no handler, it's never called physically */ - enable_piix4_virtual_irq, - disable_piix4_virtual_irq -}; - -/* - * This is the SGI Cobalt (IO-)APIC: - */ - -static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs); -static void enable_cobalt_irq(unsigned int irq); -static void disable_cobalt_irq(unsigned int irq); -static void startup_cobalt_irq(unsigned int irq); -#define shutdown_cobalt_irq disable_cobalt_irq - -static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; - -static struct hw_interrupt_type cobalt_irq_type = { - "Cobalt-APIC", - startup_cobalt_irq, - shutdown_cobalt_irq, - do_cobalt_IRQ, - enable_cobalt_irq, - disable_cobalt_irq -}; - - -/* - * Not an __init, needed by the reboot code - */ -void disable_IO_APIC(void) -{ - /* Nop on Cobalt */ -} - -/* - * Cobalt (IO)-APIC functions to handle PCI devices. - */ - -static void disable_cobalt_irq(unsigned int irq) -{ - /* XXX undo the APIC entry here? */ - - /* - * definitely, we do not want to have IRQ storms from - * unused devices --mingo - */ -} - -static void enable_cobalt_irq(unsigned int irq) -{ -} - -/* - * Set the given Cobalt APIC Redirection Table entry to point - * to the given IDT vector/index. - */ -static void co_apic_set(int entry, int idtvec) -{ - co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (CO_IRQ_BASE+idtvec)); - co_apic_write(CO_APIC_HI(entry), 0); - - printk("Cobalt APIC Entry %d IDT Vector %d\n", entry, idtvec); -} - -/* - * "irq" really just serves to identify the device. Here is where we - * map this to the Cobalt APIC entry where it's physically wired. - * This is called via request_irq -> setup_x86_irq -> irq_desc->startup() - */ -static void startup_cobalt_irq(unsigned int irq) -{ - /* - * These "irq"'s are wired to the same Cobalt APIC entries - * for all (known) motherboard types/revs - */ - switch (irq) { - case CO_IRQ_TIMER: co_apic_set(CO_APIC_CPU, CO_IRQ_TIMER); - return; - - case CO_IRQ_ENET: co_apic_set(CO_APIC_ENET, CO_IRQ_ENET); - return; - - case CO_IRQ_SERIAL: return; /* XXX move to piix4-8259 "virtual" */ - - case CO_IRQ_8259: co_apic_set(CO_APIC_8259, CO_IRQ_8259); - return; - - case CO_IRQ_IDE: - switch (visws_board_type) { - case VISWS_320: - switch (visws_board_rev) { - case 5: - co_apic_set(CO_APIC_0_5_IDE0, CO_IRQ_IDE); - co_apic_set(CO_APIC_0_5_IDE1, CO_IRQ_IDE); - return; - case 6: - co_apic_set(CO_APIC_0_6_IDE0, CO_IRQ_IDE); - co_apic_set(CO_APIC_0_6_IDE1, CO_IRQ_IDE); - return; - } - case VISWS_540: - switch (visws_board_rev) { - case 2: - co_apic_set(CO_APIC_1_2_IDE0, CO_IRQ_IDE); - return; - } - } - break; - default: - panic("huh?"); - } -} - -/* - * This is the handle() op in do_IRQ() - */ -static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs) -{ - struct irqaction * action; - irq_desc_t *desc = irq_desc + irq; - - spin_lock(&irq_controller_lock); - { - unsigned int status; - /* XXX APIC EOI? */ - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - action = NULL; - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - action = desc->action; - status |= IRQ_INPROGRESS; - } - desc->status = status; - } - spin_unlock(&irq_controller_lock); - - /* Exit early if we had no action or it was disabled */ - if (!action) - return; - - handle_IRQ_event(irq, regs, action); - - (void)co_cpu_read(CO_CPU_REV); /* Sync driver ack to its h/w */ - apic_write(APIC_EOI, APIC_EIO_ACK); /* Send EOI to Cobalt APIC */ - - spin_lock(&irq_controller_lock); - { - unsigned int status = desc->status & ~IRQ_INPROGRESS; - desc->status = status; - if (!(status & IRQ_DISABLED)) - enable_cobalt_irq(irq); - } - spin_unlock(&irq_controller_lock); -} - -/* - * PIIX4-8259 master/virtual functions to handle: - * - * floppy - * parallel - * serial - * audio (?) - * - * None of these get Cobalt APIC entries, neither do they have IDT - * entries. These interrupts are purely virtual and distributed from - * the 'master' interrupt source: CO_IRQ_8259. - * - * When the 8259 interrupts its handler figures out which of these - * devices is interrupting and dispatches to it's handler. - * - * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/ - * enable_irq gets the right irq. This 'master' irq is never directly - * manipulated by any driver. - */ - -static void startup_piix4_master_irq(unsigned int irq) -{ - /* ICW1 */ - outb(0x11, 0x20); - outb(0x11, 0xa0); - - /* ICW2 */ - outb(0x08, 0x21); - outb(0x70, 0xa1); - - /* ICW3 */ - outb(0x04, 0x21); - outb(0x02, 0xa1); - - /* ICW4 */ - outb(0x01, 0x21); - outb(0x01, 0xa1); - - /* OCW1 - disable all interrupts in both 8259's */ - outb(0xff, 0x21); - outb(0xff, 0xa1); - - startup_cobalt_irq(irq); -} - -static void shutdown_piix4_master_irq(unsigned int irq) -{ - /* - * [we skip the 8259 magic here, not strictly necessary] - */ - - shutdown_cobalt_irq(irq); -} - -static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs) -{ - int realirq, mask; - - /* Find out what's interrupting in the PIIX4 8259 */ - - spin_lock(&irq_controller_lock); - outb(0x0c, 0x20); /* OCW3 Poll command */ - realirq = inb(0x20); - - if (!(realirq & 0x80)) { - /* - * Bit 7 == 0 means invalid/spurious - */ - goto out_unlock; - } - realirq &= 0x7f; - - /* - * mask and ack the 8259 - */ - mask = inb(0x21); - if ((mask >> realirq) & 0x01) - /* - * This IRQ is masked... ignore - */ - goto out_unlock; - - outb(mask | (1<status & IRQ_DISABLED)) - enable_piix4_virtual_irq(realirq); - } - spin_unlock(&irq_controller_lock); - return; - -out_unlock: - spin_unlock(&irq_controller_lock); - return; -} - -static void enable_piix4_virtual_irq(unsigned int irq) -{ - /* - * assumes this irq is one of the legacy devices - */ - - unsigned int mask = inb(0x21); - mask &= ~(1 << irq); - outb(mask, 0x21); - enable_cobalt_irq(irq); -} - -/* - * assumes this irq is one of the legacy devices - */ -static void disable_piix4_virtual_irq(unsigned int irq) -{ - unsigned int mask; - - disable_cobalt_irq(irq); - - mask = inb(0x21); - mask &= ~(1 << irq); - outb(mask, 0x21); -} - -static struct irqaction master_action = - { no_action, 0, 0, "PIIX4-8259", NULL, NULL }; - -void init_VISWS_APIC_irqs(void) -{ - int i; - - for (i = 0; i < 16; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; - irq_desc[i].depth = 1; - - /* - * Cobalt IRQs are mapped to standard ISA - * interrupt vectors: - */ - switch (i) { - /* - * Only CO_IRQ_8259 will be raised - * externally. - */ - case CO_IRQ_8259: - irq_desc[i].handler = &piix4_master_irq_type; - break; - case CO_IRQ_FLOPPY: - case CO_IRQ_PARLL: - irq_desc[i].handler = &piix4_virtual_irq_type; - break; - default: - irq_desc[i].handler = &cobalt_irq_type; - break; - } - } - - /* - * The master interrupt is always present: - */ - setup_x86_irq(CO_IRQ_8259, &master_action); -} - diff -Nru a/arch/i386/lib/checksum.S b/arch/i386/lib/checksum.S --- a/arch/i386/lib/checksum.S Fri Sep 20 08:20:44 2002 +++ b/arch/i386/lib/checksum.S Fri Sep 20 08:20:44 2002 @@ -55,8 +55,21 @@ movl 20(%esp),%eax # Function arg: unsigned int sum movl 16(%esp),%ecx # Function arg: int len movl 12(%esp),%esi # Function arg: unsigned char *buff - testl $2, %esi # Check alignment. + testl $3, %esi # Check alignment. jz 2f # Jump if alignment is ok. + testl $1, %esi # Check alignment. + jz 10f # Jump if alignment is boundary of 2bytes. + + # buf is odd + dec %ecx + jl 8f + movzbl (%esi), %ebx + adcl %ebx, %eax + roll $8, %eax + inc %esi + testl $2, %esi + jz 2f +10: subl $2, %ecx # Alignment uses up two bytes. jae 1f # Jump if we had at least two bytes. addl $2, %ecx # ecx was < 2. Deal with it. @@ -111,6 +124,10 @@ 6: addl %ecx,%eax adcl $0, %eax 7: + testl $1, 12(%esp) + jz 8f + roll $8, %eax +8: popl %ebx popl %esi ret @@ -126,8 +143,8 @@ movl 16(%esp),%ecx # Function arg: int len movl 12(%esp),%esi # Function arg: const unsigned char *buf - testl $2, %esi - jnz 30f + testl $3, %esi + jnz 25f 10: movl %ecx, %edx movl %ecx, %ebx @@ -145,6 +162,19 @@ lea 2(%esi), %esi adcl $0, %eax jmp 10b +25: + testl $1, %esi + jz 30f + # buf is odd + dec %ecx + jl 90f + movzbl (%esi), %ebx + addl %ebx, %eax + adcl $0, %eax + roll $8, %eax + inc %esi + testl $2, %esi + jz 10b 30: subl $2, %ecx ja 20b @@ -211,6 +241,10 @@ addl %ebx,%eax adcl $0,%eax 80: + testl $1, 12(%esp) + jz 90f + roll $8, %eax +90: popl %ebx popl %esi ret diff -Nru a/arch/i386/mach-generic/Makefile b/arch/i386/mach-generic/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/Makefile Fri Sep 20 08:20:49 2002 @@ -0,0 +1,15 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +EXTRA_CFLAGS += -I../kernel +export-objs := + +obj-y := setup.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/mach-generic/do_timer.h b/arch/i386/mach-generic/do_timer.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/do_timer.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,81 @@ +/* defines for inline arch setup functions */ + +/** + * do_timer_interrupt_hook - hook into timer tick + * @regs: standard registers from interrupt + * + * Description: + * This hook is called immediately after the timer interrupt is ack'd. + * It's primary purpose is to allow architectures that don't possess + * individual per CPU clocks (like the CPU APICs supply) to broadcast the + * timer interrupt as a means of triggering reschedules etc. + **/ + +static inline void do_timer_interrupt_hook(struct pt_regs *regs) +{ + do_timer(regs); +/* + * In the SMP case we use the local APIC timer interrupt to do the + * profiling, except when we simulate SMP mode on a uniprocessor + * system, in that case we have to call the local interrupt handler. + */ +#ifndef CONFIG_X86_LOCAL_APIC + if (!user_mode(regs)) + x86_do_profile(regs->eip); +#else + if (!using_apic_timer) + smp_local_timer_interrupt(regs); +#endif +} + + +/* you can safely undefine this if you don't have the Neptune chipset */ + +#define BUGGY_NEPTUN_TIMER + +/** + * do_timer_overflow - process a detected timer overflow condition + * @count: hardware timer interrupt count on overflow + * + * Description: + * This call is invoked when the jiffies count has not incremented but + * the hardware timer interrupt has. It means that a timer tick interrupt + * came along while the previous one was pending, thus a tick was missed + **/ +static inline int do_timer_overflow(int count) +{ + int i; + + spin_lock(&i8259A_lock); + /* + * This is tricky when I/O APICs are used; + * see do_timer_interrupt(). + */ + i = inb(0x20); + spin_unlock(&i8259A_lock); + + /* assumption about timer being IRQ0 */ + if (i & 0x01) { + /* + * We cannot detect lost timer interrupts ... + * well, that's why we call them lost, don't we? :) + * [hmm, on the Pentium and Alpha we can ... sort of] + */ + count -= LATCH; + } else { +#ifdef BUGGY_NEPTUN_TIMER + /* + * for the Neptun bug we know that the 'latch' + * command doesnt latch the high and low value + * of the counter atomically. Thus we have to + * substract 256 from the counter + * ... funny, isnt it? :) + */ + + count -= 256; +#else + printk("do_slow_gettimeoffset(): hardware timer problem?\n"); +#endif + } + return count; +} diff -Nru a/arch/i386/mach-generic/entry_arch.h b/arch/i386/mach-generic/entry_arch.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/entry_arch.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,34 @@ +/* + * This file is designed to contain the BUILD_INTERRUPT specifications for + * all of the extra named interrupt vectors used by the architecture. + * Usually this is the Inter Process Interrupts (IPIs) + */ + +/* + * The following vectors are part of the Linux architecture, there + * is no hardware IRQ pin equivalent for them, they are triggered + * through the ICC by us (IPIs) + */ +#ifdef CONFIG_X86_SMP +BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) +BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) +BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) +#endif + +/* + * every pentium local APIC has two 'local interrupts', with a + * soft-definable vector attached to both interrupts, one of + * which is a timer interrupt, the other one is error counter + * overflow. Linux uses the local APIC timer interrupt to get + * a much simpler SMP time architecture: + */ +#ifdef CONFIG_X86_LOCAL_APIC +BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) +BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) +BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) + +#ifdef CONFIG_X86_MCE_P4THERMAL +BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) +#endif + +#endif diff -Nru a/arch/i386/mach-generic/irq_vectors.h b/arch/i386/mach-generic/irq_vectors.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/irq_vectors.h Fri Sep 20 08:20:43 2002 @@ -0,0 +1,85 @@ +/* + * This file should contain #defines for all of the interrupt vector + * numbers used by this architecture. + * + * In addition, there are some standard defines: + * + * FIRST_EXTERNAL_VECTOR: + * The first free place for external interrupts + * + * SYSCALL_VECTOR: + * The IRQ vector a syscall makes the user to kernel transition + * under. + * + * TIMER_IRQ: + * The IRQ number the timer interrupt comes in at. + * + * NR_IRQS: + * The total number of interrupt vectors (including all the + * architecture specific interrupts) needed. + * + */ +#ifndef _ASM_IRQ_VECTORS_H +#define _ASM_IRQ_VECTORS_H + +/* + * IDT vectors usable for external interrupt sources start + * at 0x20: + */ +#define FIRST_EXTERNAL_VECTOR 0x20 + +#define SYSCALL_VECTOR 0x80 + +/* + * Vectors 0x20-0x2f are used for ISA interrupts. + */ + +/* + * Special IRQ vectors used by the SMP architecture, 0xf0-0xff + * + * some of the following vectors are 'rare', they are merged + * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical. + * + * Vectors 0xf0-0xfa are free (reserved for future Linux use). + */ +#define SPURIOUS_APIC_VECTOR 0xff +#define ERROR_APIC_VECTOR 0xfe +#define INVALIDATE_TLB_VECTOR 0xfd +#define RESCHEDULE_VECTOR 0xfc +#define CALL_FUNCTION_VECTOR 0xfb + +#define THERMAL_APIC_VECTOR 0xf0 +/* + * Local APIC timer IRQ vector is on a different priority level, + * to work around the 'lost local interrupt if more than 2 IRQ + * sources per level' errata. + */ +#define LOCAL_TIMER_VECTOR 0xef + +/* + * First APIC vector available to drivers: (vectors 0x30-0xee) + * we start at 0x31 to spread out vectors evenly between priority + * levels. (0x80 is the syscall vector) + */ +#define FIRST_DEVICE_VECTOR 0x31 +#define FIRST_SYSTEM_VECTOR 0xef + +#define TIMER_IRQ 0 + +/* + * 16 8259A IRQ's, 208 potential APIC interrupt sources. + * Right now the APIC is mostly only used for SMP. + * 256 vectors is an architectural limit. (we can have + * more than 256 devices theoretically, but they will + * have to use shared interrupts) + * Since vectors 0x00-0x1f are used/reserved for the CPU, + * the usable vector space is 0x20-0xff (224 vectors) + */ +#ifdef CONFIG_X86_IO_APIC +#define NR_IRQS 224 +#else +#define NR_IRQS 16 +#endif + +#endif /* _ASM_IRQ_VECTORS_H */ diff -Nru a/arch/i386/mach-generic/setup.c b/arch/i386/mach-generic/setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/setup.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,104 @@ +/* + * Machine specific setup for generic + */ + +#include +#include +#include +#include +#include +#include + +/** + * pre_intr_init_hook - initialisation prior to setting up interrupt vectors + * + * Description: + * Perform any necessary interrupt initialisation prior to setting up + * the "ordinary" interrupt call gates. For legacy reasons, the ISA + * interrupts should be initialised here if the machine emulates a PC + * in any way. + **/ +void __init pre_intr_init_hook(void) +{ + init_ISA_irqs(); +} + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; + +/** + * intr_init_hook - post gate setup interrupt initialisation + * + * Description: + * Fill in any interrupts that may have been left out by the general + * init_IRQ() routine. interrupts having to do with the machine rather + * than the devices on the I/O bus (like APIC interrupts in intel MP + * systems) are started here. + **/ +void __init intr_init_hook(void) +{ +#ifdef CONFIG_X86_LOCAL_APIC + apic_intr_init(); +#endif + + setup_irq(2, &irq2); +} + +/** + * pre_setup_arch_hook - hook called prior to any setup_arch() execution + * + * Description: + * generally used to activate any machine specific identification + * routines that may be needed before setup_arch() runs. On VISWS + * this is used to get the board revision and type. + **/ +void __init pre_setup_arch_hook(void) +{ +} + +/** + * trap_init_hook - initialise system specific traps + * + * Description: + * Called as the final act of trap_init(). Used in VISWS to initialise + * the various board specific APIC traps. + **/ +void __init trap_init_hook(void) +{ +} + +static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; + +/** + * time_init_hook - do any specific initialisations for the system timer. + * + * Description: + * Must plug the system timer interrupt source at HZ into the IRQ listed + * in irq_vectors.h:TIMER_IRQ + **/ +void __init time_init_hook(void) +{ + setup_irq(0, &irq0); +} + +#ifdef CONFIG_MCA +/** + * mca_nmi_hook - hook into MCA specific NMI chain + * + * Description: + * The MCA (Microchannel Arcitecture) has an NMI chain for NMI sources + * along the MCA bus. Use this to hook into that chain if you will need + * it. + **/ +void __init mca_nmi_hook(void) +{ + /* If I recall correctly, there's a whole bunch of other things that + * we can do to check for NMI problems, but that's all I know about + * at the moment. + */ + + printk("NMI generated from unknown source!\n"); +} +#endif diff -Nru a/arch/i386/mach-generic/setup_arch_post.h b/arch/i386/mach-generic/setup_arch_post.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/setup_arch_post.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,40 @@ +/** + * machine_specific_memory_setup - Hook for machine specific memory setup. + * + * Description: + * This is included late in kernel/setup.c so that it can make + * use of all of the static functions. + **/ + +static inline char * __init machine_specific_memory_setup(void) +{ + char *who; + + + who = "BIOS-e820"; + + /* + * Try to copy the BIOS-supplied E820-map. + * + * Otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ + sanitize_e820_map(E820_MAP, &E820_MAP_NR); + if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { + unsigned long mem_size; + + /* compare results from other methods and take the greater */ + if (ALT_MEM_K < EXT_MEM_K) { + mem_size = EXT_MEM_K; + who = "BIOS-88"; + } else { + mem_size = ALT_MEM_K; + who = "BIOS-e801"; + } + + e820.nr_map = 0; + add_memory_region(0, LOWMEMSIZE(), E820_RAM); + add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); + } + return who; +} diff -Nru a/arch/i386/mach-generic/setup_arch_pre.h b/arch/i386/mach-generic/setup_arch_pre.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/setup_arch_pre.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,5 @@ +/* Hook to call BIOS initialisation function */ + +/* no action for generic */ + +#define ARCH_SETUP diff -Nru a/arch/i386/mach-generic/smpboot_hooks.h b/arch/i386/mach-generic/smpboot_hooks.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/smpboot_hooks.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,33 @@ +/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws + * which needs to alter them. */ + +static inline void smpboot_clear_io_apic_irqs(void) +{ + io_apic_irqs = 0; +} + +static inline void smpboot_setup_warm_reset_vector(void) +{ + /* + * Install writable page 0 entry to set BIOS data area. + */ + local_flush_tlb(); + + /* + * Paranoid: Set warm reset code and vector here back + * to default values. + */ + CMOS_WRITE(0, 0xf); + + *((volatile long *) phys_to_virt(0x467)) = 0; +} + +static inline void smpboot_setup_io_apic(void) +{ + /* + * Here we can be sure that there is an IO-APIC in the system. Let's + * go and set it up: + */ + if (!skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); +} diff -Nru a/arch/i386/mach-visws/Makefile b/arch/i386/mach-visws/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/Makefile Fri Sep 20 08:20:49 2002 @@ -0,0 +1,25 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.o: + $(CC) $(AFLAGS) -traditional -c $< -o $*.o + +all: mach-visws.o + +O_TARGET := mach-visws.o +EXTRA_CFLAGS += -I../kernel +export-objs := + +obj-y := setup.o traps.o + +obj-$(CONFIG_PCI) += pci-visws.o +obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o +obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/mach-visws/do_timer.h b/arch/i386/mach-visws/do_timer.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/do_timer.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,50 @@ +/* defines for inline arch setup functions */ + +#include +#include + +static inline void do_timer_interrupt_hook(struct pt_regs *regs) +{ + /* Clear the interrupt */ + co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR); + + do_timer(regs); +/* + * In the SMP case we use the local APIC timer interrupt to do the + * profiling, except when we simulate SMP mode on a uniprocessor + * system, in that case we have to call the local interrupt handler. + */ +#ifndef CONFIG_X86_LOCAL_APIC + if (!user_mode(regs)) + x86_do_profile(regs->eip); +#else + if (!using_apic_timer) + smp_local_timer_interrupt(regs); +#endif +} + +static inline int do_timer_overflow(int count) +{ + int i; + + spin_lock(&i8259A_lock); + /* + * This is tricky when I/O APICs are used; + * see do_timer_interrupt(). + */ + i = inb(0x20); + spin_unlock(&i8259A_lock); + + /* assumption about timer being IRQ0 */ + if (i & 0x01) { + /* + * We cannot detect lost timer interrupts ... + * well, that's why we call them lost, don't we? :) + * [hmm, on the Pentium and Alpha we can ... sort of] + */ + count -= LATCH; + } else { + printk("do_slow_gettimeoffset(): hardware timer problem?\n"); + } + return count; +} diff -Nru a/arch/i386/mach-visws/entry_arch.h b/arch/i386/mach-visws/entry_arch.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/entry_arch.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,23 @@ +/* + * The following vectors are part of the Linux architecture, there + * is no hardware IRQ pin equivalent for them, they are triggered + * through the ICC by us (IPIs) + */ +#ifdef CONFIG_X86_SMP +BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) +BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) +BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) +#endif + +/* + * every pentium local APIC has two 'local interrupts', with a + * soft-definable vector attached to both interrupts, one of + * which is a timer interrupt, the other one is error counter + * overflow. Linux uses the local APIC timer interrupt to get + * a much simpler SMP time architecture: + */ +#ifdef CONFIG_X86_LOCAL_APIC +BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) +BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) +BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) +#endif diff -Nru a/arch/i386/mach-visws/irq_vectors.h b/arch/i386/mach-visws/irq_vectors.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/irq_vectors.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,64 @@ +#ifndef _ASM_IRQ_VECTORS_H +#define _ASM_IRQ_VECTORS_H + +/* + * IDT vectors usable for external interrupt sources start + * at 0x20: + */ +#define FIRST_EXTERNAL_VECTOR 0x20 + +#define SYSCALL_VECTOR 0x80 + +/* + * Vectors 0x20-0x2f are used for ISA interrupts. + */ + +/* + * Special IRQ vectors used by the SMP architecture, 0xf0-0xff + * + * some of the following vectors are 'rare', they are merged + * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical. + * + * Vectors 0xf0-0xfa are free (reserved for future Linux use). + */ +#define SPURIOUS_APIC_VECTOR 0xff +#define ERROR_APIC_VECTOR 0xfe +#define INVALIDATE_TLB_VECTOR 0xfd +#define RESCHEDULE_VECTOR 0xfc +#define CALL_FUNCTION_VECTOR 0xfb + +#define THERMAL_APIC_VECTOR 0xf0 +/* + * Local APIC timer IRQ vector is on a different priority level, + * to work around the 'lost local interrupt if more than 2 IRQ + * sources per level' errata. + */ +#define LOCAL_TIMER_VECTOR 0xef + +/* + * First APIC vector available to drivers: (vectors 0x30-0xee) + * we start at 0x31 to spread out vectors evenly between priority + * levels. (0x80 is the syscall vector) + */ +#define FIRST_DEVICE_VECTOR 0x31 +#define FIRST_SYSTEM_VECTOR 0xef + +#define TIMER_IRQ 0 + +/* + * 16 8259A IRQ's, 208 potential APIC interrupt sources. + * Right now the APIC is mostly only used for SMP. + * 256 vectors is an architectural limit. (we can have + * more than 256 devices theoretically, but they will + * have to use shared interrupts) + * Since vectors 0x00-0x1f are used/reserved for the CPU, + * the usable vector space is 0x20-0xff (224 vectors) + */ +#ifdef CONFIG_X86_IO_APIC +#define NR_IRQS 224 +#else +#define NR_IRQS 16 +#endif + +#endif /* _ASM_IRQ_VECTORS_H */ diff -Nru a/arch/i386/mach-visws/mpparse.c b/arch/i386/mach-visws/mpparse.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/mpparse.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Have we found an MP table */ +int smp_found_config; + +/* + * Various Linux-internal data structures created from the + * MP-table. + */ +int apic_version [MAX_APICS]; +int mp_bus_id_to_type [MAX_MP_BUSSES]; +int mp_bus_id_to_node [MAX_MP_BUSSES]; +int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; +int mp_current_pci_id; + +/* I/O APIC entries */ +struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; + +/* # of MP IRQ source entries */ +struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; + +/* MP IRQ source entries */ +int mp_irq_entries; + +int nr_ioapics; + +int pic_mode; +unsigned long mp_lapic_addr; + +/* Processor that is doing the boot up */ +unsigned int boot_cpu_physical_apicid = -1U; +unsigned int boot_cpu_logical_apicid = -1U; +/* Internal processor count */ +static unsigned int num_processors; + +/* Bitmask of physically existing CPUs */ +unsigned long phys_cpu_present_map; + +/* + * The Visual Workstation is Intel MP compliant in the hardware + * sense, but it doesn't have a BIOS(-configuration table). + * No problem for Linux. + */ +void __init find_smp_config(void) +{ + smp_found_config = 1; + + phys_cpu_present_map |= 2; /* or in id 1 */ + apic_version[1] |= 0x10; /* integrated APIC */ + apic_version[0] |= 0x10; + + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; +} + diff -Nru a/arch/i386/mach-visws/pci-visws.c b/arch/i386/mach-visws/pci-visws.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/pci-visws.c Fri Sep 20 08:20:47 2002 @@ -0,0 +1,141 @@ +/* + * Low-Level PCI Support for SGI Visual Workstation + * + * (c) 1999--2000 Martin Mares + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pci-i386.h" + +unsigned int pci_probe = 0; + +/* + * The VISWS uses configuration access type 1 only. + */ + +#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3)) + +static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + *value = inb(0xCFC + (where&3)); + return PCIBIOS_SUCCESSFUL; +} + +static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + *value = inw(0xCFC + (where&2)); + return PCIBIOS_SUCCESSFUL; +} + +static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + *value = inl(0xCFC); + return PCIBIOS_SUCCESSFUL; +} + +static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + outb(value, 0xCFC + (where&3)); + return PCIBIOS_SUCCESSFUL; +} + +static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + outw(value, 0xCFC + (where&2)); + return PCIBIOS_SUCCESSFUL; +} + +static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + outl(value, 0xCFC); + return PCIBIOS_SUCCESSFUL; +} + +#undef CONFIG_CMD + +static struct pci_ops visws_pci_ops = { + pci_conf1_read_config_byte, + pci_conf1_read_config_word, + pci_conf1_read_config_dword, + pci_conf1_write_config_byte, + pci_conf1_write_config_word, + pci_conf1_write_config_dword +}; + +static void __init pcibios_fixup_irqs(void) +{ + struct pci_dev *dev, *p; + u8 pin; + int irq; + + pci_for_each_dev(dev) { + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + dev->irq = 0; + if (!pin) + continue; + pin--; + if (dev->bus->parent) { + p = dev->bus->parent->self; + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + } else + p = dev; + irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1); + if (irq >= 0) + dev->irq = irq; + DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq); + } +} + +void __init pcibios_fixup_bus(struct pci_bus *b) +{ + pci_read_bridge_bases(b); +} + +#if 0 +static struct resource visws_pci_bus_resources[2] = { + { "Host bus 1", 0xf4000000, 0xf7ffffff, 0 }, + { "Host bus 2", 0xf0000000, 0xf3ffffff, 0 } +}; +#endif + +void __init pcibios_init(void) +{ + unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff; + + printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus); + pci_scan_bus(0, &visws_pci_ops, NULL); + pci_scan_bus(sec_bus, &visws_pci_ops, NULL); + pcibios_fixup_irqs(); + pcibios_resource_survey(); +} + +char * __init pcibios_setup(char *str) +{ + return str; +} + +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + return pcibios_enable_resources(dev, mask); +} + +void __init pcibios_penalize_isa_irq(irq) +{ +} diff -Nru a/arch/i386/mach-visws/setup.c b/arch/i386/mach-visws/setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/setup.c Fri Sep 20 08:20:43 2002 @@ -0,0 +1,170 @@ +/* + * Unmaintained SGI Visual Workstation support. + * Split out from setup.c by davej@suse.de + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +char visws_board_type = -1; +char visws_board_rev = -1; + +#define PIIX_PM_START 0x0F80 + +#define SIO_GPIO_START 0x0FC0 + +#define SIO_PM_START 0x0FC8 + +#define PMBASE PIIX_PM_START +#define GPIREG0 (PMBASE+0x30) +#define GPIREG(x) (GPIREG0+((x)/8)) +#define PIIX_GPI_BD_ID1 18 +#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1) + +#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8) + +#define SIO_INDEX 0x2e +#define SIO_DATA 0x2f + +#define SIO_DEV_SEL 0x7 +#define SIO_DEV_ENB 0x30 +#define SIO_DEV_MSB 0x60 +#define SIO_DEV_LSB 0x61 + +#define SIO_GP_DEV 0x7 + +#define SIO_GP_BASE SIO_GPIO_START +#define SIO_GP_MSB (SIO_GP_BASE>>8) +#define SIO_GP_LSB (SIO_GP_BASE&0xff) + +#define SIO_GP_DATA1 (SIO_GP_BASE+0) + +#define SIO_PM_DEV 0x8 + +#define SIO_PM_BASE SIO_PM_START +#define SIO_PM_MSB (SIO_PM_BASE>>8) +#define SIO_PM_LSB (SIO_PM_BASE&0xff) +#define SIO_PM_INDEX (SIO_PM_BASE+0) +#define SIO_PM_DATA (SIO_PM_BASE+1) + +#define SIO_PM_FER2 0x1 + +#define SIO_PM_GP_EN 0x80 + +void __init visws_get_board_type_and_rev(void) +{ + int raw; + + visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) + >> PIIX_GPI_BD_SHIFT; +/* + * Get Board rev. + * First, we have to initialize the 307 part to allow us access + * to the GPIO registers. Let's map them at 0x0fc0 which is right + * after the PIIX4 PM section. + */ + outb_p(SIO_DEV_SEL, SIO_INDEX); + outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */ + + outb_p(SIO_DEV_MSB, SIO_INDEX); + outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */ + + outb_p(SIO_DEV_LSB, SIO_INDEX); + outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */ + + outb_p(SIO_DEV_ENB, SIO_INDEX); + outb_p(1, SIO_DATA); /* Enable GPIO registers. */ + +/* + * Now, we have to map the power management section to write + * a bit which enables access to the GPIO registers. + * What lunatic came up with this shit? + */ + outb_p(SIO_DEV_SEL, SIO_INDEX); + outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */ + + outb_p(SIO_DEV_MSB, SIO_INDEX); + outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */ + + outb_p(SIO_DEV_LSB, SIO_INDEX); + outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */ + + outb_p(SIO_DEV_ENB, SIO_INDEX); + outb_p(1, SIO_DATA); /* Enable PM registers. */ + +/* + * Now, write the PM register which enables the GPIO registers. + */ + outb_p(SIO_PM_FER2, SIO_PM_INDEX); + outb_p(SIO_PM_GP_EN, SIO_PM_DATA); + +/* + * Now, initialize the GPIO registers. + * We want them all to be inputs which is the + * power on default, so let's leave them alone. + * So, let's just read the board rev! + */ + raw = inb_p(SIO_GP_DATA1); + raw &= 0x7f; /* 7 bits of valid board revision ID. */ + + if (visws_board_type == VISWS_320) { + if (raw < 0x6) { + visws_board_rev = 4; + } else if (raw < 0xc) { + visws_board_rev = 5; + } else { + visws_board_rev = 6; + } + } else if (visws_board_type == VISWS_540) { + visws_board_rev = 2; + } else { + visws_board_rev = raw; + } + + printk(KERN_INFO "Silicon Graphics %s (rev %d)\n", + visws_board_type == VISWS_320 ? "320" : + (visws_board_type == VISWS_540 ? "540" : + "unknown"), visws_board_rev); +} + +void __init pre_intr_init_hook(void) +{ + init_VISWS_APIC_irqs(); +} + +void __init intr_init_hook(void) +{ +#ifdef CONFIG_X86_LOCAL_APIC + apic_intr_init(); +#endif +} + +void __init pre_setup_arch_hook() +{ + visws_get_board_type_and_rev(); +} +static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; + +void __init time_init_hook(void) +{ + printk("Starting Cobalt Timer system clock\n"); + + /* Set the countdown value */ + co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ); + + /* Start the timer */ + co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN); + + /* Enable (unmask) the timer interrupt */ + co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); + + /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ + setup_irq(CO_IRQ_TIMER, &irq0); +} diff -Nru a/arch/i386/mach-visws/setup_arch_post.h b/arch/i386/mach-visws/setup_arch_post.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/setup_arch_post.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,37 @@ +/* Hook for machine specific memory setup. + * + * This is included late in kernel/setup.c so that it can make use of all of + * the static functions. */ + +static inline char * __init machine_specific_memory_setup(void) +{ + char *who; + + + who = "BIOS-e820"; + + /* + * Try to copy the BIOS-supplied E820-map. + * + * Otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ + sanitize_e820_map(E820_MAP, &E820_MAP_NR); + if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { + unsigned long mem_size; + + /* compare results from other methods and take the greater */ + if (ALT_MEM_K < EXT_MEM_K) { + mem_size = EXT_MEM_K; + who = "BIOS-88"; + } else { + mem_size = ALT_MEM_K; + who = "BIOS-e801"; + } + + e820.nr_map = 0; + add_memory_region(0, LOWMEMSIZE(), E820_RAM); + add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); + } + return who; +} diff -Nru a/arch/i386/mach-visws/setup_arch_pre.h b/arch/i386/mach-visws/setup_arch_pre.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/setup_arch_pre.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,5 @@ +/* Hook to call BIOS initialisation function */ + +/* no action for visws */ + +#define ARCH_SETUP diff -Nru a/arch/i386/mach-visws/smpboot_hooks.h b/arch/i386/mach-visws/smpboot_hooks.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/smpboot_hooks.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,13 @@ +/* for visws do nothing for any of these */ + +static inline void smpboot_clear_io_apic_irqs(void) +{ +} + +static inline void smpboot_setup_warm_reset_vector(void) +{ +} + +static inline void smpboot_setup_io_apic(void) +{ +} diff -Nru a/arch/i386/mach-visws/traps.c b/arch/i386/mach-visws/traps.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/traps.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,134 @@ +/* VISWS traps */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_X86_VISWS_APIC +#include +#include +#include +#endif + +#ifdef CONFIG_X86_VISWS_APIC + +/* + * On Rev 005 motherboards legacy device interrupt lines are wired directly + * to Lithium from the 307. But the PROM leaves the interrupt type of each + * 307 logical device set appropriate for the 8259. Later we'll actually use + * the 8259, but for now we have to flip the interrupt types to + * level triggered, active lo as required by Lithium. + */ + +#define REG 0x2e /* The register to read/write */ +#define DEV 0x07 /* Register: Logical device select */ +#define VAL 0x2f /* The value to read/write */ + +static void +superio_outb(int dev, int reg, int val) +{ + outb(DEV, REG); + outb(dev, VAL); + outb(reg, REG); + outb(val, VAL); +} + +static int __attribute__ ((unused)) +superio_inb(int dev, int reg) +{ + outb(DEV, REG); + outb(dev, VAL); + outb(reg, REG); + return inb(VAL); +} + +#define FLOP 3 /* floppy logical device */ +#define PPORT 4 /* parallel logical device */ +#define UART5 5 /* uart2 logical device (not wired up) */ +#define UART6 6 /* uart1 logical device (THIS is the serial port!) */ +#define IDEST 0x70 /* int. destination (which 307 IRQ line) reg. */ +#define ITYPE 0x71 /* interrupt type register */ + +/* interrupt type bits */ +#define LEVEL 0x01 /* bit 0, 0 == edge triggered */ +#define ACTHI 0x02 /* bit 1, 0 == active lo */ + +static __init void +superio_init(void) +{ + if (visws_board_type == VISWS_320 && visws_board_rev == 5) { + superio_outb(UART6, IDEST, 0); /* 0 means no intr propagated */ + printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n"); + } +} + +static __init void +lithium_init(void) +{ + set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS); + printk("Lithium PCI Bridge A, Bus Number: %d\n", + li_pcia_read16(LI_PCI_BUSNUM) & 0xff); + set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS); + printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n", + li_pcib_read16(LI_PCI_BUSNUM) & 0xff); + + /* XXX blindly enables all interrupts */ + li_pcia_write16(LI_PCI_INTEN, 0xffff); + li_pcib_write16(LI_PCI_INTEN, 0xffff); +} + +static __init void +cobalt_init(void) +{ + /* + * On normal SMP PC this is used only with SMP, but we have to + * use it and set it up here to start the Cobalt clock + */ + set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); + printk("Local APIC ID %lx\n", apic_read(APIC_ID)); + printk("Local APIC Version %lx\n", apic_read(APIC_LVR)); + + set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); + printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV)); + + set_fixmap(FIX_CO_APIC, CO_APIC_PHYS); + printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID)); + + /* Enable Cobalt APIC being careful to NOT change the ID! */ + co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE); + + printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID)); +} +#endif + +void __init trap_init_hook() +{ +#ifdef CONFIG_X86_VISWS_APIC + superio_init(); + lithium_init(); + cobalt_init(); +#endif +} diff -Nru a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/visws_apic.c Fri Sep 20 08:20:41 2002 @@ -0,0 +1,410 @@ +/* + * linux/arch/i386/kernel/visws_apic.c + * + * Copyright (C) 1999 Bent Hagemark, Ingo Molnar + * + * SGI Visual Workstation interrupt controller + * + * The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC + * which serves as the main interrupt controller in the system. Non-legacy + * hardware in the system uses this controller directly. Legacy devices + * are connected to the PIIX4 which in turn has its 8259(s) connected to + * a of the Cobalt APIC entry. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +/* + * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt + * -- not the manner expected by the normal 8259 code in irq.c. + * + * there is a 'master' physical interrupt source that gets sent to + * the CPU. But in the chipset there are various 'virtual' interrupts + * waiting to be handled. We represent this to Linux through a 'master' + * interrupt controller type, and through a special virtual interrupt- + * controller. Device drivers only see the virtual interrupt sources. + */ + +#define CO_IRQ_BASE 0x20 /* This is the 0x20 in init_IRQ()! */ + +static void startup_piix4_master_irq(unsigned int irq); +static void shutdown_piix4_master_irq(unsigned int irq); +static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs); +#define enable_piix4_master_irq startup_piix4_master_irq +#define disable_piix4_master_irq shutdown_piix4_master_irq + +static struct hw_interrupt_type piix4_master_irq_type = { + "PIIX4-master", + startup_piix4_master_irq, + shutdown_piix4_master_irq, + do_piix4_master_IRQ, + enable_piix4_master_irq, + disable_piix4_master_irq +}; + +static void enable_piix4_virtual_irq(unsigned int irq); +static void disable_piix4_virtual_irq(unsigned int irq); +#define startup_piix4_virtual_irq enable_piix4_virtual_irq +#define shutdown_piix4_virtual_irq disable_piix4_virtual_irq + +static struct hw_interrupt_type piix4_virtual_irq_type = { + "PIIX4-virtual", + startup_piix4_virtual_irq, + shutdown_piix4_virtual_irq, + 0, /* no handler, it's never called physically */ + enable_piix4_virtual_irq, + disable_piix4_virtual_irq +}; + +/* + * This is the SGI Cobalt (IO-)APIC: + */ + +static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs); +static void enable_cobalt_irq(unsigned int irq); +static void disable_cobalt_irq(unsigned int irq); +static void startup_cobalt_irq(unsigned int irq); +#define shutdown_cobalt_irq disable_cobalt_irq + +static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; + +static struct hw_interrupt_type cobalt_irq_type = { + "Cobalt-APIC", + startup_cobalt_irq, + shutdown_cobalt_irq, + do_cobalt_IRQ, + enable_cobalt_irq, + disable_cobalt_irq +}; + + +/* + * Not an __init, needed by the reboot code + */ +void disable_IO_APIC(void) +{ + /* Nop on Cobalt */ +} + +/* + * Cobalt (IO)-APIC functions to handle PCI devices. + */ + +static void disable_cobalt_irq(unsigned int irq) +{ + /* XXX undo the APIC entry here? */ + + /* + * definitely, we do not want to have IRQ storms from + * unused devices --mingo + */ +} + +static void enable_cobalt_irq(unsigned int irq) +{ +} + +/* + * Set the given Cobalt APIC Redirection Table entry to point + * to the given IDT vector/index. + */ +static void co_apic_set(int entry, int idtvec) +{ + co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (CO_IRQ_BASE+idtvec)); + co_apic_write(CO_APIC_HI(entry), 0); + + printk("Cobalt APIC Entry %d IDT Vector %d\n", entry, idtvec); +} + +/* + * "irq" really just serves to identify the device. Here is where we + * map this to the Cobalt APIC entry where it's physically wired. + * This is called via request_irq -> setup_x86_irq -> irq_desc->startup() + */ +static void startup_cobalt_irq(unsigned int irq) +{ + /* + * These "irq"'s are wired to the same Cobalt APIC entries + * for all (known) motherboard types/revs + */ + switch (irq) { + case CO_IRQ_TIMER: co_apic_set(CO_APIC_CPU, CO_IRQ_TIMER); + return; + + case CO_IRQ_ENET: co_apic_set(CO_APIC_ENET, CO_IRQ_ENET); + return; + + case CO_IRQ_SERIAL: return; /* XXX move to piix4-8259 "virtual" */ + + case CO_IRQ_8259: co_apic_set(CO_APIC_8259, CO_IRQ_8259); + return; + + case CO_IRQ_IDE: + switch (visws_board_type) { + case VISWS_320: + switch (visws_board_rev) { + case 5: + co_apic_set(CO_APIC_0_5_IDE0, CO_IRQ_IDE); + co_apic_set(CO_APIC_0_5_IDE1, CO_IRQ_IDE); + return; + case 6: + co_apic_set(CO_APIC_0_6_IDE0, CO_IRQ_IDE); + co_apic_set(CO_APIC_0_6_IDE1, CO_IRQ_IDE); + return; + } + case VISWS_540: + switch (visws_board_rev) { + case 2: + co_apic_set(CO_APIC_1_2_IDE0, CO_IRQ_IDE); + return; + } + } + break; + default: + panic("huh?"); + } +} + +/* + * This is the handle() op in do_IRQ() + */ +static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs) +{ + struct irqaction * action; + irq_desc_t *desc = irq_desc + irq; + + spin_lock(&irq_controller_lock); + { + unsigned int status; + /* XXX APIC EOI? */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status |= IRQ_INPROGRESS; + } + desc->status = status; + } + spin_unlock(&irq_controller_lock); + + /* Exit early if we had no action or it was disabled */ + if (!action) + return; + + handle_IRQ_event(irq, regs, action); + + (void)co_cpu_read(CO_CPU_REV); /* Sync driver ack to its h/w */ + apic_write(APIC_EOI, APIC_EIO_ACK); /* Send EOI to Cobalt APIC */ + + spin_lock(&irq_controller_lock); + { + unsigned int status = desc->status & ~IRQ_INPROGRESS; + desc->status = status; + if (!(status & IRQ_DISABLED)) + enable_cobalt_irq(irq); + } + spin_unlock(&irq_controller_lock); +} + +/* + * PIIX4-8259 master/virtual functions to handle: + * + * floppy + * parallel + * serial + * audio (?) + * + * None of these get Cobalt APIC entries, neither do they have IDT + * entries. These interrupts are purely virtual and distributed from + * the 'master' interrupt source: CO_IRQ_8259. + * + * When the 8259 interrupts its handler figures out which of these + * devices is interrupting and dispatches to it's handler. + * + * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/ + * enable_irq gets the right irq. This 'master' irq is never directly + * manipulated by any driver. + */ + +static void startup_piix4_master_irq(unsigned int irq) +{ + /* ICW1 */ + outb(0x11, 0x20); + outb(0x11, 0xa0); + + /* ICW2 */ + outb(0x08, 0x21); + outb(0x70, 0xa1); + + /* ICW3 */ + outb(0x04, 0x21); + outb(0x02, 0xa1); + + /* ICW4 */ + outb(0x01, 0x21); + outb(0x01, 0xa1); + + /* OCW1 - disable all interrupts in both 8259's */ + outb(0xff, 0x21); + outb(0xff, 0xa1); + + startup_cobalt_irq(irq); +} + +static void shutdown_piix4_master_irq(unsigned int irq) +{ + /* + * [we skip the 8259 magic here, not strictly necessary] + */ + + shutdown_cobalt_irq(irq); +} + +static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs) +{ + int realirq, mask; + + /* Find out what's interrupting in the PIIX4 8259 */ + + spin_lock(&irq_controller_lock); + outb(0x0c, 0x20); /* OCW3 Poll command */ + realirq = inb(0x20); + + if (!(realirq & 0x80)) { + /* + * Bit 7 == 0 means invalid/spurious + */ + goto out_unlock; + } + realirq &= 0x7f; + + /* + * mask and ack the 8259 + */ + mask = inb(0x21); + if ((mask >> realirq) & 0x01) + /* + * This IRQ is masked... ignore + */ + goto out_unlock; + + outb(mask | (1<status & IRQ_DISABLED)) + enable_piix4_virtual_irq(realirq); + } + spin_unlock(&irq_controller_lock); + return; + +out_unlock: + spin_unlock(&irq_controller_lock); + return; +} + +static void enable_piix4_virtual_irq(unsigned int irq) +{ + /* + * assumes this irq is one of the legacy devices + */ + + unsigned int mask = inb(0x21); + mask &= ~(1 << irq); + outb(mask, 0x21); + enable_cobalt_irq(irq); +} + +/* + * assumes this irq is one of the legacy devices + */ +static void disable_piix4_virtual_irq(unsigned int irq) +{ + unsigned int mask; + + disable_cobalt_irq(irq); + + mask = inb(0x21); + mask &= ~(1 << irq); + outb(mask, 0x21); +} + +static struct irqaction master_action = + { no_action, 0, 0, "PIIX4-8259", NULL, NULL }; + +void init_VISWS_APIC_irqs(void) +{ + int i; + + for (i = 0; i < 16; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + + /* + * Cobalt IRQs are mapped to standard ISA + * interrupt vectors: + */ + switch (i) { + /* + * Only CO_IRQ_8259 will be raised + * externally. + */ + case CO_IRQ_8259: + irq_desc[i].handler = &piix4_master_irq_type; + break; + case CO_IRQ_FLOPPY: + case CO_IRQ_PARLL: + irq_desc[i].handler = &piix4_virtual_irq_type; + break; + default: + irq_desc[i].handler = &cobalt_irq_type; + break; + } + } + + /* + * The master interrupt is always present: + */ + setup_x86_irq(CO_IRQ_8259, &master_action); +} + diff -Nru a/arch/i386/math-emu/Makefile b/arch/i386/math-emu/Makefile --- a/arch/i386/math-emu/Makefile Fri Sep 20 08:20:41 2002 +++ b/arch/i386/math-emu/Makefile Fri Sep 20 08:20:41 2002 @@ -2,8 +2,6 @@ # Makefile for wm-FPU-emu # -O_TARGET := math.o - #DEBUG = -DDEBUGGING DEBUG = PARANOID = -DPARANOID diff -Nru a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile --- a/arch/i386/mm/Makefile Fri Sep 20 08:20:43 2002 +++ b/arch/i386/mm/Makefile Fri Sep 20 08:20:43 2002 @@ -1,17 +1,11 @@ # # Makefile for the linux i386-specific parts of the memory manager. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now in the main makefile... -O_TARGET := mm.o +export-objs := pageattr.o -obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o +obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o obj-$(CONFIG_DISCONTIGMEM) += discontig.o -export-objs := pageattr.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c --- a/arch/i386/mm/discontig.c Fri Sep 20 08:20:46 2002 +++ b/arch/i386/mm/discontig.c Fri Sep 20 08:20:46 2002 @@ -275,20 +275,9 @@ void __init set_max_mapnr_init(void) { #ifdef CONFIG_HIGHMEM - unsigned long lmax_mapnr; - int nid; - - highmem_start_page = mem_map + NODE_DATA(0)->node_zones[ZONE_HIGHMEM].zone_start_mapnr; + highmem_start_page = NODE_DATA(0)->node_zones[ZONE_HIGHMEM].zone_mem_map; num_physpages = highend_pfn; - - for (nid = 0; nid < numnodes; nid++) { - lmax_mapnr = node_startnr(nid) + node_size(nid); - if (lmax_mapnr > max_mapnr) { - max_mapnr = lmax_mapnr; - } - } - #else - max_mapnr = num_physpages = max_low_pfn; + num_physpages = max_low_pfn; #endif } diff -Nru a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c --- a/arch/i386/mm/hugetlbpage.c Fri Sep 20 08:20:47 2002 +++ b/arch/i386/mm/hugetlbpage.c Fri Sep 20 08:20:47 2002 @@ -319,7 +319,7 @@ } if (i == MAX_ID) return NULL; - inode = kmalloc(sizeof (struct inode), GFP_KERNEL); + inode = kmalloc(sizeof (struct inode), GFP_ATOMIC); if (inode == NULL) return NULL; @@ -502,7 +502,7 @@ if (lcount > 0) { /* Increase the mem size. */ while (lcount--) { - page = alloc_pages(GFP_ATOMIC, HUGETLB_PAGE_ORDER); + page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER); if (page == NULL) break; map = page; diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c --- a/arch/i386/mm/init.c Fri Sep 20 08:20:43 2002 +++ b/arch/i386/mm/init.c Fri Sep 20 08:20:43 2002 @@ -440,8 +440,10 @@ int tmp; int bad_ppro; +#ifndef CONFIG_DISCONTIGMEM if (!mem_map) BUG(); +#endif bad_ppro = ppro_with_ram_bug(); @@ -471,7 +473,7 @@ printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), - max_mapnr << (PAGE_SHIFT-10), + num_physpages << (PAGE_SHIFT-10), codesize >> 10, reservedpages << (PAGE_SHIFT-10), datasize >> 10, @@ -504,7 +506,7 @@ /*Will make this kernel command line. */ INIT_LIST_HEAD(&htlbpage_freelist); for (i=0; i 0) { - page = pfn_to_page(pfn); - total++; - if (PageHighMem(page)) - highmem++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page) - 1; + for_each_pgdat(pgdat) { + for (i = 0; i < pgdat->node_size; ++i) { + page = pgdat->node_mem_map + i; + total++; + if (PageHighMem(page)) + highmem++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page) - 1; + } } printk("%d pages of RAM\n", total); printk("%d pages of HIGHMEM\n",highmem); diff -Nru a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile --- a/arch/i386/pci/Makefile Fri Sep 20 08:20:46 2002 +++ b/arch/i386/pci/Makefile Fri Sep 20 08:20:46 2002 @@ -1,11 +1,5 @@ -O_TARGET := pci.o - obj-y := i386.o -ifdef CONFIG_VISWS -obj-y += visws.o -else - obj-$(CONFIG_PCI_BIOS) += pcbios.o obj-$(CONFIG_PCI_DIRECT) += direct.o @@ -22,6 +16,5 @@ endif # CONFIG_MULTIQUAD obj-y += irq.o common.o -endif # CONFIG_VISWS include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c --- a/arch/i386/pci/acpi.c Fri Sep 20 08:20:47 2002 +++ b/arch/i386/pci/acpi.c Fri Sep 20 08:20:47 2002 @@ -11,7 +11,7 @@ if (!(pci_probe & PCI_NO_ACPI_ROUTING)) { if (!acpi_pci_irq_init()) { printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); - printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi'\n"); + printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi' or even 'acpi=off'\n"); pcibios_scanned++; pcibios_enable_irq = acpi_pci_irq_enable; } else diff -Nru a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c --- a/arch/i386/pci/visws.c Fri Sep 20 08:20:47 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,141 +0,0 @@ -/* - * Low-Level PCI Support for SGI Visual Workstation - * - * (c) 1999--2000 Martin Mares - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "pci-i386.h" - -unsigned int pci_probe = 0; - -/* - * The VISWS uses configuration access type 1 only. - */ - -#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3)) - -static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - *value = inb(0xCFC + (where&3)); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - *value = inw(0xCFC + (where&2)); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - *value = inl(0xCFC); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - outb(value, 0xCFC + (where&3)); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - outw(value, 0xCFC + (where&2)); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - outl(value, 0xCFC); - return PCIBIOS_SUCCESSFUL; -} - -#undef CONFIG_CMD - -static struct pci_ops visws_pci_ops = { - pci_conf1_read_config_byte, - pci_conf1_read_config_word, - pci_conf1_read_config_dword, - pci_conf1_write_config_byte, - pci_conf1_write_config_word, - pci_conf1_write_config_dword -}; - -static void __init pcibios_fixup_irqs(void) -{ - struct pci_dev *dev, *p; - u8 pin; - int irq; - - pci_for_each_dev(dev) { - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - dev->irq = 0; - if (!pin) - continue; - pin--; - if (dev->bus->parent) { - p = dev->bus->parent->self; - pin = (pin + PCI_SLOT(dev->devfn)) % 4; - } else - p = dev; - irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1); - if (irq >= 0) - dev->irq = irq; - DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq); - } -} - -void __init pcibios_fixup_bus(struct pci_bus *b) -{ - pci_read_bridge_bases(b); -} - -#if 0 -static struct resource visws_pci_bus_resources[2] = { - { "Host bus 1", 0xf4000000, 0xf7ffffff, 0 }, - { "Host bus 2", 0xf0000000, 0xf3ffffff, 0 } -}; -#endif - -void __init pcibios_init(void) -{ - unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff; - - printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus); - pci_scan_bus(0, &visws_pci_ops, NULL); - pci_scan_bus(sec_bus, &visws_pci_ops, NULL); - pcibios_fixup_irqs(); - pcibios_resource_survey(); -} - -char * __init pcibios_setup(char *str) -{ - return str; -} - -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - return pcibios_enable_resources(dev, mask); -} - -void __init pcibios_penalize_isa_irq(irq) -{ -} diff -Nru a/arch/m68k/vmlinux.lds.S b/arch/m68k/vmlinux.lds.S --- a/arch/m68k/vmlinux.lds.S Fri Sep 20 08:20:44 2002 +++ b/arch/m68k/vmlinux.lds.S Fri Sep 20 08:20:44 2002 @@ -4,4 +4,4 @@ #include "vmlinux-sun3.lds" #else #include "vmlinux-std.lds" -#endif \ No newline at end of file +#endif diff -Nru a/arch/mips/Makefile b/arch/mips/Makefile --- a/arch/mips/Makefile Fri Sep 20 08:20:41 2002 +++ b/arch/mips/Makefile Fri Sep 20 08:20:41 2002 @@ -112,7 +112,7 @@ ifdef CONFIG_DECSTATION CORE_FILES += arch/mips/dec/dec.o SUBDIRS += arch/mips/dec arch/mips/dec/prom -LIBS += arch/mips/dec/prom/rexlib.a +LIBS += arch/mips/dec/prom/lib.a LOADADDR += 0x80040000 endif @@ -134,20 +134,20 @@ ifdef CONFIG_MIPS_JAZZ CORE_FILES += arch/mips/jazz/jazz.o SUBDIRS += arch/mips/jazz arch/mips/arc -LIBS += arch/mips/arc/arclib.a +LIBS += arch/mips/arc/lib.a LOADADDR += 0x80080000 endif ifdef CONFIG_SNI_RM200_PCI CORE_FILES += arch/mips/sni/sni.o SUBDIRS += arch/mips/sni arch/mips/arc -LIBS += arch/mips/arc/arclib.a +LIBS += arch/mips/arc/lib.a LOADADDR += 0x80080000 endif ifdef CONFIG_SGI_IP22 CORE_FILES += arch/mips/sgi/kernel/ip22-kern.o -LIBS += arch/mips/arc/arclib.a +LIBS += arch/mips/arc/lib.a SUBDIRS += arch/mips/sgi/kernel arch/mips/arc # # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon, @@ -162,7 +162,7 @@ # ifdef CONFIG_BAGET_MIPS SUBDIRS += arch/mips/baget arch/mips/baget/prom -LIBS += arch/mips/baget/baget.a arch/mips/baget/prom/bagetlib.a +LIBS += arch/mips/baget/baget.a arch/mips/baget/prom/lib.a LOADADDR += 0x80001000 endif diff -Nru a/arch/mips/arc/Makefile b/arch/mips/arc/Makefile --- a/arch/mips/arc/Makefile Fri Sep 20 08:20:44 2002 +++ b/arch/mips/arc/Makefile Fri Sep 20 08:20:44 2002 @@ -2,13 +2,8 @@ # Makefile for the SGI arcs prom monitor library routines # under Linux. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now in the main makefile... -L_TARGET = arclib.a +L_TARGET = lib.a obj-y += console.o init.o memory.o tree.o env.o cmdline.o misc.o \ time.o file.o identify.o diff -Nru a/arch/mips/baget/prom/Makefile b/arch/mips/baget/prom/Makefile --- a/arch/mips/baget/prom/Makefile Fri Sep 20 08:20:47 2002 +++ b/arch/mips/baget/prom/Makefile Fri Sep 20 08:20:47 2002 @@ -1,13 +1,8 @@ # # Makefile for the Baget/MIPS prom emulator library routines. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now in the main makefile... -L_TARGET := bagetlib.a +L_TARGET := lib.a obj-y := init.o diff -Nru a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile --- a/arch/mips/dec/prom/Makefile Fri Sep 20 08:20:44 2002 +++ b/arch/mips/dec/prom/Makefile Fri Sep 20 08:20:44 2002 @@ -3,7 +3,7 @@ # under Linux. # -L_TARGET := rexlib.a +L_TARGET := lib.a obj-y := init.o memory.o cmdline.o identify.o locore.o diff -Nru a/arch/mips64/Makefile b/arch/mips64/Makefile --- a/arch/mips64/Makefile Fri Sep 20 08:20:43 2002 +++ b/arch/mips64/Makefile Fri Sep 20 08:20:43 2002 @@ -72,7 +72,7 @@ # Board-dependent options and extra files # ifdef CONFIG_SGI_IP22 -LIBS += arch/mips64/sgi-ip22/ip22.a arch/mips64/arc/arclib.a +LIBS += arch/mips64/sgi-ip22/lib.a arch/mips64/arc/lib.a SUBDIRS += arch/mips64/sgi-ip22 arch/mips64/arc # # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon, @@ -84,7 +84,7 @@ ifdef CONFIG_SGI_IP27 CORE_FILES += arch/mips64/sgi-ip27/ip27.o -LIBS += arch/mips64/arc/arclib.a +LIBS += arch/mips64/arc/lib.a SUBDIRS += arch/mips64/sgi-ip27 arch/mips64/arc # # Set LOADADDR to >= 0xc000000000300000 if you want to leave space for @@ -100,7 +100,7 @@ endif ifdef CONFIG_SGI_IP32 -LIBS += arch/mips64/sgi-ip32/ip32-kern.a arch/mips64/arc/arclib.a +LIBS += arch/mips64/sgi-ip32/ip32-kern.a arch/mips64/arc/lib.a SUBDIRS += arch/mips64/sgi-ip32 arch/mips64/arc # # Set LOADADDR to >= 0x????????? if you want to leave space for symmon, diff -Nru a/arch/mips64/arc/Makefile b/arch/mips64/arc/Makefile --- a/arch/mips64/arc/Makefile Fri Sep 20 08:20:48 2002 +++ b/arch/mips64/arc/Makefile Fri Sep 20 08:20:48 2002 @@ -2,7 +2,7 @@ # Makefile for the ARC prom monitor library routines under Linux. # -L_TARGET = arclib.a +L_TARGET = lib.a obj-y := console.o init.o identify.o tree.o env.o cmdline.o misc.o time.o \ file.o diff -Nru a/arch/mips64/sgi-ip22/Makefile b/arch/mips64/sgi-ip22/Makefile --- a/arch/mips64/sgi-ip22/Makefile Fri Sep 20 08:20:41 2002 +++ b/arch/mips64/sgi-ip22/Makefile Fri Sep 20 08:20:41 2002 @@ -5,7 +5,7 @@ EXTRA_AFLAGS := $(CFLAGS) -L_TARGET = ip22.a +L_TARGET = lib.a obj-y += ip22-berr.o ip22-mc.o ip22-sc.o ip22-hpc.o ip22-int.o ip22-rtc.o \ ip22-setup.o system.o ip22-timer.o ip22-irq.o ip22-reset.o time.o diff -Nru a/arch/mips64/sgi-ip27/ip27-memory.c b/arch/mips64/sgi-ip27/ip27-memory.c --- a/arch/mips64/sgi-ip27/ip27-memory.c Fri Sep 20 08:20:44 2002 +++ b/arch/mips64/sgi-ip27/ip27-memory.c Fri Sep 20 08:20:44 2002 @@ -254,10 +254,6 @@ zones_size[ZONE_DMA] = end_pfn + 1 - start_pfn; free_area_init_node(node, NODE_DATA(node), 0, zones_size, start_pfn, 0); - if ((PLAT_NODE_DATA_STARTNR(node) + - PLAT_NODE_DATA_SIZE(node)) > pagenr) - pagenr = PLAT_NODE_DATA_STARTNR(node) + - PLAT_NODE_DATA_SIZE(node); } } @@ -271,7 +267,6 @@ unsigned long codesize, datasize, initsize; int slot, numslots; struct page *pg, *pslot; - pfn_t pgnr; num_physpages = numpages; /* memory already sized by szmem */ max_mapnr = pagenr; /* already found during paging_init */ @@ -293,7 +288,6 @@ * We need to manually do the other slots. */ pg = NODE_DATA(nid)->node_mem_map + slot_getsize(nid, 0); - pgnr = PLAT_NODE_DATA_STARTNR(nid) + slot_getsize(nid, 0); numslots = node_getlastslot(nid); for (slot = 1; slot <= numslots; slot++) { pslot = NODE_DATA(nid)->node_mem_map + @@ -304,7 +298,7 @@ * free up the pages that hold the memmap entries. */ while (pg < pslot) { - pg++; pgnr++; + pg++; } /* @@ -312,8 +306,8 @@ */ pslot += slot_getsize(nid, slot); while (pg < pslot) { - if (!page_is_ram(pgnr)) - continue; + /* if (!page_is_ram(pgnr)) continue; */ + /* commented out until page_is_ram works */ ClearPageReserved(pg); atomic_set(&pg->count, 1); __free_page(pg); diff -Nru a/arch/ppc/8260_io/Makefile b/arch/ppc/8260_io/Makefile --- a/arch/ppc/8260_io/Makefile Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/8260_io/Makefile Fri Sep 20 08:20:47 2002 @@ -1,5 +1,3 @@ -# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:19 cort -# # # Makefile for the linux MPC8xx ppc-specific parts of comm processor # diff -Nru a/arch/ppc/8260_io/commproc.c b/arch/ppc/8260_io/commproc.c --- a/arch/ppc/8260_io/commproc.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/8260_io/commproc.c Fri Sep 20 08:20:41 2002 @@ -1,8 +1,4 @@ /* - * BK Id: SCCS/s.commproc.c 1.10 10/16/01 16:21:52 trini - */ - -/* * General Purpose functions for the global management of the * 8260 Communication Processor Module. * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) diff -Nru a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c --- a/arch/ppc/8260_io/enet.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/8260_io/enet.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.enet.c 1.9 09/14/01 18:01:16 trini - */ -/* * Ethernet driver for Motorola MPC8260. * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) * Copyright (c) 2000 MontaVista Software Inc. (source@mvista.com) diff -Nru a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c --- a/arch/ppc/8260_io/fcc_enet.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/8260_io/fcc_enet.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Fast Ethernet Controller (FCC) driver for Motorola MPC8260. * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net) * diff -Nru a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c --- a/arch/ppc/8260_io/uart.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/8260_io/uart.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * UART driver for MPC8260 CPM SCC or SMC * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) * Copyright (c) 2000 MontaVista Software, Inc. (source@mvista.com) diff -Nru a/arch/ppc/8xx_io/Makefile b/arch/ppc/8xx_io/Makefile --- a/arch/ppc/8xx_io/Makefile Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/8xx_io/Makefile Fri Sep 20 08:20:46 2002 @@ -1,5 +1,3 @@ -# BK Id: %F% %I% %G% %U% %#% -# # # Makefile for the linux MPC8xx ppc-specific parts of comm processor # diff -Nru a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c --- a/arch/ppc/8xx_io/commproc.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/8xx_io/commproc.c Fri Sep 20 08:20:46 2002 @@ -1,8 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ - -/* * General Purpose functions for the global management of the * Communication Processor Module. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) diff -Nru a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c --- a/arch/ppc/8xx_io/enet.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/8xx_io/enet.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Ethernet driver for Motorola MPC8xx. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * diff -Nru a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c --- a/arch/ppc/8xx_io/fec.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/8xx_io/fec.c Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * diff -Nru a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c --- a/arch/ppc/8xx_io/uart.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/8xx_io/uart.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * UART driver for MPC860 CPM SCC or SMC * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile --- a/arch/ppc/Makefile Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/Makefile Fri Sep 20 08:20:41 2002 @@ -1,5 +1,3 @@ -# BK Id: %F% %I% %G% %U% %#% -# # This file is included by the global makefile so that you can add your own # architecture-specific flags and dependencies. Remember to do have actions # for "archclean" and "archdep" for cleaning up and making dependencies for @@ -24,9 +22,8 @@ LDFLAGS_vmlinux = -Ttext $(KERNELLOAD) -Bstatic CPPFLAGS := $(CPPFLAGS) -I$(TOPDIR)/arch/$(ARCH) AFLAGS := $(AFLAGS) -I$(TOPDIR)/arch/$(ARCH) -CFLAGS := $(CFLAGS) -I$(TOPDIR)/arch/$(ARCH) -fsigned-char \ - -msoft-float -pipe -ffixed-r2 -Wno-uninitialized \ - -mmultiple -mstring +CFLAGS := $(CFLAGS) -I$(TOPDIR)/arch/$(ARCH) -msoft-float -pipe \ + -ffixed-r2 -Wno-uninitialized -mmultiple -mstring CPP = $(CC) -E $(CFLAGS) ifdef CONFIG_4xx @@ -99,6 +96,8 @@ endif BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd pImage vmlinux.sm + +AFLAGS_vmlinux.lds.o := -Upowerpc # All the instructions talk about "make bzImage". bzImage: zImage diff -Nru a/arch/ppc/amiga/Makefile b/arch/ppc/amiga/Makefile --- a/arch/ppc/amiga/Makefile Fri Sep 20 08:20:45 2002 +++ b/arch/ppc/amiga/Makefile Fri Sep 20 08:20:45 2002 @@ -1,5 +1,3 @@ -# BK Id: %F% %I% %G% %U% %#% -# # # Makefile for Linux arch/m68k/amiga source directory # diff -Nru a/arch/ppc/amiga/amiga_ksyms.c b/arch/ppc/amiga/amiga_ksyms.c --- a/arch/ppc/amiga/amiga_ksyms.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/amiga/amiga_ksyms.c Fri Sep 20 08:20:41 2002 @@ -1,4 +1 @@ -/* - * BK Id: SCCS/s.amiga_ksyms.c 1.5 05/17/01 18:14:20 cort - */ #include "../../m68k/amiga/amiga_ksyms.c" diff -Nru a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c --- a/arch/ppc/amiga/amiints.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/amiga/amiints.c Fri Sep 20 08:20:41 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code + * arch/ppc/amiga/amiints.c -- Amiga Linux interrupt handling code * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive diff -Nru a/arch/ppc/amiga/amisound.c b/arch/ppc/amiga/amisound.c --- a/arch/ppc/amiga/amisound.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/amiga/amisound.c Fri Sep 20 08:20:47 2002 @@ -1,4 +1 @@ -/* - * BK Id: SCCS/s.amisound.c 1.5 05/17/01 18:14:20 cort - */ #include "../../m68k/amiga/amisound.c" diff -Nru a/arch/ppc/amiga/bootinfo.c b/arch/ppc/amiga/bootinfo.c --- a/arch/ppc/amiga/bootinfo.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/amiga/bootinfo.c Fri Sep 20 08:20:47 2002 @@ -1,8 +1,5 @@ /* - * BK Id: SCCS/s.bootinfo.c 1.5 05/17/01 18:14:20 cort - */ -/* - * linux/arch/ppc/amiga/bootinfo.c + * arch/ppc/amiga/bootinfo.c * * Extracted from arch/m68k/kernel/setup.c. * Should be properly generalized and put somewhere else. diff -Nru a/arch/ppc/amiga/chipram.c b/arch/ppc/amiga/chipram.c --- a/arch/ppc/amiga/chipram.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/amiga/chipram.c Fri Sep 20 08:20:47 2002 @@ -1,4 +1 @@ -/* - * BK Id: SCCS/s.chipram.c 1.7 05/21/01 00:49:49 cort - */ #include "../../m68k/amiga/chipram.c" diff -Nru a/arch/ppc/amiga/cia.c b/arch/ppc/amiga/cia.c --- a/arch/ppc/amiga/cia.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/amiga/cia.c Fri Sep 20 08:20:43 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * linux/arch/m68k/amiga/cia.c - CIA support + * arch/ppc/amiga/cia.c - CIA support * * Copyright (C) 1996 Roman Zippel * diff -Nru a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c --- a/arch/ppc/amiga/config.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/amiga/config.c Fri Sep 20 08:20:47 2002 @@ -1,10 +1,7 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #define m68k_debug_device debug_device /* - * linux/arch/m68k/amiga/config.c + * arch/ppc/amiga/config.c * * Copyright (C) 1993 Hamish Macdonald * diff -Nru a/arch/ppc/amiga/ints.c b/arch/ppc/amiga/ints.c --- a/arch/ppc/amiga/ints.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/amiga/ints.c Fri Sep 20 08:20:41 2002 @@ -1,8 +1,5 @@ /* - * BK Id: SCCS/s.ints.c 1.5 05/17/01 18:14:20 cort - */ -/* - * linux/arch/ppc/amiga/ints.c + * arch/ppc/amiga/ints.c * * Linux/m68k general interrupt handling code from arch/m68k/kernel/ints.c * Needed to drive the m68k emulating IRQ hardware on the PowerUp boards. diff -Nru a/arch/ppc/amiga/pcmcia.c b/arch/ppc/amiga/pcmcia.c --- a/arch/ppc/amiga/pcmcia.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/amiga/pcmcia.c Fri Sep 20 08:20:44 2002 @@ -1,4 +1 @@ -/* - * BK Id: SCCS/s.pcmcia.c 1.5 05/17/01 18:14:20 cort - */ #include "../../m68k/amiga/pcmcia.c" diff -Nru a/arch/ppc/amiga/time.c b/arch/ppc/amiga/time.c --- a/arch/ppc/amiga/time.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/amiga/time.c Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.time.c 1.5 05/17/01 18:14:20 cort - */ #include /* CONFIG_HEARTBEAT */ #include #include diff -Nru a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile --- a/arch/ppc/boot/Makefile Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/boot/Makefile Fri Sep 20 08:20:47 2002 @@ -19,7 +19,7 @@ MKIMAGE := ./utils/mkimage.wrapper -lib/zlib.a: lib/zlib.c +lib/lib.a: lib/zlib.c $(MAKE) -C lib images/vmlinux.gz: $(TOPDIR)/vmlinux @@ -28,7 +28,7 @@ # Subdirs and tools needed for each. Assume we always need to go into # 'simple' unless told otherwise. subdir-y := lib common simple -subdir-$(CONFIG_ALL_PPC) := chrp pmac prep +subdir-$(CONFIG_ALL_PPC) := openfirmware prep tools-$(CONFIG_ALL_PPC) := addnote mknote hack-coff mkprep tools-$(CONFIG_PPLUS) := mkbugboot mkprep tools-$(CONFIG_4xx) := mktree @@ -47,6 +47,9 @@ # These are the subdirs we want to use BOOTDIRS = $(filter-out $(NONBOOT), $(subdir-y)) +makeof1275: + $(MAKE) -C of1275 + # This will make the tools we need. We do it like this to ensure that we use # HOSTCC. -- Tom maketools: @@ -55,7 +58,7 @@ # The targets all boards support for boot images. BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd -$(BOOT_TARGETS): vmapus lib/zlib.a images/vmlinux.gz maketools +$(BOOT_TARGETS): vmapus lib/lib.a images/vmlinux.gz makeof1275 maketools ifneq ($(BOOTDIRS),) for d in $(BOOTDIRS); do $(MAKE) -C $$d $@; done endif @@ -80,5 +83,6 @@ clean: $(MAKE) -C images clean $(MAKE) -C utils clean + $(MAKE) -C openfirmware clean include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/chrp/Makefile b/arch/ppc/boot/chrp/Makefile --- a/arch/ppc/boot/chrp/Makefile Fri Sep 20 08:20:47 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,69 +0,0 @@ -# BK Id: %F% %I% %G% %U% %#% -# -# Makefile for making ELF bootable images for booting on CHRP -# using Open Firmware. -# -# Geert Uytterhoeven September 1997 -# -# Based on coffboot by Paul Mackerras - -LD_ARGS = -T ../ld.script -Ttext 0x00400000 - -OBJS = ../common/crt0.o start.o main.o misc.o ../common/string.o image.o \ - ../common/ofcommon.o - -EXTRA_TARGETS := $(OBJS) -LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a - -# Utils -ADDNOTE = ../utils/addnote -PIGGYBACK = ../utils/piggyback - -ifeq ($(CONFIG_PPC64BRIDGE),y) -END += .64 -AFLAGS += -Wa,-mppc64bridge -endif -ifeq ($(CONFIG_SMP),y) -END += .smp -endif - -TFTPIMAGE=/tftpboot/zImage.chrp$(END) - -all: zImage - -znetboot: zImage - cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux$(END) - cp ../images/zImage.chrp $(TFTPIMAGE) - -znetboot.initrd: zImage.initrd - cp ../images/zImage.initrd.chrp $(TFTPIMAGE) - -floppy: zImage - mcopy zImage a:zImage - -image.o: ../images/vmlinux.gz ../common/dummy.o - $(OBJCOPY) ../common/dummy.o $@ \ - --add-section=.image=../images/vmlinux.gz \ - --set-section-flags=.image=contents,alloc,load,readonly,data -ifdef CONFIG_XMON - $(OBJCOPY) $@ $@ \ - --add-section=.sysmap=$(TOPDIR)/System.map \ - --set-section-flags=.sysmap=contents,alloc,load,readonly,data -endif - -zImage: $(OBJS) $(LIBS) $(ADDNOTE) - $(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) $(LIBS) - $(OBJCOPY) ../images/$@.chrp ../images/$@.chrp -R .comment -R .ramdisk - cp ../images/$@.chrp ../images/$@.chrp-rs6k - $(ADDNOTE) ../images/$@.chrp-rs6k - -zImage.initrd: $(OBJS) $(LIBS) $(ADDNOTE) ../images/ramdisk.image.gz - $(OBJCOPY) image.o image.o \ - --add-section=.ramdisk=../images/ramdisk.image.gz \ - --set-section-flags=.ramdisk=contents,alloc,load,readonly,data - $(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) $(LIBS) - $(OBJCOPY) ../images/$@.chrp ../images/$@.chrp -R .comment - cp ../images/$@.chrp ../images/$@.chrp-rs6k - $(ADDNOTE) ../images/$@.chrp-rs6k - -include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/chrp/main.c b/arch/ppc/boot/chrp/main.c --- a/arch/ppc/boot/chrp/main.c Fri Sep 20 08:20:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,106 +0,0 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * Copyright (C) Paul Mackerras 1997. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include "nonstdio.h" -#include -#include - -/* Passed from the linker */ -extern char __image_begin, __image_end; -extern char __ramdisk_begin[], __ramdisk_end; -extern char _start, _end; - -extern int getprop(void *, const char *, void *, int); -extern unsigned int heap_max; -extern void claim(unsigned int virt, unsigned int size, unsigned int align); -extern void *finddevice(const char *); -extern void flush_cache(void *, unsigned long); -extern void gunzip(void *, int, unsigned char *, int *); -extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach, - unsigned int progend); -extern void pause(void); - -char *avail_ram; -char *begin_avail, *end_avail; -char *avail_high; - -#define RAM_START 0x00000000 -#define RAM_END (64<<20) - -#define BOOT_START ((unsigned long)_start) -#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF) - -#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) -#define PROG_START 0x00010000 -#define PROG_SIZE 0x00400000 /* 4MB */ - -#define SCRATCH_SIZE (128 << 10) - -static char scratch[SCRATCH_SIZE]; /* 1MB of scratch space for gunzip */ - -typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int); - -void -chrpboot(int a1, int a2, void *prom) -{ - unsigned sa, len; - void *dst; - unsigned char *im; - unsigned int initrd_size, initrd_start; - - printf("chrpboot starting: loaded at 0x%p\n\r", &_start); - - initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); - if (initrd_size) { - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - claim(initrd_start, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", - initrd_start, (char *)(&__ramdisk_begin), initrd_size); - memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); - } else { - initrd_start = 0; - initrd_size = 0; - a2 = 0xdeadbeef; - } - - im = (char *)(&__image_begin); - len = (char *)(&__image_end) - (char *)(&__image_begin); - /* claim 4MB starting at PROG_START */ - claim(PROG_START, PROG_SIZE - PROG_START, 0); - dst = (void *) PROG_START; - if (im[0] == 0x1f && im[1] == 0x8b) { - avail_ram = scratch; - begin_avail = avail_high = avail_ram; - end_avail = scratch + sizeof(scratch); - printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); - gunzip(dst, 0x400000, im, &len); - printf("done %u bytes\n\r", len); - printf("%u bytes of heap consumed, max in use %u\n\r", - avail_high - begin_avail, heap_max); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_chrp, - (PROG_START + PROG_SIZE)); - - sa = PROG_START; - printf("start address = 0x%x\n\r", sa); - - (*(kernel_start_t)sa)(a1, a2, prom, initrd_start, initrd_size); - - printf("returned?\n\r"); - - pause(); -} diff -Nru a/arch/ppc/boot/chrp/misc.S b/arch/ppc/boot/chrp/misc.S --- a/arch/ppc/boot/chrp/misc.S Fri Sep 20 08:20:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,53 +0,0 @@ -/* - * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:16:59 cort - */ -/* - * Copyright (C) Paul Mackerras 1997. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - .text - -/* - * Use the BAT0 registers to map the 1st 8MB of RAM to 0x90000000. - */ - .globl setup_bats -setup_bats: - mfpvr 3 - rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */ - cmpi 0,3,1 - lis 4,0x9000 - bne 4f - ori 4,4,4 /* set up BAT registers for 601 */ - li 5,0x7f - b 5f -4: ori 4,4,0xff /* set up BAT registers for 604 */ - li 5,2 - mtdbatu 3,4 - mtdbatl 3,5 -5: mtibatu 3,4 - mtibatl 3,5 - isync - blr - -/* - * Flush the dcache and invalidate the icache for a range of addresses. - * - * flush_cache(addr, len) - */ - .global flush_cache -flush_cache: - addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ - rlwinm. 4,4,27,5,31 - mtctr 4 - beqlr -1: dcbf 0,3 - icbi 0,3 - addi 3,3,0x20 - bdnz 1b - sync - isync - blr diff -Nru a/arch/ppc/boot/chrp/start.c b/arch/ppc/boot/chrp/start.c --- a/arch/ppc/boot/chrp/start.c Fri Sep 20 08:20:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,311 +0,0 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * Copyright (C) Paul Mackerras 1997. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include - -int (*prom)(void *args); - -void *chosen_handle; -void *stdin; -void *stdout; -void *stderr; - -void exit(void); -void *finddevice(const char *name); -int getprop(void *phandle, const char *name, void *buf, int buflen); - -void printk(char *fmt, ...); - -extern void chrpboot(int a1, int a2, void *prom); -extern int strlen(const char *s); - -void -start(int a1, int a2, void *promptr) -{ - prom = promptr; - chosen_handle = finddevice("/chosen"); - if (chosen_handle == (void *) -1) - exit(); - if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) - exit(); - stderr = stdout; - if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) - exit(); - - chrpboot(a1, a2, promptr); - for (;;) - exit(); -} - -int -write(void *handle, void *ptr, int nb) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *ihandle; - void *addr; - int len; - int actual; - } args; - - args.service = "write"; - args.nargs = 3; - args.nret = 1; - args.ihandle = handle; - args.addr = ptr; - args.len = nb; - args.actual = -1; - prom(&args); - return args.actual; -} - -int -read(void *handle, void *ptr, int nb) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *ihandle; - void *addr; - int len; - int actual; - } args; - - args.service = "read"; - args.nargs = 3; - args.nret = 1; - args.ihandle = handle; - args.addr = ptr; - args.len = nb; - args.actual = -1; - (*prom)(&args); - return args.actual; -} - -void -exit(void) -{ - struct prom_args { - char *service; - } args; - - for (;;) { - args.service = "exit"; - (*prom)(&args); - } -} - -void -pause(void) -{ - struct prom_args { - char *service; - } args; - - args.service = "enter"; - (*prom)(&args); -} - -void * -finddevice(const char *name) -{ - struct prom_args { - char *service; - int nargs; - int nret; - const char *devspec; - void *phandle; - } args; - - args.service = "finddevice"; - args.nargs = 1; - args.nret = 1; - args.devspec = name; - args.phandle = (void *) -1; - (*prom)(&args); - return args.phandle; -} - -void * -claim(unsigned int virt, unsigned int size, unsigned int align) -{ - struct prom_args { - char *service; - int nargs; - int nret; - unsigned int virt; - unsigned int size; - unsigned int align; - void *ret; - } args; - - args.service = "claim"; - args.nargs = 3; - args.nret = 1; - args.virt = virt; - args.size = size; - args.align = align; - (*prom)(&args); - return args.ret; -} - -int -getprop(void *phandle, const char *name, void *buf, int buflen) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *phandle; - const char *name; - void *buf; - int buflen; - int size; - } args; - - args.service = "getprop"; - args.nargs = 4; - args.nret = 1; - args.phandle = phandle; - args.name = name; - args.buf = buf; - args.buflen = buflen; - args.size = -1; - (*prom)(&args); - return args.size; -} - -int -putc(int c, void *f) -{ - char ch = c; - - if (c == '\n') - putc('\r', f); - return write(f, &ch, 1) == 1? c: -1; -} - -int -putchar(int c) -{ - return putc(c, stdout); -} - -int -fputs(char *str, void *f) -{ - int n = strlen(str); - - return write(f, str, n) == n? 0: -1; -} - -int -readchar(void) -{ - char ch; - - for (;;) { - switch (read(stdin, &ch, 1)) { - case 1: - return ch; - case -1: - printk("read(stdin) returned -1\r\n"); - return -1; - } - } -} - -static char line[256]; -static char *lineptr; -static int lineleft; - -int -getchar(void) -{ - int c; - - if (lineleft == 0) { - lineptr = line; - for (;;) { - c = readchar(); - if (c == -1 || c == 4) - break; - if (c == '\r' || c == '\n') { - *lineptr++ = '\n'; - putchar('\n'); - break; - } - switch (c) { - case 0177: - case '\b': - if (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - case 'U' & 0x1F: - while (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - default: - if (lineptr >= &line[sizeof(line) - 1]) - putchar('\a'); - else { - putchar(c); - *lineptr++ = c; - } - } - } - lineleft = lineptr - line; - lineptr = line; - } - if (lineleft == 0) - return -1; - --lineleft; - return *lineptr++; -} - -extern int vsprintf(char *buf, const char *fmt, va_list args); -static char sprint_buf[1024]; - -void -printk(char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(sprint_buf, fmt, args); - va_end(args); - write(stdout, sprint_buf, n); -} - -int -printf(char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(sprint_buf, fmt, args); - va_end(args); - write(stdout, sprint_buf, n); - return n; -} diff -Nru a/arch/ppc/boot/common/cpc700_memory.c b/arch/ppc/boot/common/cpc700_memory.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/common/cpc700_memory.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,38 @@ +/* + * arch/ppc/boot/common/cpc700_memory.c + * + * Find memory based upon settings in the CPC700 bridge + * + * Author: Dan Cox + * + * Copyright 2001-2002 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include "cpc700.h" + +unsigned long +cpc700_get_mem_size(void) +{ + int i; + unsigned long len, amt; + + /* Start at MB1EA, since MB0EA will most likely be the ending address + for ROM space. */ + for(len = 0, i = CPC700_MB1EA; i <= CPC700_MB4EA; i+=4) { + amt = cpc700_read_memreg(i); + if (amt == 0) + break; + len = amt; + } + + return len; +} + + diff -Nru a/arch/ppc/boot/common/crt0.S b/arch/ppc/boot/common/crt0.S --- a/arch/ppc/boot/common/crt0.S Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/boot/common/crt0.S Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ /* Copyright (c) 1997 Paul Mackerras * Initial Power Macintosh COFF version. * Copyright (c) 1999 Grant Erickson diff -Nru a/arch/ppc/boot/common/dummy.c b/arch/ppc/boot/common/dummy.c --- a/arch/ppc/boot/common/dummy.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/boot/common/dummy.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ int main(void) { return 0; diff -Nru a/arch/ppc/boot/common/misc-simple.c b/arch/ppc/boot/common/misc-simple.c --- a/arch/ppc/boot/common/misc-simple.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/boot/common/misc-simple.c Fri Sep 20 08:20:47 2002 @@ -64,6 +64,7 @@ extern unsigned long start; extern int CRT_tstc(void); +extern unsigned long get_mem_size(void); extern unsigned long serial_init(int chan, void *ignored); extern void serial_close(unsigned long com_port); extern void gunzip(void *, int, unsigned char *, int *); @@ -75,10 +76,19 @@ int timer = 0; char *cp, ch; struct bi_record *rec, *birecs; + unsigned long TotalMemory = 0; serial_fixups(); com_port = serial_init(0, NULL); +#if defined(CONFIG_LOPEC) || defined(CONFIG_PAL4) + /* + * Call get_mem_size(), which is memory controller dependant, + * and we must have the correct file linked in here. + */ + TotalMemory = get_mem_size(); +#endif + /* assume the chunk below 8M is free */ end_avail = (char *)0x00800000; @@ -193,6 +203,13 @@ rec->tag = BI_FIRST; rec->size = sizeof(struct bi_record); rec = (struct bi_record *)((unsigned long)rec + rec->size); + + if ( TotalMemory ) { + rec->tag = BI_MEMSIZE; + rec->data[0] = TotalMemory; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } rec->tag = BI_CMD_LINE; memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); diff -Nru a/arch/ppc/boot/common/mpc10x_memory.c b/arch/ppc/boot/common/mpc10x_memory.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/common/mpc10x_memory.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,109 @@ +/* + * arch/ppc/boot/common/mpc10x_common.c + * + * A routine to find out how much memory the machine has. + * + * Based on: + * arch/ppc/kernel/mpc10x_common.c + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Copyright 2001-2002 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include "mpc10x.h" + +/* + * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs *** + */ + +/* + * PCI config space macros, similar to indirect_xxx and early_xxx macros. + * We assume bus 0. + */ +#define MPC10X_CFG_read(val, addr, type, op) *val = op((type)(addr)) +#define MPC10X_CFG_write(val, addr, type, op) op((type *)(addr), (val)) + +#define MPC10X_PCI_OP(rw, size, type, op, mask) \ +static void \ +mpc10x_##rw##_config_##size(unsigned int *cfg_addr, \ + unsigned int *cfg_data, int devfn, int offset, \ + type val) \ +{ \ + out_be32(cfg_addr, \ + ((offset & 0xfc) << 24) | (devfn << 16) \ + | (0 << 8) | 0x80); \ + MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op); \ + return; \ +} + +MPC10X_PCI_OP(read, byte, u8 *, in_8, 3) +MPC10X_PCI_OP(read, dword, u32 *, in_le32, 0) + +/* + * Read the memory controller registers to determine the amount of memory in + * the system. This assumes that the firmware has correctly set up the memory + * controller registers. On CONFIG_ALL_PPC, we know we are being called + * under a PReP memory map. On all other machines, we assume we are under + * a CHRP memory map. + */ +unsigned long +get_mem_size(void) +{ + unsigned int *config_addr, *config_data, val; + unsigned long start, end, total, offset; + int i; + unsigned char bank_enables; + +#ifdef CONFIG_ALL_PPC + config_addr = (unsigned int *)MPC10X_MAPA_CNFG_ADDR; + config_data = (unsigned int *)MPC10X_MAPA_CNFG_DATA; +#else + config_addr = (unsigned int *)MPC10X_MAPB_CNFG_ADDR; + config_data = (unsigned int *)MPC10X_MAPB_CNFG_DATA; +#endif + + mpc10x_read_config_byte(config_addr, config_data, PCI_DEVFN(0,0), + MPC10X_MCTLR_MEM_BANK_ENABLES, &bank_enables); + + total = 0; + + for (i = 0; i < 8; i++) { + if (bank_enables & (1 << i)) { + offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0); + mpc10x_read_config_dword(config_addr, config_data, + PCI_DEVFN(0,0), offset, &val); + start = (val >> ((i & 3) << 3)) & 0xff; + + offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0); + mpc10x_read_config_dword(config_addr, config_data, + PCI_DEVFN(0,0), offset, &val); + val = (val >> ((i & 3) << 3)) & 0x03; + start = (val << 28) | (start << 20); + + offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0); + mpc10x_read_config_dword(config_addr, config_data, + PCI_DEVFN(0,0), offset, &val); + end = (val >> ((i & 3) << 3)) & 0xff; + + offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0); + mpc10x_read_config_dword(config_addr, config_data, + PCI_DEVFN(0,0), offset, &val); + val = (val >> ((i & 3) << 3)) & 0x03; + end = (val << 28) | (end << 20) | 0xfffff; + + total += (end - start + 1); + } + } + + return total; +} diff -Nru a/arch/ppc/boot/common/ns16550.c b/arch/ppc/boot/common/ns16550.c --- a/arch/ppc/boot/common/ns16550.c Fri Sep 20 08:20:45 2002 +++ b/arch/ppc/boot/common/ns16550.c Fri Sep 20 08:20:45 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * COM1 NS16550 support */ diff -Nru a/arch/ppc/boot/common/ofcommon.c b/arch/ppc/boot/common/ofcommon.c --- a/arch/ppc/boot/common/ofcommon.c Fri Sep 20 08:20:45 2002 +++ b/arch/ppc/boot/common/ofcommon.c Fri Sep 20 08:20:45 2002 @@ -1,6 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - * * Copyright (C) Paul Mackerras 1997. * * This program is free software; you can redistribute it and/or diff -Nru a/arch/ppc/boot/common/string.S b/arch/ppc/boot/common/string.S --- a/arch/ppc/boot/common/string.S Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/boot/common/string.S Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.string.S 1.8 05/18/01 06:20:29 patch - */ -/* * String handling functions for PowerPC. * * Copyright (C) 1996 Paul Mackerras. diff -Nru a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S --- a/arch/ppc/boot/common/util.S Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/boot/common/util.S Fri Sep 20 08:20:48 2002 @@ -160,11 +160,6 @@ blt 2b 3: blr -.globl _put_MSR -_put_MSR: - mtmsr r3 - blr - .section ".relocate_code","xa" /* * Flush and enable instruction cache diff -Nru a/arch/ppc/boot/include/cpc700.h b/arch/ppc/boot/include/cpc700.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/include/cpc700.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,26 @@ + +#ifndef __PPC_BOOT_CPC700_H +#define __PPC_BOOT_CPC700_H + +#define CPC700_MEM_CFGADDR 0xff500008 +#define CPC700_MEM_CFGDATA 0xff50000c + +#define CPC700_MB0SA 0x38 +#define CPC700_MB0EA 0x58 +#define CPC700_MB1SA 0x3c +#define CPC700_MB1EA 0x5c +#define CPC700_MB2SA 0x40 +#define CPC700_MB2EA 0x60 +#define CPC700_MB3SA 0x44 +#define CPC700_MB3EA 0x64 +#define CPC700_MB4SA 0x48 +#define CPC700_MB4EA 0x68 + +static inline long +cpc700_read_memreg(int reg) +{ + out_be32((volatile unsigned int *) CPC700_MEM_CFGADDR, reg); + return in_be32((volatile unsigned int *) CPC700_MEM_CFGDATA); +} + +#endif diff -Nru a/arch/ppc/boot/include/mpc10x.h b/arch/ppc/boot/include/mpc10x.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/include/mpc10x.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,67 @@ +/* + * arch/ppc/boot/include/mpc10.h + * + * Common defines for the Motorola SPS MPC106/8240/107 Host bridge/Mem + * ctrl/EPIC/etc. + * + * Author: Tom Rini + * + * This is a heavily stripped down version of: + * include/asm-ppc/mpc10x.h + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Copyright 2001-2002 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __BOOT_MPC10X_H__ +#define __BOOT_MPC10X_H__ + +/* + * The values here don't completely map everything but should work in most + * cases. + * + * MAP A (PReP Map) + * Processor: 0x80000000 - 0x807fffff -> PCI I/O: 0x00000000 - 0x007fffff + * Processor: 0xc0000000 - 0xdfffffff -> PCI MEM: 0x00000000 - 0x1fffffff + * PCI MEM: 0x80000000 -> Processor System Memory: 0x00000000 + * EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB) + * + * MAP B (CHRP Map) + * Processor: 0xfe000000 - 0xfebfffff -> PCI I/O: 0x00000000 - 0x00bfffff + * Processor: 0x80000000 - 0xbfffffff -> PCI MEM: 0x80000000 - 0xbfffffff + * PCI MEM: 0x00000000 -> Processor System Memory: 0x00000000 + * EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB) + */ + +/* Define the type of map to use */ +#define MPC10X_MEM_MAP_A 1 +#define MPC10X_MEM_MAP_B 2 + +/* Map A (PReP Map) Defines */ +#define MPC10X_MAPA_CNFG_ADDR 0x80000cf8 +#define MPC10X_MAPA_CNFG_DATA 0x80000cfc + +/* Map B (CHRP Map) Defines */ +#define MPC10X_MAPB_CNFG_ADDR 0xfec00000 +#define MPC10X_MAPB_CNFG_DATA 0xfee00000 + +/* Define offsets for the memory controller registers in the config space */ +#define MPC10X_MCTLR_MEM_START_1 0x80 /* Banks 0-3 */ +#define MPC10X_MCTLR_MEM_START_2 0x84 /* Banks 4-7 */ +#define MPC10X_MCTLR_EXT_MEM_START_1 0x88 /* Banks 0-3 */ +#define MPC10X_MCTLR_EXT_MEM_START_2 0x8c /* Banks 4-7 */ + +#define MPC10X_MCTLR_MEM_END_1 0x90 /* Banks 0-3 */ +#define MPC10X_MCTLR_MEM_END_2i 0x94 /* Banks 4-7 */ +#define MPC10X_MCTLR_EXT_MEM_END_1 0x98 /* Banks 0-3 */ +#define MPC10X_MCTLR_EXT_MEM_END_2 0x9c /* Banks 4-7 */ + +#define MPC10X_MCTLR_MEM_BANK_ENABLES 0xa0 + +#endif /* __BOOT_MPC10X_H__ */ diff -Nru a/arch/ppc/boot/include/nonstdio.h b/arch/ppc/boot/include/nonstdio.h --- a/arch/ppc/boot/include/nonstdio.h Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/boot/include/nonstdio.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.nonstdio.h 1.9 07/25/01 18:13:07 trini - */ -/* * Copyright (C) Paul Mackerras 1997. * * This program is free software; you can redistribute it and/or diff -Nru a/arch/ppc/boot/include/of1275.h b/arch/ppc/boot/include/of1275.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/include/of1275.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,38 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +typedef void *prom_handle; +typedef void *ihandle; +typedef void *phandle; +typedef int (*prom_entry)(void *); + +#define OF_INVALID_HANDLE ((prom_handle)-1UL) + +extern prom_entry of_prom_entry; + +/* function declarations */ + +void * claim(unsigned int virt, unsigned int size, unsigned int align); +void enter(void); +void exit(void); +phandle finddevice(const char *name); +int getprop(phandle node, const char *name, void *buf, int buflen); +void ofinit(prom_entry entry); +int ofstdio(ihandle *stdin, ihandle *stdout, ihandle *stderr); +int read(ihandle instance, void *buf, int buflen); +void release(void *virt, unsigned int size); +int write(ihandle instance, void *buf, int buflen); + +/* inlines */ + +extern inline void pause(void) +{ + enter(); +} diff -Nru a/arch/ppc/boot/include/rs6000.h b/arch/ppc/boot/include/rs6000.h --- a/arch/ppc/boot/include/rs6000.h Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/boot/include/rs6000.h Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.rs6000.h 1.7 05/18/01 15:17:23 cort - */ /* IBM RS/6000 "XCOFF" file definitions for BFD. Copyright (C) 1990, 1991 Free Software Foundation, Inc. FIXME: Can someone provide a transliteration of this name into ASCII? diff -Nru a/arch/ppc/boot/include/zlib.h b/arch/ppc/boot/include/zlib.h --- a/arch/ppc/boot/include/zlib.h Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/boot/include/zlib.h Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.zlib.h 1.8 05/18/01 15:17:23 cort - */ -/* * This file is derived from zlib.h and zconf.h from the zlib-0.95 * distribution by Jean-loup Gailly and Mark Adler, with some additions * by Paul Mackerras to aid in implementing Deflate compression and diff -Nru a/arch/ppc/boot/ld.script b/arch/ppc/boot/ld.script --- a/arch/ppc/boot/ld.script Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/boot/ld.script Fri Sep 20 08:20:41 2002 @@ -39,7 +39,7 @@ PROVIDE (etext = .); /* Read-write section, merged into data segment: */ - . = (. + 0x0FFF) & 0xFFFFF000; + . = ALIGN(8); .data : { *(.data) @@ -69,6 +69,7 @@ _edata = .; PROVIDE (edata = .); + . = ALIGN(8); __bss_start = .; .bss : { diff -Nru a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile --- a/arch/ppc/boot/lib/Makefile Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/boot/lib/Makefile Fri Sep 20 08:20:44 2002 @@ -2,7 +2,7 @@ # Makefile for some libs needed by zImage. # -L_TARGET := zlib.a +L_TARGET := lib.a obj-y := zlib.o diff -Nru a/arch/ppc/boot/lib/zlib.c b/arch/ppc/boot/lib/zlib.c --- a/arch/ppc/boot/lib/zlib.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/boot/lib/zlib.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * This file is derived from various .h and .c files from the zlib-0.95 * distribution by Jean-loup Gailly and Mark Adler, with some additions * by Paul Mackerras to aid in implementing Deflate compression and diff -Nru a/arch/ppc/boot/of1275/Makefile b/arch/ppc/boot/of1275/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/Makefile Fri Sep 20 08:20:49 2002 @@ -0,0 +1,10 @@ +# +# Makefile of1275 stuff +# + +L_TARGET := of1275.a + +obj-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o \ + ofstdio.o read.o release.o write.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/of1275/claim.c b/arch/ppc/boot/of1275/claim.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/claim.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,34 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "of1275.h" + +void * +claim(unsigned int virt, unsigned int size, unsigned int align) +{ + struct prom_args { + char *service; + int nargs; + int nret; + unsigned int virt; + unsigned int size; + unsigned int align; + void *ret; + } args; + + args.service = "claim"; + args.nargs = 3; + args.nret = 1; + args.virt = virt; + args.size = size; + args.align = align; + (*of_prom_entry)(&args); + return args.ret; +} diff -Nru a/arch/ppc/boot/of1275/enter.c b/arch/ppc/boot/of1275/enter.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/enter.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,22 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "of1275.h" + +void +enter(void) +{ + struct prom_args { + char *service; + } args; + + args.service = "enter"; + (*of_prom_entry)(&args); +} diff -Nru a/arch/ppc/boot/of1275/exit.c b/arch/ppc/boot/of1275/exit.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/exit.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,24 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "of1275.h" + +void +exit(void) +{ + struct prom_args { + char *service; + } args; + + for (;;) { + args.service = "exit"; + (*of_prom_entry)(&args); + } +} diff -Nru a/arch/ppc/boot/of1275/finddevice.c b/arch/ppc/boot/of1275/finddevice.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/finddevice.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,31 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "of1275.h" + +phandle +finddevice(const char *name) +{ + struct prom_args { + char *service; + int nargs; + int nret; + const char *devspec; + phandle device; + } args; + + args.service = "finddevice"; + args.nargs = 1; + args.nret = 1; + args.devspec = name; + args.device = OF_INVALID_HANDLE; + (*of_prom_entry)(&args); + return args.device; +} diff -Nru a/arch/ppc/boot/of1275/getprop.c b/arch/ppc/boot/of1275/getprop.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/getprop.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,37 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "of1275.h" + +int +getprop(phandle node, const char *name, void *buf, int buflen) +{ + struct prom_args { + char *service; + int nargs; + int nret; + phandle node; + const char *name; + void *buf; + int buflen; + int size; + } args; + + args.service = "getprop"; + args.nargs = 4; + args.nret = 1; + args.node = node; + args.name = name; + args.buf = buf; + args.buflen = buflen; + args.size = -1; + (*of_prom_entry)(&args); + return args.size; +} diff -Nru a/arch/ppc/boot/of1275/ofinit.c b/arch/ppc/boot/of1275/ofinit.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/ofinit.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,19 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "of1275.h" + +prom_entry of_prom_entry; + +void +ofinit(prom_entry prom_ptr) +{ + of_prom_entry = prom_ptr; +} diff -Nru a/arch/ppc/boot/of1275/ofstdio.c b/arch/ppc/boot/of1275/ofstdio.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/ofstdio.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,32 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "of1275.h" + +int +ofstdio(ihandle *stdin, ihandle *stdout, ihandle *stderr) +{ + ihandle in, out; + phandle chosen; + + if ((chosen = finddevice("/chosen")) == OF_INVALID_HANDLE) + goto err; + if (getprop(chosen, "stdout", &out, sizeof(out)) != 4) + goto err; + if (getprop(chosen, "stdin", &in, sizeof(in)) != 4) + goto err; + + *stdin = in; + *stdout = out; + *stderr = out; + return 0; +err: + return -1; +} diff -Nru a/arch/ppc/boot/of1275/read.c b/arch/ppc/boot/of1275/read.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/read.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,35 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "of1275.h" + +int +read(ihandle instance, void *buf, int buflen) +{ + struct prom_args { + char *service; + int nargs; + int nret; + ihandle instance; + void *buf; + int buflen; + int actual; + } args; + + args.service = "read"; + args.nargs = 3; + args.nret = 1; + args.instance = instance; + args.buf = buf; + args.buflen = buflen; + args.actual = -1; + (*of_prom_entry)(&args); + return args.actual; +} diff -Nru a/arch/ppc/boot/of1275/release.c b/arch/ppc/boot/of1275/release.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/release.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,30 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "of1275.h" + +void +release(void *virt, unsigned int size) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *virt; + unsigned int size; + } args; + + args.service = "release"; + args.nargs = 2; + args.nret = 0; + args.virt = virt; + args.size = size; + (*of_prom_entry)(&args); +} diff -Nru a/arch/ppc/boot/of1275/write.c b/arch/ppc/boot/of1275/write.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/of1275/write.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,35 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * Copyright (C) Leigh Brown 2002. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "of1275.h" + +int +write(ihandle instance, void *buf, int buflen) +{ + struct prom_args { + char *service; + int nargs; + int nret; + ihandle instance; + void *buf; + int buflen; + int actual; + } args; + + args.service = "write"; + args.nargs = 3; + args.nret = 1; + args.instance = instance; + args.buf = buf; + args.buflen = buflen; + args.actual = -1; + (*of_prom_entry)(&args); + return args.actual; +} diff -Nru a/arch/ppc/boot/openfirmware/Makefile b/arch/ppc/boot/openfirmware/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/openfirmware/Makefile Fri Sep 20 08:20:44 2002 @@ -0,0 +1,137 @@ +# Makefile for making bootable images on various OpenFirmware machines. +# +# Paul Mackerras January 1997 +# XCOFF bootable images for PowerMacs +# Geert Uytterhoeven September 1997 +# ELF bootable iamges for CHRP machines. +# Tom Rini January 2001 +# Cleaned up, moved into arch/ppc/boot/pmac +# Tom Rini July/August 2002 +# Merged 'chrp' and 'pmac' into 'openfirmware', and cleaned up the +# rules. + +OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment +COFF_LD_ARGS = -T ../ld.script -e _start -Ttext 0x00500000 -Bstatic +CHRP_LD_ARGS = -T ../ld.script -e _start -Ttext 0x00400000 +NEWWORLD_LD_ARGS = -T ../ld.script -e _start -Ttext 0x01000000 + +COMMONOBJS = start.o misc.o ../common/string.o common.o +COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o +CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o +NEWWORLDOBJS = ../common/crt0.o $(COMMONOBJS) newworldmain.o + +EXTRA_TARGETS := $(COFFOBJS) $(CHRPOBJS) $(NEWWORLDOBJS) +LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a ../of1275/of1275.a + +ADDNOTE := ../utils/addnote +MKNOTE := ../utils/mknote +SIZE := ../utils/size +OFFSET := ../utils/offset +HACKCOFF := ../utils/hack-coff + +ifdef CONFIG_SMP +END := .smp +endif +ifdef CONFIG_PPC64BRIDGE +END += .64 +endif + +TFTPIMAGE=/tftpboot/zImage. + +../common/coffcrt0.o: + $(MAKE) -C ../common coffcrt0.o + +image.o: ../images/vmlinux.gz ../common/dummy.o + $(OBJCOPY) ../common/dummy.o $@ -R .comment \ + --add-section=.image=../images/vmlinux.gz \ + --set-section-flags=.image=contents,alloc,load,readonly,data +ifdef CONFIG_XMON + $(OBJCOPY) $@ $@ \ + --add-section=.sysmap=$(TOPDIR)/System.map \ + --set-section-flags=.sysmap=contents,alloc,load,readonly,data +endif + +# Place the ramdisk in the initrd image. +image-initrd.o: image.o ../images/ramdisk.image.gz + $(OBJCOPY) image.o $@ \ + --add-section=.ramdisk=../images/ramdisk.image.gz \ + --set-section-flags=.ramdisk=contents,alloc,load,readonly,data + +# Create the note section for New-World PowerMacs. +note: $(MKNOTE) + $(MKNOTE) > note + +znetboot: vmlinux.coff vmlinux.elf-pmac zImage + cp ../images/vmlinux.coff $(TFTPIMAGE).pmac$(END) + cp ../images/vmlinux.elf-pmac $(TFTPIMAGE).pmac$(END)elf + cp ../images/zImage.chrp $(TFTPIMAGE).chrp$(END) + +znetboot.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac + cp ../images/vmlinux.initrd.coff $(TFTPIMAGE).pmac$(END) + cp ../images/vmlinux.initrd.elf-pmac $(TFTPIMAGE).pmac$(END).elf + cp ../images/zImage.initrd.chrp $(TFTPIMAGE).chrp$(END) + +miboot.image: ../common/dummy.o ../images/vmlinux.gz + $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=../images/vmlinux.gz \ + ../common/dummy.o ../images/$@ + +miboot.initrd.image: miboot.image ../images/ramdisk.image.gz + $(OBJCOPY) $(OBJCOPY_ARGS) \ + --add-section=initrd=../images/ramdisk.image.gz \ + ../images/miboot.image ../images/$@ + +coffboot: $(COFFOBJS) image.o $(LIBS) + $(LD) -o $@ $(COFF_LD_ARGS) $^ + $(OBJCOPY) $@ $@ -R .comment -R .ramdisk + +coffboot.initrd: $(COFFOBJS) image-initrd.o $(LIBS) + $(LD) -o $@ $(COFF_LD_ARGS) $^ + $(OBJCOPY) $@ $@ -R .comment + +vmlinux.coff: coffboot $(HACKCOFF) + $(OBJCOPY) $(OBJCOPY_ARGS) coffboot ../images/$@ + $(HACKCOFF) ../images/$@ + rm -f coffboot + ln -sf vmlinux.coff ../images/zImage.pmac + +vmlinux.initrd.coff: coffboot.initrd $(HACKCOFF) + $(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd ../images/$@ + $(HACKCOFF) ../images/$@ + rm -f coffboot.initrd + ln -sf vmlinux.initrd.coff ../images/zImage.initrd.pmac + +vmlinux.elf-pmac: $(NEWWORLDOBJS) $(LIBS) image.o + $(LD) $(NEWWORLD_LD_ARGS) -o ../images/$@ $^ + +vmlinux.initrd.elf-pmac: $(NEWWORLDOBJS) $(LIBS) image-initrd.o + $(LD) $(NEWWORLD_LD_ARGS) -o ../images/$@ $^ + +zImage.chrp: $(CHRPOBJS) image.o $(LIBS) + $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $^ + +zImage.initrd.chrp: $(CHRPOBJS) image-initrd.o $(LIBS) + $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $^ + +zImage: vmlinux.coff vmlinux.elf-pmac zImage.chrp miboot.image $(ADDNOTE) \ + note + $(OBJCOPY) ../images/vmlinux.elf-pmac ../images/vmlinux.elf-pmac \ + --add-section=.note=note -R .comment -R .ramdisk + $(OBJCOPY) ../images/zImage.chrp ../images/zImage.chrp \ + -R .comment -R .ramdisk + cp ../images/zImage.chrp ../images/zImage.chrp-rs6k + $(ADDNOTE) ../images/zImage.chrp-rs6k + +zImage.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac zImage.initrd.chrp \ + miboot.initrd.image $(ADDNOTE) note + $(OBJCOPY) ../images/vmlinux.initrd.elf-pmac \ + ../images/vmlinux.initrd.elf-pmac --add-section=.note=note \ + -R .comment + $(OBJCOPY) ../images/zImage.initrd.chrp ../images/zImage.initrd.chrp \ + -R .comment + cp ../images/zImage.initrd.chrp ../images/zImage.initrd.chrp-rs6k + $(ADDNOTE) ../images/zImage.initrd.chrp-rs6k + +clean: + rm -f note + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/openfirmware/chrpmain.c b/arch/ppc/boot/openfirmware/chrpmain.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/openfirmware/chrpmain.c Fri Sep 20 08:20:41 2002 @@ -0,0 +1,100 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "nonstdio.h" +#include "of1275.h" +#include +#include + +/* Passed from the linker */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin, __ramdisk_end; +extern char _start, _end; + +extern unsigned int heap_max; +extern void flush_cache(void *, unsigned long); +extern void gunzip(void *, int, unsigned char *, int *); +extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach, + unsigned int progend); + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; + +#define RAM_START 0x00000000 +#define RAM_END (64<<20) + +#define BOOT_START ((unsigned long)_start) +#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF) + +#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) +#define PROG_START 0x00010000 +#define PROG_SIZE 0x00400000 /* 4MB */ + +#define SCRATCH_SIZE (128 << 10) + +static char scratch[SCRATCH_SIZE]; /* 1MB of scratch space for gunzip */ + +typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int); + +void +boot(int a1, int a2, void *prom) +{ + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned int initrd_size, initrd_start; + + printf("chrpboot starting: loaded at 0x%p\n\r", &_start); + + initrd_size = &__ramdisk_end - &__ramdisk_begin; + if (initrd_size) { + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", + initrd_start, &__ramdisk_begin, initrd_size); + memcpy((char *)initrd_start, &__ramdisk_begin, initrd_size); + } else { + initrd_start = 0; + initrd_size = 0; + a2 = 0xdeadbeef; + } + + im = &__image_begin; + len = &__image_end - &__image_begin; + /* claim 4MB starting at PROG_START */ + claim(PROG_START, PROG_SIZE - PROG_START, 0); + dst = (void *) PROG_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + avail_ram = scratch; + begin_avail = avail_high = avail_ram; + end_avail = scratch + sizeof(scratch); + printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); + gunzip(dst, 0x400000, im, &len); + printf("done %u bytes\n\r", len); + printf("%u bytes of heap consumed, max in use %u\n\r", + avail_high - begin_avail, heap_max); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_chrp, + (PROG_START + PROG_SIZE)); + + sa = PROG_START; + printf("start address = 0x%x\n\r", sa); + + (*(kernel_start_t)sa)(a1, a2, prom, initrd_start, initrd_size); + + printf("returned?\n\r"); + + pause(); +} diff -Nru a/arch/ppc/boot/openfirmware/coffmain.c b/arch/ppc/boot/openfirmware/coffmain.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/openfirmware/coffmain.c Fri Sep 20 08:20:46 2002 @@ -0,0 +1,99 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include + +#include "nonstdio.h" +#include "of1275.h" +#include "zlib.h" + +/* Passed from the linker */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin[], __ramdisk_end; +extern char _start, _end; + +extern char image_data[], initrd_data[]; +extern int initrd_len, image_len; +extern unsigned int heap_max; +extern void flush_cache(void *start, unsigned int len); +extern void gunzip(void *, int, unsigned char *, int *); +extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach, + unsigned int progend); +extern void setup_bats(unsigned long start); + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; + +#define RAM_START 0 +#define RAM_END (RAM_START + 0x800000) /* only 8M mapped with BATs */ + +#define PROG_START RAM_START +#define PROG_SIZE 0x00400000 + +#define SCRATCH_SIZE (128 << 10) + +static char heap[SCRATCH_SIZE]; + +typedef void (*kernel_start_t)(int, int, void *); + +void boot(int a1, int a2, void *prom) +{ + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + + printf("coffboot starting: loaded at 0x%p\n", &_start); + setup_bats(RAM_START); + + initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); + if (initrd_size) { + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", + initrd_start, (char *)(&__ramdisk_begin), initrd_size); + memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); + } else + a2 = 0xdeadbeef; + + im = (char *)(&__image_begin); + len = (char *)(&__image_end) - (char *)(&__image_begin); + /* claim 4MB starting at 0 */ + claim(0, PROG_SIZE, 0); + dst = (void *) RAM_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + /* set up scratch space */ + begin_avail = avail_high = avail_ram = heap; + end_avail = heap + sizeof(heap); + printf("heap at 0x%p\n", avail_ram); + printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); + gunzip(dst, PROG_SIZE, im, &len); + printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + make_bi_recs(((unsigned long) dst + len), "coffboot", _MACH_Pmac, + (PROG_START + PROG_SIZE)); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n", sa); + + (*(kernel_start_t)sa)(a1, a2, prom); + + printf("returned?\n"); + + pause(); +} diff -Nru a/arch/ppc/boot/openfirmware/common.c b/arch/ppc/boot/openfirmware/common.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/openfirmware/common.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,179 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "zlib.h" +#include "nonstdio.h" +#include "of1275.h" +#include +#include + +/* Information from the linker */ +extern char __sysmap_begin, __sysmap_end; + +extern int strcmp(const char *s1, const char *s2); +extern char *avail_ram, *avail_high; +extern char *end_avail; + +unsigned int heap_use, heap_max; + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; + +static void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p; + struct memchunk **mpp, *mp; + + size *= items; + size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; + avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; + if (avail_ram > end_avail) { + printf("oops... out of memory\n\r"); + pause(); + } + return p; +} + +static void zfree(void *x, void *addr, unsigned nb) +{ + struct memchunk *mp = addr; + + nb = (nb + 7) & -8; + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n\r"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n\r"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n\r", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n\r", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} + +/* Make a bi_rec in OF. We need to be passed a name for BI_BOOTLOADER_ID, + * a machine type for BI_MACHTYPE, and the location where the end of the + * bootloader is (PROG_START + PROG_SIZE) + */ +void make_bi_recs(unsigned long addr, char *name, unsigned int mach, + unsigned long progend) +{ + unsigned long sysmap_size; + struct bi_record *rec; + + /* Figure out the size of a possible System.map we're going to + * pass along. + * */ + sysmap_size = (unsigned long)(&__sysmap_end) - + (unsigned long)(&__sysmap_begin); + + /* leave a 1MB gap then align to the next 1MB boundary */ + addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); + /* oldworld machine seem very unhappy about this. -- Tom */ + if (addr >= progend) + claim(addr, 0x1000, 0); + + rec = (struct bi_record *)addr; + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, name); + rec->size = sizeof(struct bi_record) + strlen(name) + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = mach; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + if (sysmap_size) { + rec->tag = BI_SYSMAP; + rec->data[0] = (unsigned long)(&__sysmap_begin); + rec->data[1] = sysmap_size; + rec->size = sizeof(struct bi_record) + 2 * + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +} diff -Nru a/arch/ppc/boot/openfirmware/misc.S b/arch/ppc/boot/openfirmware/misc.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/openfirmware/misc.S Fri Sep 20 08:20:47 2002 @@ -0,0 +1,57 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + .text + +/* + * Use the BAT3 registers to map the 1st 8MB of RAM to + * the address given as the 1st argument. + */ + .globl setup_bats +setup_bats: + mfpvr 5 + rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ + cmpi 0,5,1 + li 0,0 + bne 4f + mtibatl 3,0 /* invalidate BAT first */ + ori 3,3,4 /* set up BAT registers for 601 */ + li 4,0x7f + mtibatu 3,3 + mtibatl 3,4 + b 5f +4: mtdbatu 3,0 /* invalidate BATs first */ + mtibatu 3,0 + ori 3,3,0xff /* set up BAT registers for 604 */ + li 4,2 + mtdbatl 3,4 + mtdbatu 3,3 + mtibatl 3,4 + mtibatu 3,3 +5: sync + isync + blr + +/* + * Flush the dcache and invalidate the icache for a range of addresses. + * + * flush_cache(addr, len) + */ + .global flush_cache +flush_cache: + addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ + rlwinm. 4,4,27,5,31 + mtctr 4 + beqlr +1: dcbf 0,3 + icbi 0,3 + addi 3,3,0x20 + bdnz 1b + sync + isync + blr diff -Nru a/arch/ppc/boot/openfirmware/newworldmain.c b/arch/ppc/boot/openfirmware/newworldmain.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/openfirmware/newworldmain.c Fri Sep 20 08:20:41 2002 @@ -0,0 +1,93 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "nonstdio.h" +#include "of1275.h" +#include +#include + +/* Passed from the linker */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin[], __ramdisk_end; +extern char _start, _end; + +extern unsigned int heap_max; +extern void flush_cache(void *start, unsigned int len); +extern void gunzip(void *, int, unsigned char *, int *); +extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach, + unsigned int progend); + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; + + +#define RAM_END (16 << 20) + +#define PROG_START 0x00010000 +#define PROG_SIZE 0x003f0000 + +#define SCRATCH_SIZE (128 << 10) + +typedef void (*kernel_start_t)(int, int, void *); + +void boot(int a1, int a2, void *prom) +{ + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + + printf("chrpboot starting: loaded at 0x%p\n", &_start); + + initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); + if (initrd_size) { + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", + initrd_start, (char *)(&__ramdisk_begin), initrd_size); + memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); + } else + a2 = 0xdeadbeef; + + im = (char *)(&__image_begin); + len = (char *)(&__image_end) - (char *)(&__image_begin); + /* claim 3MB starting at PROG_START */ + claim(PROG_START, PROG_SIZE, 0); + dst = (void *) PROG_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + /* claim some memory for scratch space */ + avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); + begin_avail = avail_high = avail_ram; + end_avail = avail_ram + SCRATCH_SIZE; + printf("heap at 0x%p\n", avail_ram); + printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); + gunzip(dst, PROG_SIZE, im, &len); + printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); + release(begin_avail, SCRATCH_SIZE); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_Pmac, + (PROG_START + PROG_SIZE)); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n", sa); + + (*(kernel_start_t)sa)(a1, a2, prom); + + printf("returned?\n"); + + pause(); +} diff -Nru a/arch/ppc/boot/openfirmware/start.c b/arch/ppc/boot/openfirmware/start.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/openfirmware/start.c Fri Sep 20 08:20:47 2002 @@ -0,0 +1,172 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include "of1275.h" + +extern int strlen(const char *s); +extern void boot(int a1, int a2, void *prom); + +phandle stdin; +phandle stdout; +phandle stderr; + +void printk(char *fmt, ...); + +void +start(int a1, int a2, void *promptr) +{ + ofinit(promptr); + if (ofstdio(&stdin, &stdout, &stderr)) + exit(); + + boot(a1, a2, promptr); + for (;;) + exit(); +} + +int writestring(void *f, char *ptr, int nb) +{ + int w = 0, i; + char *ret = "\r"; + + for (i = 0; i < nb; ++i) { + if (ptr[i] == '\n') { + if (i > w) { + write(f, ptr + w, i - w); + w = i; + } + write(f, ret, 1); + } + } + if (w < nb) + write(f, ptr + w, nb - w); + return nb; +} + +int +putc(int c, void *f) +{ + char ch = c; + + return writestring(f, &ch, 1) == 1? c: -1; +} + +int +putchar(int c) +{ + return putc(c, stdout); +} + +int +fputs(char *str, void *f) +{ + int n = strlen(str); + + return writestring(f, str, n) == n? 0: -1; +} + +int +readchar(void) +{ + char ch; + + for (;;) { + switch (read(stdin, &ch, 1)) { + case 1: + return ch; + case -1: + printk("read(stdin) returned -1\n"); + return -1; + } + } +} + +static char line[256]; +static char *lineptr; +static int lineleft; + +int +getchar(void) +{ + int c; + + if (lineleft == 0) { + lineptr = line; + for (;;) { + c = readchar(); + if (c == -1 || c == 4) + break; + if (c == '\r' || c == '\n') { + *lineptr++ = '\n'; + putchar('\n'); + break; + } + switch (c) { + case 0177: + case '\b': + if (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + case 'U' & 0x1F: + while (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + default: + if (lineptr >= &line[sizeof(line) - 1]) + putchar('\a'); + else { + putchar(c); + *lineptr++ = c; + } + } + } + lineleft = lineptr - line; + lineptr = line; + } + if (lineleft == 0) + return -1; + --lineleft; + return *lineptr++; +} + +extern int vsprintf(char *buf, const char *fmt, va_list args); +static char sprint_buf[1024]; + +void +printk(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + writestring(stdout, sprint_buf, n); +} + +int +printf(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + writestring(stdout, sprint_buf, n); + return n; +} diff -Nru a/arch/ppc/boot/pmac/Makefile b/arch/ppc/boot/pmac/Makefile --- a/arch/ppc/boot/pmac/Makefile Fri Sep 20 08:20:44 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,112 +0,0 @@ -# BK Id: %F% %I% %G% %U% %#% -# -# Makefile for making XCOFF bootable images for booting on PowerMacs -# using Open Firmware. -# -# Paul Mackerras January 1997 -# -# Cleaned up, moved into arch/ppc/boot/pmac -# Tom Rini January 2001 - -OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment -COFF_LD_ARGS = -T ../ld.script -e _start -Ttext 0x00500000 -Bstatic -CHRP_LD_ARGS = -T ../ld.script -Ttext 0x01000000 - -COMMONOBJS = start.o misc.o ../common/string.o ../common/ofcommon.o -COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o -CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o - -EXTRA_TARGETS := $(COFFOBJS) $(CHRPOBJS) -LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a - -MKNOTE := ../utils/mknote -SIZE := ../utils/size -OFFSET := ../utils/offset -HACKCOFF := ../utils/hack-coff - -ifdef CONFIG_SMP -END := .smp -endif -ifdef CONFIG_PPC64BRIDGE -END += .64 -endif - -TFTPIMAGE=/tftpboot/zImage.pmac$(END) - -../common/coffcrt0.o: - $(MAKE) -C ../common coffcrt0.o - -image.o: ../images/vmlinux.gz ../common/dummy.o - $(OBJCOPY) ../common/dummy.o $@ -R .comment \ - --add-section=.image=../images/vmlinux.gz \ - --set-section-flags=.image=contents,alloc,load,readonly,data -ifdef CONFIG_XMON - $(OBJCOPY) $@ $@ \ - --add-section=.sysmap=$(TOPDIR)/System.map \ - --set-section-flags=.sysmap=contents,alloc,load,readonly,data -endif - -znetboot: vmlinux.coff vmlinux.elf-pmac zImage - cp ../images/vmlinux.coff $(TFTPIMAGE) - cp ../images/vmlinux.elf-pmac $(TFTPIMAGE).elf - -znetboot.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac - cp ../images/vmlinux.initrd.coff $(TFTPIMAGE) - cp ../images/vmlinux.initrd.elf-pmac $(TFTPIMAGE).elf - -miboot.image: ../common/dummy.o ../images/vmlinux.gz - $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=../images/vmlinux.gz \ - ../common/dummy.o ../images/$@ - -miboot.initrd.image: miboot.image ../images/ramdisk.image.gz - $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=../images/ramdisk.image.gz \ - ../images/miboot.image ../images/$@ - -coffboot: $(COFFOBJS) image.o $(LIBS) ../ld.script - $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) image.o $(LIBS) - $(OBJCOPY) $@ $@ -R .comment - -coffboot.initrd: $(COFFOBJS) image.o $(LIBS) ../ld.script \ - ../images/ramdisk.image.gz - $(OBJCOPY) image.o image-coff.o \ - --add-section=.ramdisk=../images/ramdisk.image.gz \ - --set-section-flags=.ramdisk=contents,alloc,load,readonly,data - $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) image-coff.o $(LIBS) - $(OBJCOPY) $@ $@ -R .comment - rm -f image-coff.o - -vmlinux.coff: coffboot $(HACKCOFF) - $(OBJCOPY) $(OBJCOPY_ARGS) coffboot ../images/$@ - $(HACKCOFF) ../images/$@ - rm -f coffboot - ln -sf vmlinux.coff ../images/zImage.pmac - -vmlinux.initrd.coff: coffboot.initrd $(HACKCOFF) - $(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd ../images/$@ - $(HACKCOFF) ../images/$@ - rm -f coffboot.initrd - ln -sf vmlinux.initrd.coff ../images/zImage.initrd.pmac - -vmlinux.elf-pmac: $(CHRPOBJS) $(LIBS) $(MKNOTE) image.o - $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) $(LIBS) image.o - $(MKNOTE) > note - $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \ - -R .comment -R .ramdisk - rm -f note - -vmlinux.initrd.elf-pmac: $(CHRPOBJS) $(LIBS) $(MKNOTE) image.o \ - ../images/ramdisk.image.gz - $(OBJCOPY) image.o image-elf.o \ - --add-section=.ramdisk=../images/ramdisk.image.gz \ - --set-section-flags=.ramdisk=contents,alloc,load,readonly,data - $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) $(LIBS) image-elf.o - $(MKNOTE) > note - $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \ - -R .comment - rm -f note image-elf.o - -zImage: vmlinux.coff vmlinux.elf-pmac miboot.image - -zImage.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac miboot.initrd.image - -include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/pmac/chrpmain.c b/arch/ppc/boot/pmac/chrpmain.c --- a/arch/ppc/boot/pmac/chrpmain.c Fri Sep 20 08:20:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,100 +0,0 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * Copyright (C) Paul Mackerras 1997. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include "nonstdio.h" -#include -#include - -/* Passed from the linker */ -extern char __image_begin, __image_end; -extern char __ramdisk_begin[], __ramdisk_end; -extern char _start, _end; - -extern int getprop(void *, const char *, void *, int); -extern unsigned int heap_max; -extern void *claim(unsigned int virt, unsigned int size, unsigned int align); -extern void *finddevice(const char *); -extern void flush_cache(void *start, unsigned int len); -extern void gunzip(void *, int, unsigned char *, int *); -extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach, - unsigned int progend); -extern void pause(void); -extern void release(void *ptr, unsigned int len); - -char *avail_ram; -char *begin_avail, *end_avail; -char *avail_high; - - -#define RAM_END (16 << 20) - -#define PROG_START 0x00010000 -#define PROG_SIZE 0x003f0000 - -#define SCRATCH_SIZE (128 << 10) - -typedef void (*kernel_start_t)(int, int, void *); - -void boot(int a1, int a2, void *prom) -{ - unsigned sa, len; - void *dst; - unsigned char *im; - unsigned initrd_start, initrd_size; - - printf("chrpboot starting: loaded at 0x%p\n", &_start); - - initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); - if (initrd_size) { - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - claim(initrd_start, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", - initrd_start, (char *)(&__ramdisk_begin), initrd_size); - memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); - } else - a2 = 0xdeadbeef; - - im = (char *)(&__image_begin); - len = (char *)(&__image_end) - (char *)(&__image_begin); - /* claim 3MB starting at PROG_START */ - claim(PROG_START, PROG_SIZE, 0); - dst = (void *) PROG_START; - if (im[0] == 0x1f && im[1] == 0x8b) { - /* claim some memory for scratch space */ - avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); - begin_avail = avail_high = avail_ram; - end_avail = avail_ram + SCRATCH_SIZE; - printf("heap at 0x%p\n", avail_ram); - printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); - gunzip(dst, PROG_SIZE, im, &len); - printf("done %u bytes\n", len); - printf("%u bytes of heap consumed, max in use %u\n", - avail_high - begin_avail, heap_max); - release(begin_avail, SCRATCH_SIZE); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_Pmac, - (PROG_START + PROG_SIZE)); - - sa = (unsigned long)PROG_START; - printf("start address = 0x%x\n", sa); - - (*(kernel_start_t)sa)(a1, a2, prom); - - printf("returned?\n"); - - pause(); -} diff -Nru a/arch/ppc/boot/pmac/coffmain.c b/arch/ppc/boot/pmac/coffmain.c --- a/arch/ppc/boot/pmac/coffmain.c Fri Sep 20 08:20:46 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,105 +0,0 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * Copyright (C) Paul Mackerras 1997. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include - -#include "nonstdio.h" -#include "zlib.h" - -/* Passed from the linker */ -extern char __image_begin, __image_end; -extern char __ramdisk_begin[], __ramdisk_end; -extern char _start, _end; - -extern char *claim(unsigned, unsigned, unsigned); -extern char image_data[], initrd_data[]; -extern int initrd_len, image_len; -extern int getprop(void *, const char *, void *, int); -extern unsigned int heap_max; -extern void *finddevice(const char *); -extern void flush_cache(void *start, unsigned int len); -extern void gunzip(void *, int, unsigned char *, int *); -extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach, - unsigned int progend); -extern void pause(void); -extern void setup_bats(unsigned long start); - -char *avail_ram; -char *begin_avail, *end_avail; -char *avail_high; - -#define RAM_START 0 -#define RAM_END (RAM_START + 0x800000) /* only 8M mapped with BATs */ - -#define PROG_START RAM_START -#define PROG_SIZE 0x00400000 - -#define SCRATCH_SIZE (128 << 10) - -static char heap[SCRATCH_SIZE]; - -typedef void (*kernel_start_t)(int, int, void *); - -void boot(int a1, int a2, void *prom) -{ - unsigned sa, len; - void *dst; - unsigned char *im; - unsigned initrd_start, initrd_size; - - printf("coffboot starting: loaded at 0x%p\n", &_start); - setup_bats(RAM_START); - - initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); - if (initrd_size) { - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - claim(initrd_start, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", - initrd_start, (char *)(&__ramdisk_begin), initrd_size); - memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); - } else - a2 = 0xdeadbeef; - - im = (char *)(&__image_begin); - len = (char *)(&__image_end) - (char *)(&__image_begin); - /* claim 4MB starting at 0 */ - claim(0, PROG_SIZE, 0); - dst = (void *) RAM_START; - if (im[0] == 0x1f && im[1] == 0x8b) { - /* set up scratch space */ - begin_avail = avail_high = avail_ram = heap; - end_avail = heap + sizeof(heap); - printf("heap at 0x%p\n", avail_ram); - printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); - gunzip(dst, PROG_SIZE, im, &len); - printf("done %u bytes\n", len); - printf("%u bytes of heap consumed, max in use %u\n", - avail_high - begin_avail, heap_max); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - make_bi_recs(((unsigned long) dst + len), "coffboot", _MACH_Pmac, - (PROG_START + PROG_SIZE)); - - sa = (unsigned long)PROG_START; - printf("start address = 0x%x\n", sa); - - (*(kernel_start_t)sa)(a1, a2, prom); - - printf("returned?\n"); - - pause(); -} diff -Nru a/arch/ppc/boot/pmac/misc.S b/arch/ppc/boot/pmac/misc.S --- a/arch/ppc/boot/pmac/misc.S Fri Sep 20 08:20:47 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,60 +0,0 @@ -/* - * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:17:15 cort - */ -/* - * Copyright (C) Paul Mackerras 1997. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - .text - -/* - * Use the BAT3 registers to map the 1st 8MB of RAM to - * the address given as the 1st argument. - */ - .globl setup_bats -setup_bats: - mfpvr 5 - rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ - cmpi 0,5,1 - li 0,0 - bne 4f - mtibatl 3,0 /* invalidate BAT first */ - ori 3,3,4 /* set up BAT registers for 601 */ - li 4,0x7f - mtibatu 3,3 - mtibatl 3,4 - b 5f -4: mtdbatu 3,0 /* invalidate BATs first */ - mtibatu 3,0 - ori 3,3,0xff /* set up BAT registers for 604 */ - li 4,2 - mtdbatl 3,4 - mtdbatu 3,3 - mtibatl 3,4 - mtibatu 3,3 -5: sync - isync - blr - -/* - * Flush the dcache and invalidate the icache for a range of addresses. - * - * flush_cache(addr, len) - */ - .global flush_cache -flush_cache: - addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ - rlwinm. 4,4,27,5,31 - mtctr 4 - beqlr -1: dcbf 0,3 - icbi 0,3 - addi 3,3,0x20 - bdnz 1b - sync - isync - blr diff -Nru a/arch/ppc/boot/pmac/start.c b/arch/ppc/boot/pmac/start.c --- a/arch/ppc/boot/pmac/start.c Fri Sep 20 08:20:47 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,346 +0,0 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * Copyright (C) Paul Mackerras 1997. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include - -extern int strlen(const char *s); -extern void boot(int a1, int a2, void *prom); - -int (*prom)(void *); - -void *chosen_handle; -void *stdin; -void *stdout; -void *stderr; - -void exit(void); -void *finddevice(const char *name); -int getprop(void *phandle, const char *name, void *buf, int buflen); -void printk(char *fmt, ...); - -void -start(int a1, int a2, void *promptr) -{ - prom = (int (*)(void *)) promptr; - chosen_handle = finddevice("/chosen"); - if (chosen_handle == (void *) -1) - exit(); - if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) - exit(); - stderr = stdout; - if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) - exit(); - - boot(a1, a2, promptr); - for (;;) - exit(); -} - -int -write(void *handle, void *ptr, int nb) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *ihandle; - void *addr; - int len; - int actual; - } args; - - args.service = "write"; - args.nargs = 3; - args.nret = 1; - args.ihandle = handle; - args.addr = ptr; - args.len = nb; - args.actual = -1; - (*prom)(&args); - return args.actual; -} - -int writestring(void *f, char *ptr, int nb) -{ - int w = 0, i; - char *ret = "\r"; - - for (i = 0; i < nb; ++i) { - if (ptr[i] == '\n') { - if (i > w) { - write(f, ptr + w, i - w); - w = i; - } - write(f, ret, 1); - } - } - if (w < nb) - write(f, ptr + w, nb - w); - return nb; -} - -int -read(void *handle, void *ptr, int nb) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *ihandle; - void *addr; - int len; - int actual; - } args; - - args.service = "read"; - args.nargs = 3; - args.nret = 1; - args.ihandle = handle; - args.addr = ptr; - args.len = nb; - args.actual = -1; - (*prom)(&args); - return args.actual; -} - -void -exit(void) -{ - struct prom_args { - char *service; - } args; - - for (;;) { - args.service = "exit"; - (*prom)(&args); - } -} - -void -pause(void) -{ - struct prom_args { - char *service; - } args; - - args.service = "enter"; - (*prom)(&args); -} - -void * -finddevice(const char *name) -{ - struct prom_args { - char *service; - int nargs; - int nret; - const char *devspec; - void *phandle; - } args; - - args.service = "finddevice"; - args.nargs = 1; - args.nret = 1; - args.devspec = name; - args.phandle = (void *) -1; - (*prom)(&args); - return args.phandle; -} - -void * -claim(unsigned int virt, unsigned int size, unsigned int align) -{ - struct prom_args { - char *service; - int nargs; - int nret; - unsigned int virt; - unsigned int size; - unsigned int align; - void *ret; - } args; - - args.service = "claim"; - args.nargs = 3; - args.nret = 1; - args.virt = virt; - args.size = size; - args.align = align; - (*prom)(&args); - return args.ret; -} - -void -release(void *virt, unsigned int size) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *virt; - unsigned int size; - } args; - - args.service = "release"; - args.nargs = 2; - args.nret = 0; - args.virt = virt; - args.size = size; - (*prom)(&args); -} - -int -getprop(void *phandle, const char *name, void *buf, int buflen) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *phandle; - const char *name; - void *buf; - int buflen; - int size; - } args; - - args.service = "getprop"; - args.nargs = 4; - args.nret = 1; - args.phandle = phandle; - args.name = name; - args.buf = buf; - args.buflen = buflen; - args.size = -1; - (*prom)(&args); - return args.size; -} - -int -putc(int c, void *f) -{ - char ch = c; - - return writestring(f, &ch, 1) == 1? c: -1; -} - -int -putchar(int c) -{ - return putc(c, stdout); -} - -int -fputs(char *str, void *f) -{ - int n = strlen(str); - - return writestring(f, str, n) == n? 0: -1; -} - -int -readchar(void) -{ - char ch; - - for (;;) { - switch (read(stdin, &ch, 1)) { - case 1: - return ch; - case -1: - printk("read(stdin) returned -1\n"); - return -1; - } - } -} - -static char line[256]; -static char *lineptr; -static int lineleft; - -int -getchar(void) -{ - int c; - - if (lineleft == 0) { - lineptr = line; - for (;;) { - c = readchar(); - if (c == -1 || c == 4) - break; - if (c == '\r' || c == '\n') { - *lineptr++ = '\n'; - putchar('\n'); - break; - } - switch (c) { - case 0177: - case '\b': - if (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - case 'U' & 0x1F: - while (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - default: - if (lineptr >= &line[sizeof(line) - 1]) - putchar('\a'); - else { - putchar(c); - *lineptr++ = c; - } - } - } - lineleft = lineptr - line; - lineptr = line; - } - if (lineleft == 0) - return -1; - --lineleft; - return *lineptr++; -} - -extern int vsprintf(char *buf, const char *fmt, va_list args); -static char sprint_buf[1024]; - -void -printk(char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(sprint_buf, fmt, args); - va_end(args); - writestring(stdout, sprint_buf, n); -} - -int -printf(char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(sprint_buf, fmt, args); - va_end(args); - writestring(stdout, sprint_buf, n); - return n; -} diff -Nru a/arch/ppc/boot/prep/Makefile b/arch/ppc/boot/prep/Makefile --- a/arch/ppc/boot/prep/Makefile Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/boot/prep/Makefile Fri Sep 20 08:20:47 2002 @@ -1,5 +1,3 @@ -# BK Id: %F% %I% %G% %U% %#% -# # arch/ppc/boot/Makefile # # This file is subject to the terms and conditions of the GNU General Public @@ -21,13 +19,14 @@ endif LD_ARGS = -T ../ld.script -Ttext 0x00800000 -Bstatic -boot-y := head.o ../simple/legacy.o misc.o of1275.o \ +boot-y := head.o ../simple/legacy.o misc.o \ ../common/util.o ../common/string.o \ - ../common/misc-common.o + ../common/misc-common.o \ + ../common/mpc10x_memory.o OBJCOPY_ARGS = -O elf32-powerpc LIBS = ../lib/zlib.a -boot-$($CONFIG_SERIAL_8250_CONSOLE) += ../common/ns16550.o +boot-$(CONFIG_SERIAL_8250_CONSOLE) += ../common/ns16550.o boot-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o EXTRA_TARGETS := $(boot-y) diff -Nru a/arch/ppc/boot/prep/head.S b/arch/ppc/boot/prep/head.S --- a/arch/ppc/boot/prep/head.S Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/boot/prep/head.S Fri Sep 20 08:20:43 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - #include #include #include @@ -38,10 +34,6 @@ isync mr r11,r3 /* Save pointer to residual/board data */ - mr r25,r5 /* Save OFW pointer */ - - /* Save the original MSR value */ - mfmsr r26 /* Establish default MSR value */ li r3,MSR_IP|MSR_FP @@ -114,17 +106,11 @@ li r2,0x000F /* Mask pointer to 16-byte boundary */ andc r1,r1,r2 - /* Store the original MSR into 'orig_MSR' */ - lis r3,orig_MSR@h - ori r3,r3,orig_MSR@l - stw r26,0(r3) - /* Run loader */ mr r3,r8 /* Load point */ mr r4,r7 /* Program length */ mr r5,r6 /* Checksum */ mr r6,r11 /* Residual data */ - mr r7,r25 /* OFW interfaces */ bl decompress_kernel /* diff -Nru a/arch/ppc/boot/prep/iso_font.h b/arch/ppc/boot/prep/iso_font.h --- a/arch/ppc/boot/prep/iso_font.h Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/boot/prep/iso_font.h Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.iso_font.h 1.6 05/18/01 15:16:42 cort - */ static const unsigned char font[] = { /* 0x00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x01 */ 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00, diff -Nru a/arch/ppc/boot/prep/kbd.c b/arch/ppc/boot/prep/kbd.c --- a/arch/ppc/boot/prep/kbd.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/boot/prep/kbd.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - #include #include "defkeymap.c" /* yeah I know it's bad -- Cort */ diff -Nru a/arch/ppc/boot/prep/misc.c b/arch/ppc/boot/prep/misc.c --- a/arch/ppc/boot/prep/misc.c Fri Sep 20 08:20:42 2002 +++ b/arch/ppc/boot/prep/misc.c Fri Sep 20 08:20:42 2002 @@ -1,6 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - * * arch/ppc/boot/prep/misc.c * * Adapted for PowerPC by Gary Thomas @@ -20,6 +18,7 @@ #include #include #include + #include "nonstdio.h" #include "zlib.h" @@ -51,7 +50,6 @@ RESIDUAL hold_resid_buf; RESIDUAL *hold_residual = &hold_resid_buf; unsigned long initrd_size = 0; -unsigned long orig_MSR; char *zimage_start; int zimage_size; @@ -66,16 +64,11 @@ #endif /* CONFIG_VGA_CONSOLE */ extern int CRT_tstc(void); -extern void of_init(void *handler); -extern int of_finddevice(const char *device_specifier, int *phandle); -extern int of_getprop(int phandle, const char *name, void *buf, int buflen, - int *size); extern int vga_init(unsigned char *ISA_mem); extern void gunzip(void *, int, unsigned char *, int *); - -extern void _put_MSR(unsigned int val); extern unsigned long serial_init(int chan, void *ignored); extern void serial_fixups(void); +extern unsigned long get_mem_size(void); void writel(unsigned int val, unsigned int address) @@ -120,15 +113,12 @@ unsigned long decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, - RESIDUAL *residual, void *OFW_interface) + RESIDUAL *residual) { int timer = 0; extern unsigned long start; char *cp, ch; unsigned long TotalMemory; - int dev_handle; - int mem_info[2]; - int res, size; unsigned char board_type; unsigned char base_mod; int start_multi = 0; @@ -142,6 +132,11 @@ vga_init((unsigned char *)0xC0000000); #endif /* CONFIG_VGA_CONSOLE */ + /* + * Find out how much memory we have. + */ + TotalMemory = get_mem_size(); + /* * Tell the user where we were loaded at and where we were relocated * to for debugging this process. @@ -218,47 +213,6 @@ } else { /* Tell the user we didn't find anything. */ puts("No residual data found.\n"); - - /* Assume 32M in the absence of more info... */ - TotalMemory = 0x02000000; - - /* - * This is a 'best guess' check. We want to make sure - * we don't try this on a PReP box without OF - * -- Cort - */ - while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) ) - { - /* We need to restore the slightly inaccurate - * MSR so that OpenFirmware will behave. -- Tom - */ - _put_MSR(orig_MSR); - of_init(OFW_interface); - - /* get handle to memory description */ - res = of_finddevice("/memory@0", - &dev_handle); - if (res) - break; - - /* get the info */ - res = of_getprop(dev_handle, - "reg", - mem_info, - sizeof(mem_info), - &size); - if (res) - break; - - TotalMemory = mem_info[1]; - break; - } - - hold_residual->TotalMemory = TotalMemory; - residual = hold_residual; - - /* Enforce a sane MSR for booting. */ - _put_MSR(MSR_IP); } /* assume the chunk below 8M is free */ @@ -361,6 +315,11 @@ rec->data[1] = 0; rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MEMSIZE; + rec->data[0] = TotalMemory; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); rec->tag = BI_CMD_LINE; diff -Nru a/arch/ppc/boot/prep/of1275.c b/arch/ppc/boot/prep/of1275.c --- a/arch/ppc/boot/prep/of1275.c Fri Sep 20 08:20:45 2002 +++ b/arch/ppc/boot/prep/of1275.c Fri Sep 20 08:20:45 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.of1275.c 1.6 05/18/01 15:16:42 cort - */ /* Open Firmware Client Interface */ diff -Nru a/arch/ppc/boot/prep/of1275.h b/arch/ppc/boot/prep/of1275.h --- a/arch/ppc/boot/prep/of1275.h Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/boot/prep/of1275.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.of1275.h 1.6 05/18/01 15:16:42 cort - */ /* 6.3.2.1 Client interface */ diff -Nru a/arch/ppc/boot/prep/vreset.c b/arch/ppc/boot/prep/vreset.c --- a/arch/ppc/boot/prep/vreset.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/boot/prep/vreset.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * vreset.c * * Initialize the VGA control registers to 80x25 text mode. diff -Nru a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile --- a/arch/ppc/boot/simple/Makefile Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/boot/simple/Makefile Fri Sep 20 08:20:41 2002 @@ -3,11 +3,21 @@ # # Author: Tom Rini # -# Copyright 2001 MontaVista Software Inc. +# Copyright 2001-2002 MontaVista Software Inc. # -# Notes: For machine targets which produce more than one image, define +# Notes: +# (1) For machine targets which produce more than one image, define # ZNETBOOT and ZNETBOOTRD to the image which should be available for # 'znetboot' and 'znetboot.initrd` +# (2) Also, for machine targets which just need to remove the ELF header, +# define END to be the machine name you want in the image. +# (3) For machine targets which use the mktree program, define END to be +# the machine name you want in the image, and you can optionally set +# ENTRYPOINT which the image should be loaded at. The optimal setting +# for ENTRYPOINT is the link address. +# (4) It is advisable to pass in the memory size using BI_MEMSIZE and +# get_mem_size(), which is memory controller dependant. Add in the correct +# XXX_memory.o file for this to work, as well as editing the $(MISC) file. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the @@ -17,40 +27,36 @@ # Normally, we use the 'misc-simple.c' file for decompress_kernel and # whatnot. Sometimes we need to override this however. MISC := ../common/misc-simple.o -ifeq ($(CONFIG_TREEBOOT),y) +ifeq ($(CONFIG_IBM_OPENBIOS),y) ZIMAGE := zImage-TREE ZIMAGEINITRD := zImage.initrd-TREE -TFTPIMAGE := /tftpboot/zImage.embedded +END := treeboot +TFTPIMAGE := /tftpboot/zImage.$(END) MISC := misc-embedded.o endif ifeq ($(CONFIG_EMBEDDEDBOOT),y) -ZIMAGE := zImage-EMBEDDED -ZIMAGEINITRD := zImage.initrd-EMBEDDED TFTPIMAGE := /tftpboot/zImage.embedded MISC := misc-embedded.o endif ifeq ($(CONFIG_EV64260),y) -ZIMAGE := zImage-EV64260 -ZIMAGEINITRD := zImage.initrd-EV64260 -HEADHELP := direct.o misc-ev64260.o +EXTRA := direct.o misc-ev64260.o TFTPIMAGE := /tftpboot/zImage.ev64260 endif ifeq ($(CONFIG_GEMINI),y) -ZIMAGE := zImage-SMON -ZIMAGEINITRD := zImage.initrd-SMON -HEADHELP := direct.o -TFTPIMAGE := /tftpboot/zImage.gemini +ZIMAGE := zImage-STRIPELF +ZIMAGEINITRD := zImage.initrd-STRIPELF +EXTRA := direct.o +END := gemini +TFTPIMAGE := /tftpboot/zImage.$(END) endif ifeq ($(CONFIG_MENF1),y) ZIMAGE := zImage-MENF1 ZIMAGEINITRD := zImage.initrd-MENF1 -HEADHELP := chrpmap.o +EXTRA := chrpmap.o TFTPIMAGE := /tftpboot/zImage.menf1 endif ifeq ($(CONFIG_K2),y) -ZIMAGE := zImage-K2 -ZIMAGEINITRD := zImage.initrd-K2 -HEADHELP := legacy.o +EXTRA := legacy.o TFTPIMAGE := /tftpboot/zImage.k2 endif # kbuild-2.4 'feature', only one of these will ever by 'y' at a time. @@ -58,45 +64,50 @@ ifeq ($(CONFIG_MCPN765)$(CONFIG_MVME5100)$(CONFIG_PRPMC750)$(CONFIG_PRPMC800)$(CONFIG_LOPEC)$(CONFIG_PPLUS),y) ZIMAGE := zImage-PPLUS ZIMAGEINITRD := zImage.initrd-PPLUS -HEADHELP := direct.o +EXTRA := direct.o TFTPIMAGE := /tftpboot/zImage.pplus ZNETBOOT := zImage.pplus ZNETBOOTRD := zImage.initrd.pplus endif ifeq ($(CONFIG_PPLUS),y) -HEADHELP := legacy.o +EXTRA := legacy.o +endif +ifeq ($(CONFIG_LOPEC),y) +EXTRA += ../common/mpc10x_memory.o +endif +ifeq ($(CONFIG_PAL4),y) +EXTRA := direct.o ../common/cpc700_memory.o endif -ifeq ($(CONFIG_PCORE),y) -ZIMAGE := zImage-PCORE -ZIMAGEINITRD := zImage.initrd-PCORE -HEADHELP := chrpmap.o -TFTPIMAGE := /tftpboot/zImage.pcore +ifeq ($(CONFIG_PCORE)$(CONFIG_POWERPMC250),y) +ZIMAGE := zImage-STRIPELF +ZIMAGEINITRD := zImage.initrd-STRIPELF +EXTRA := chrpmap.o +END := pcore +TFTPIMAGE := /tftpboot/zImage.$(END) endif -#Ugh, should come up with a better nameing convention.. +# The PowerPMC 250 needs the dummy serial_fixups() ifeq ($(CONFIG_POWERPMC250),y) -ZIMAGE := zImage-PCORE -ZIMAGEINITRD := zImage.initrd-PCORE -HEADHELP := direct.o -TFTPIMAGE := /tftpboot/zImage.pcore +EXTRA := direct.o endif ifeq ($(CONFIG_SANDPOINT),y) -ZIMAGE := zImage-SP -ZIMAGEINITRD := zImage.initrd-SP -HEADHELP := direct.o +EXTRA := direct.o TFTPIMAGE := /tftpboot/zImage.sandpoint endif ifeq ($(CONFIG_SPRUCE),y) -ZIMAGE := zImage-SPRUCE -ZIMAGEINITRD := zImage.initrd-SPRUCE -HEADHELP := direct.o +ZIMAGE := zImage-TREE +ZIMAGEINITRD := zImage.initrd-TREE +EXTRA := direct.o +END := spruce +ENTRYPOINT := 0x00800000 MISC := misc-spruce.o -TFTPIMAGE := /tftpboot/zImage.spruce +TFTPIMAGE := /tftpboot/zImage.$(END) endif ifeq ($(CONFIG_ZX4500),y) -ZIMAGE := zImage-ZX4500 -ZIMAGEINITRD := zImage.initrd-ZX4500 -HEADHELP := direct.o -TFTPIMAGE := /tftpboot/zImage.zx4500 +ZIMAGE := zImage-STRIPELF +ZIMAGEINITRD := zImage.initrd-STRIPELF +EXTRA := direct.o +END := zx4500 +TFTPIMAGE := /tftpboot/zImage.$(END) endif ifeq ($(CONFIG_SMP),y) TFTPIMAGE += .smp @@ -105,7 +116,7 @@ # This is a treeboot that needs init functions until the # boot rom is sorted out (i.e. this is short lived) EXTRA_AFLAGS := -Wa,-m405 -HEADHELP := rw4/rw4_init.o rw4/rw4_init_brd.o +EXTRA := rw4/rw4_init.o rw4/rw4_init_brd.o endif # Default linker args. Link at 0x00800000 or 0x00400000 by default, but @@ -122,7 +133,7 @@ OBJCOPY_ARGS := -O elf32-powerpc # head.o and ../common/relocate.o must be at the start. -boot-y := head.o ../common/relocate.o $(HEADHELP) \ +boot-y := head.o ../common/relocate.o $(EXTRA) \ $(MISC) ../common/misc-common.o \ ../common/string.o ../common/util.o boot-$(CONFIG_4xx) += embed_config.o @@ -170,9 +181,12 @@ -R .sysmap # Sort-of dummy rules, that let us format the image we want. -zImage: $(ZIMAGE) +zImage: $(ZIMAGE) zvmlinux + cp -f zvmlinux ../images/zImage.elf rm -f zvmlinux -zImage.initrd: $(ZIMAGEINITRD) + +zImage.initrd: $(ZIMAGEINITRD) zvmlinux.initrd + cp -f zvmlinux.initrd ../images/zImage.initrd.elf rm -f zvmlinux.initrd znetboot: zImage @@ -189,23 +203,17 @@ cp ../images/zImage.* $(TFTPIMAGE) endif -zImage-EMBEDDED: zvmlinux - mv zvmlinux ../images/zImage.embedded +zImage-STRIPELF: zvmlinux + dd if=zvmlinux of=../images/zImage.$(END) skip=64 bs=1k -zImage.initrd-EMBEDDED: zvmlinux.initrd - mv zvmlinux.initrd ../images/zImage.initrd.embedded +zImage.initrd-STRIPELF: zvmlinux.initrd + dd if=zvmlinux.initrd of=../images/zImage.initrd.$(END) skip=64 bs=1k -zImage-K2: zvmlinux - mv zvmlinux ../images/zImage.k2 - -zImage.initrd-K2: zvmlinux.initrd - mv zvmlinux.initrd ../images/zImage.initrd.k2 - -zImage-EV64260: zvmlinux - mv zvmlinux ../images/zImage.ev64260 +zImage-TREE: zvmlinux + $(MKTREE) zvmlinux ../images/zImage.$(END) $(ENTRYPOINT) -zImage.initrd-EV64260: zvmlinux.initrd - mv zvmlinux.initrd ../images/zImage.initrd.ev64260 +zImage.initrd-TREE: zvmlinux.initrd + $(MKTREE) zvmlinux.initrd ../images/zImage.initrd.$(END) $(ENTRYPOINT) zImage-MENF1: zvmlinux $(MKPREP) -pbp zvmlinux ../images/zImage.menf1 @@ -213,12 +221,6 @@ zImage.initrd-MENF1: zvmlinux.initrd $(MKPREP) -pbp zvmlinux.initrd ../images/zImage.initrd.menf1 -zImage-PCORE: zvmlinux - dd if=zvmlinux of=../images/zImage.pcore skip=64 bs=1k - -zImage.initrd-PCORE: zvmlinux.initrd - dd if=zvmlinux.initrd of=../images/zImage.initrd.pcore skip=64 bs=1k - zImage-PPLUS: zvmlinux $(MKPREP) $(MKBUGBOOT) $(MKPREP) -pbp zvmlinux ../images/zImage.pplus $(MKBUGBOOT) zvmlinux ../images/zImage.bugboot @@ -226,35 +228,5 @@ zImage.initrd-PPLUS: zvmlinux.initrd $(MKPREP) $(MKBUGBOOT) $(MKPREP) -pbp zvmlinux.initrd ../images/zImage.initrd.pplus $(MKBUGBOOT) zvmlinux.initrd ../images/zImage.initrd.bugboot - -zImage-SMON: zvmlinux - dd if=zvmlinux of=../images/zImage.gemini skip=64 bs=1k - -zImage.initrd-SMON: zvmlinux.initrd - dd if=zvmlinux.initrd of=../images/zImage.initrd.gemini skip=64 bs=1k - -zImage-SP: zvmlinux - mv zvmlinux ../images/zImage.sandpoint - -zImage.initrd-SP: zvmlinux.initrd - mv zvmlinux.initrd ../images/zImage.initrd.sandpoint - -zImage-SPRUCE: zvmlinux - $(MKTREE) zvmlinux ../images/zImage.spruce 0x800000 - -zImage.initrd-SPRUCE: zvmlinux.initrd - $(MKTREE) zvmlinux.initrd ../images/zImage.initrd.spruce 0x800000 - -zImage-TREE: zvmlinux - $(MKTREE) zvmlinux ../images/zImage.treeboot - -zImage.initrd-TREE: zvmlinux.initrd - $(MKTREE) zvmlinux.initrd ../images/zImage.initrd.treeboot - -zImage-ZX4500: zvmlinux - dd if=zvmlinux of=../images/zImage.zx4500 skip=64 bs=1k - -zImage.initrd-ZX4500: zvmlinux.initrd - dd if=zvmlinux.initrd of=../images/zImage.initrd.zx4500 skip=64 bs=1k include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/simple/embed_config.c b/arch/ppc/boot/simple/embed_config.c --- a/arch/ppc/boot/simple/embed_config.c Fri Sep 20 08:20:42 2002 +++ b/arch/ppc/boot/simple/embed_config.c Fri Sep 20 08:20:42 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - /* Board specific functions for those embedded 8xx boards that do * not have boot monitor support for board information. * @@ -14,7 +10,6 @@ #include #include #include -#include #ifdef CONFIG_8xx #include #endif @@ -22,6 +17,9 @@ #include #include #endif +#ifdef CONFIG_40x +#include +#endif /* For those boards that don't provide one. */ @@ -657,15 +655,65 @@ } #endif /* WILLOW */ -#ifdef CONFIG_TREEBOOT +void +embed_config(bd_t ** bdp) +{ + static const unsigned long line_size = 32; + static const unsigned long congruence_classes = 256; + unsigned long addr; + u_char *cp; + int i; + bd_t *bd; + + /* + * At one point, we were getting machine checks. Linux was not + * invalidating the data cache before it was enabled. The + * following code was added to do that. Soon after we had done + * that, we found the real reasons for the machine checks. I've + * run the kernel a few times with the following code + * temporarily removed without any apparent problems. However, + * I objdump'ed the kernel and boot code and found out that + * there were no other dccci's anywhere, so I put the code back + * in and have been reluctant to remove it. It seems safer to + * just leave it here. + */ + for (addr = 0; + addr < (congruence_classes * line_size); addr += line_size) { + __asm__("dccci 0,%0": :"b"(addr)); + } + + bd = &bdinfo; + *bdp = bd; + bd->bi_memsize = XPAR_DDR_0_SIZE; + bd->bi_intfreq = XPAR_CORE_CLOCK_FREQ_HZ; + bd->bi_busfreq = XPAR_PLB_CLOCK_FREQ_HZ; +} + +#ifdef CONFIG_IBM_OPENBIOS /* This could possibly work for all treeboot roms. */ -#if defined(CONFIG_ASH) +#if defined(CONFIG_ASH) || defined(CONFIG_BEECH) #define BOARD_INFO_VECTOR 0xFFF80B50 /* openbios 1.19 moved this vector down - armin */ #else -#define BOARD_INFO_VECTOR 0xFFFE0B50 +#define BOARD_INFO_VECTOR 0xFFFE0B50 #endif +#ifdef CONFIG_BEECH +static void +get_board_info(bd_t **bdp) +{ + typedef void (*PFV)(bd_t *bd); + ((PFV)(*(unsigned long *)BOARD_INFO_VECTOR))(*bdp); + return; +} + +void +embed_config(bd_t **bdp) +{ + *bdp = &bdinfo; + get_board_info(bdp); +} +#else /* !CONFIG_BEECH */ void embed_config(bd_t **bdp) { @@ -675,16 +723,13 @@ bd_t *(*get_board_info)(void) = (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); #if !defined(CONFIG_STB03xxx) - volatile emac_t *emacp; - emacp = (emac_t *)EMAC0_BASE; /* assume 1st emac - armin */ /* shut down the Ethernet controller that the boot rom * sometimes leaves running. */ mtdcr(DCRN_MALCR(DCRN_MAL_BASE), MALCR_MMSR); /* 1st reset MAL */ while (mfdcr(DCRN_MALCR(DCRN_MAL_BASE)) & MALCR_MMSR) {}; /* wait for the reset */ - emacp->em0mr0 = 0x20000000; /* then reset EMAC */ - eieio(); + out_be32(EMAC0_BASE,0x20000000); /* then reset EMAC */ #endif bd = &bdinfo; @@ -715,14 +760,15 @@ #endif } /* Yeah, this look weird, but on Redwood 4 they are - * different object in the structure. When RW5 uses - * OpenBIOS, it requires a special value. + * different object in the structure. Sincr Redwwood 5 + * and Redwood 6 use OpenBIOS, it requires a special value. */ -#ifdef CONFIG_REDWOOD_5 +#if defined(CONFIG_REDWOOD_5) || defined (CONFIG_REDWOOD_6) bd->bi_tbfreq = 27 * 1000 * 1000; #endif } -#endif +#endif /* CONFIG_BEECH */ +#endif /* CONFIG_IBM_OPENBIOS */ #ifdef CONFIG_EP405 #include @@ -749,6 +795,14 @@ writeb(0, UART0_IO_BASE + UART_LCR); } + /* We haven't seen actual problems with the EP405 leaving the + * EMAC running (as we have on Walnut). But the registers + * suggest it may not be left completely quiescent. Reset it + * just to be sure. */ + mtdcr(DCRN_MALCR(DCRN_MAL_BASE), MALCR_MMSR); /* 1st reset MAL */ + while (mfdcr(DCRN_MALCR(DCRN_MAL_BASE)) & MALCR_MMSR) {}; /* wait for the reset */ + out_be32(EMAC0_BASE,0x20000000); /* then reset EMAC */ + bd = &bdinfo; *bdp = bd; #if 1 @@ -808,6 +862,16 @@ bd = &bdinfo; *bdp = bd; + + for(i=0;i<8192;i+=32) { + __asm__("dccci 0,%0" :: "r" (i)); + } + __asm__("iccci 0,0"); + __asm__("sync;isync"); + + /* init ram for parity */ + memset(0, 0,0x400000); /* Lo memory */ + bd->bi_memsize = (32 * 1024 * 1024) ; bd->bi_intfreq = 133000000; //the internal clock is 133 MHz diff -Nru a/arch/ppc/boot/simple/gt64260_tty.c b/arch/ppc/boot/simple/gt64260_tty.c --- a/arch/ppc/boot/simple/gt64260_tty.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/boot/simple/gt64260_tty.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/boot/simple/gt64260_tty.c * * Bootloader version of the embedded MPSC/UART driver for the GT64260[A]. diff -Nru a/arch/ppc/boot/simple/head.S b/arch/ppc/boot/simple/head.S --- a/arch/ppc/boot/simple/head.S Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/boot/simple/head.S Fri Sep 20 08:20:47 2002 @@ -37,7 +37,7 @@ .globl start start: bl start_ -#ifdef CONFIG_TREEBOOT +#ifdef CONFIG_IBM_OPENBIOS /* The IBM "Tree" bootrom knows that the address of the bootrom * read only structure is 4 bytes after _start. */ @@ -73,7 +73,8 @@ #ifdef CONFIG_6xx bl disable_6xx_mmu bl disable_6xx_l1cache -#if defined(CONFIG_FORCE) || defined(CONFIG_K2) || defined(CONFIG_EV64260) +#if defined(CONFIG_FORCE) || defined(CONFIG_K2) \ + || defined(CONFIG_EV64260) || defined(CONFIG_PAL4) bl _setup_L2CR #endif #endif diff -Nru a/arch/ppc/boot/simple/iic.c b/arch/ppc/boot/simple/iic.c --- a/arch/ppc/boot/simple/iic.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/boot/simple/iic.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - /* Minimal support functions to read configuration from IIC EEPROMS * on MPC8xx boards. Originally written for RPGC RPX-Lite. * Dan Malek (dmalek@jlc.net). diff -Nru a/arch/ppc/boot/simple/m8260_tty.c b/arch/ppc/boot/simple/m8260_tty.c --- a/arch/ppc/boot/simple/m8260_tty.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/boot/simple/m8260_tty.c Fri Sep 20 08:20:44 2002 @@ -1,8 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - - /* Minimal serial functions needed to send messages out the serial * port on SMC1. */ diff -Nru a/arch/ppc/boot/simple/m8xx_tty.c b/arch/ppc/boot/simple/m8xx_tty.c --- a/arch/ppc/boot/simple/m8xx_tty.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/boot/simple/m8xx_tty.c Fri Sep 20 08:20:41 2002 @@ -1,8 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - - /* Minimal serial functions needed to send messages out the serial * port on the MBX console. * diff -Nru a/arch/ppc/boot/simple/misc-embedded.c b/arch/ppc/boot/simple/misc-embedded.c --- a/arch/ppc/boot/simple/misc-embedded.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/boot/simple/misc-embedded.c Fri Sep 20 08:20:43 2002 @@ -1,6 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - * * Originally adapted by Gary Thomas. Much additional work by * Cort Dougan . On top of that still more work by * Dan Malek . @@ -82,7 +80,7 @@ * initialize the serial console port. */ embed_config(&bp); -#ifdef CONFIG_SERIAL_CONSOLE +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) com_port = serial_init(0, bp); #endif diff -Nru a/arch/ppc/boot/simple/pci.c b/arch/ppc/boot/simple/pci.c --- a/arch/ppc/boot/simple/pci.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/boot/simple/pci.c Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ /* Stand alone funtions for QSpan Tundra support. */ #include diff -Nru a/arch/ppc/boot/simple/qspan_pci.c b/arch/ppc/boot/simple/qspan_pci.c --- a/arch/ppc/boot/simple/qspan_pci.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/boot/simple/qspan_pci.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * LinuxPPC arch/ppc/kernel/qspan_pci.c Dan Malek (dmalek@jlc.net) * * QSpan Motorola bus to PCI bridge. The config address register diff -Nru a/arch/ppc/boot/utils/addnote.c b/arch/ppc/boot/utils/addnote.c --- a/arch/ppc/boot/utils/addnote.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/boot/utils/addnote.c Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.addnote.c 1.7 05/18/01 15:17:23 cort - */ -/* * Program to hack in a PT_NOTE program header entry in an ELF file. * This is needed for OF on RS/6000s to load an image correctly. * Note that OF needs a program header entry for the note, not an diff -Nru a/arch/ppc/boot/utils/hack-coff.c b/arch/ppc/boot/utils/hack-coff.c --- a/arch/ppc/boot/utils/hack-coff.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/boot/utils/hack-coff.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.hack-coff.c 1.8 05/18/01 06:20:29 patch - */ -/* * hack-coff.c - hack the header of an xcoff file to fill in * a few fields needed by the Open Firmware xcoff loader on * Power Macs but not initialized by objcopy. diff -Nru a/arch/ppc/boot/utils/mknote.c b/arch/ppc/boot/utils/mknote.c --- a/arch/ppc/boot/utils/mknote.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/boot/utils/mknote.c Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.mknote.c 1.7 05/18/01 15:17:23 cort - */ -/* * Copyright (C) Cort Dougan 1999. * * This program is free software; you can redistribute it and/or diff -Nru a/arch/ppc/boot/utils/mkprep.c b/arch/ppc/boot/utils/mkprep.c --- a/arch/ppc/boot/utils/mkprep.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/boot/utils/mkprep.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.mkprep.c 1.7 05/18/01 06:20:29 patch - */ -/* * Makes a prep bootable image which can be dd'd onto * a disk device to make a bootdisk. Will take * as input a elf executable, strip off the header diff -Nru a/arch/ppc/boot/utils/mktree.c b/arch/ppc/boot/utils/mktree.c --- a/arch/ppc/boot/utils/mktree.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/boot/utils/mktree.c Fri Sep 20 08:20:44 2002 @@ -1,6 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - * * Makes a tree bootable image for IBM Evaluation boards. * Basically, just take a zImage, skip the ELF header, and stuff * a 32 byte header on the front. diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in --- a/arch/ppc/config.in Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/config.in Fri Sep 20 08:20:46 2002 @@ -1,5 +1,3 @@ -# BK Id: %F% %I% %G% %U% %#% -# # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # @@ -7,7 +5,6 @@ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y define_bool CONFIG_HAVE_DEC_LOCK y -define_bool CONFIG_GENERIC_ISA_DMA y mainmenu_name "Linux/PowerPC Kernel Configuration" @@ -30,9 +27,13 @@ if [ "$CONFIG_6xx" = "y" ]; then bool 'MPC8260 CPM Support' CONFIG_8260 + if [ "$CONFIG_8260" = "n" ]; then + define_bool CONFIG_GENERIC_ISA_DMA y + fi fi if [ "$CONFIG_POWER3" = "y" ]; then + define_bool CONFIG_GENERIC_ISA_DMA y define_bool CONFIG_PPC64BRIDGE y define_bool CONFIG_ALL_PPC y fi @@ -264,38 +265,6 @@ comment 'General setup' bool 'High memory support' CONFIG_HIGHMEM -bool 'Prompt for advanced kernel configuration options' CONFIG_ADVANCED_OPTIONS -if [ "$CONFIG_ADVANCED_OPTIONS" = "y" ]; then - if [ "$CONFIG_HIGHMEM" = "y" ]; then - bool " Set high memory pool address" CONFIG_HIGHMEM_START_BOOL - if [ "$CONFIG_HIGHMEM_START_BOOL" = "y" ]; then - hex " Virtual start address of high memory pool" CONFIG_HIGHMEM_START 0xfe000000 - fi - bool " Set maximum low memory" CONFIG_LOWMEM_SIZE_BOOL - if [ "$CONFIG_LOWMEM_SIZE_BOOL" = "y" ]; then - hex " Maximum low memory size (in bytes)" CONFIG_LOWMEM_SIZE 0x20000000 - fi - fi - - bool "Set custom kernel base address" CONFIG_KERNEL_START_BOOL - if [ "$CONFIG_KERNEL_START_BOOL" = "y" ]; then - hex " Virtual address of kernel base" CONFIG_KERNEL_START 0xc0000000 - fi - bool "Set custom user task size" CONFIG_TASK_SIZE_BOOL - if [ "$CONFIG_TASK_SIZE_BOOL" = "y" ]; then - hex " Size of user task space" CONFIG_TASK_SIZE 0x80000000 - fi - if [ "$CONFIG_8xx" = "y" ]; then - bool "Pinned Kernel TLBs (860 ONLY)" CONFIG_PIN_TLB - fi - if [ "$CONFIG_ALL_PPC" != "y" ]; then - bool "Set the boot link/load address" CONFIG_BOOT_LOAD_BOOL - if [ "$CONFIG_BOOT_LOAD_BOOL" = "y" ]; then - hex " Link/load address for booting" CONFIG_BOOT_LOAD 0x00400000 - fi - fi -fi - if [ "$CONFIG_ALL_PPC" = "y" ]; then bool 'Support for ISA-bus hardware' CONFIG_ISA else @@ -349,14 +318,6 @@ source drivers/parport/Config.in -if [ "$CONFIG_PPC_ISERIES" != "y" ]; then - if [ "$CONFIG_APUS" != "y" ]; then - tristate 'Support for /dev/rtc' CONFIG_PPC_RTC - else - bool 'Generic /dev/rtc emulation' CONFIG_GEN_RTC - fi -fi - if [ "$CONFIG_ALL_PPC" = "y" -a "$CONFIG_POWER3" = "n" ] ; then bool 'Workarounds for PPC601 bugs' CONFIG_PPC601_SYNC_FIX fi @@ -381,11 +342,7 @@ define_bool CONFIG_FB_CONSOLE y define_bool CONFIG_AMIGA y define_bool CONFIG_ZORRO y - define_bool CONFIG_AMIGAMOUSE y define_bool CONFIG_ABSTRACT_CONSOLE y - define_bool CONFIG_FB y - define_bool CONFIG_MOUSE y - define_bool CONFIG_BUSMOUSE y define_bool CONFIG_APUS_FAST_EXCEPT y if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -412,8 +369,43 @@ bool '/proc/hardware support' CONFIG_PROC_HARDWARE source drivers/zorro/Config.in fi +endmenu + +mainmenu_option next_comment +comment 'Advanced setup' +bool 'Prompt for advanced kernel configuration options' CONFIG_ADVANCED_OPTIONS +if [ "$CONFIG_ADVANCED_OPTIONS" = "y" ]; then + if [ "$CONFIG_HIGHMEM" = "y" ]; then + bool " Set high memory pool address" CONFIG_HIGHMEM_START_BOOL + if [ "$CONFIG_HIGHMEM_START_BOOL" = "y" ]; then + hex " Virtual start address of high memory pool" CONFIG_HIGHMEM_START 0xfe000000 + fi + bool " Set maximum low memory" CONFIG_LOWMEM_SIZE_BOOL + if [ "$CONFIG_LOWMEM_SIZE_BOOL" = "y" ]; then + hex " Maximum low memory size (in bytes)" CONFIG_LOWMEM_SIZE 0x20000000 + fi + fi + bool "Set custom kernel base address" CONFIG_KERNEL_START_BOOL + if [ "$CONFIG_KERNEL_START_BOOL" = "y" ]; then + hex " Virtual address of kernel base" CONFIG_KERNEL_START 0xc0000000 + fi + bool "Set custom user task size" CONFIG_TASK_SIZE_BOOL + if [ "$CONFIG_TASK_SIZE_BOOL" = "y" ]; then + hex " Size of user task space" CONFIG_TASK_SIZE 0x80000000 + fi + if [ "$CONFIG_8xx" = "y" ]; then + bool "Pinned Kernel TLBs (860 ONLY)" CONFIG_PIN_TLB + fi + if [ "$CONFIG_ALL_PPC" != "y" ]; then + bool "Set the boot link/load address" CONFIG_BOOT_LOAD_BOOL + if [ "$CONFIG_BOOT_LOAD_BOOL" = "y" ]; then + hex " Link/load address for booting" CONFIG_BOOT_LOAD 0x00400000 + fi + fi +fi endmenu + source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in @@ -467,14 +459,6 @@ source drivers/isdn/Config.in mainmenu_option next_comment -comment 'Old CD-ROM drivers (not SCSI, not IDE)' -bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI -if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then - source drivers/cdrom/Config.in -fi -endmenu - -mainmenu_option next_comment comment 'Console drivers' if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then bool 'VGA text console' CONFIG_VGA_CONSOLE @@ -504,6 +488,14 @@ if [ "$CONFIG_VIOCD" = "y" ]; then define_bool CONFIG_CD_NO_IDESCSI y define_bool CONFIG_BLK_DEV_IDECD y + fi + endmenu +else + mainmenu_option next_comment + comment 'Old CD-ROM drivers (not SCSI, not IDE)' + bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI + if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in fi endmenu fi diff -Nru a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile --- a/arch/ppc/kernel/Makefile Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/kernel/Makefile Fri Sep 20 08:20:47 2002 @@ -1,5 +1,3 @@ -# BK Id: %F% %I% %G% %U% %#% -# # # Makefile for the linux kernel. # diff -Nru a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c --- a/arch/ppc/kernel/align.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/kernel/align.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * align.c - handle alignment exceptions for the Power PC. * * Copyright (c) 1996 Paul Mackerras diff -Nru a/arch/ppc/kernel/bitops.c b/arch/ppc/kernel/bitops.c --- a/arch/ppc/kernel/bitops.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/kernel/bitops.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Copyright (C) 1996 Paul Mackerras. */ diff -Nru a/arch/ppc/kernel/btext.c b/arch/ppc/kernel/btext.c --- a/arch/ppc/kernel/btext.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/kernel/btext.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Procedures for drawing on the screen early on in the boot process. * * Benjamin Herrenschmidt diff -Nru a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c --- a/arch/ppc/kernel/cputable.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/cputable.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/kernel/cputable.c * * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S --- a/arch/ppc/kernel/entry.S Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/kernel/entry.S Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Rewritten by Cort Dougan (cort@fsmlabs.com) for PReP diff -Nru a/arch/ppc/kernel/find_name.c b/arch/ppc/kernel/find_name.c --- a/arch/ppc/kernel/find_name.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/kernel/find_name.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.find_name.c 1.5 05/17/01 18:14:21 cort - */ #include #include #include diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S --- a/arch/ppc/kernel/head.S Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/kernel/head.S Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * diff -Nru a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S --- a/arch/ppc/kernel/head_8xx.S Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/head_8xx.S Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/kernel/except_8xx.S * * PowerPC version diff -Nru a/arch/ppc/kernel/i8259.c b/arch/ppc/kernel/i8259.c --- a/arch/ppc/kernel/i8259.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/i8259.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - #include #include #include diff -Nru a/arch/ppc/kernel/iSeries_asm.h b/arch/ppc/kernel/iSeries_asm.h --- a/arch/ppc/kernel/iSeries_asm.h Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/iSeries_asm.h Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/kernel/iSeries_asm.h * * Definitions used by various bits of low-level assembly code on iSeries. diff -Nru a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c --- a/arch/ppc/kernel/idle.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/kernel/idle.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. * diff -Nru a/arch/ppc/kernel/indirect_pci.c b/arch/ppc/kernel/indirect_pci.c --- a/arch/ppc/kernel/indirect_pci.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/kernel/indirect_pci.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Support for indirect PCI bridges. * * Copyright (C) 1998 Gabriel Paubert. diff -Nru a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c --- a/arch/ppc/kernel/irq.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/kernel/irq.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/kernel/irq.c * * Derived from arch/i386/kernel/irq.c diff -Nru a/arch/ppc/kernel/m8260_setup.c b/arch/ppc/kernel/m8260_setup.c --- a/arch/ppc/kernel/m8260_setup.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/m8260_setup.c Fri Sep 20 08:20:46 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * linux/arch/ppc/kernel/setup.c + * arch/ppc/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds * Adapted from 'alpha' version by Gary Thomas diff -Nru a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c --- a/arch/ppc/kernel/m8xx_setup.c Fri Sep 20 08:20:45 2002 +++ b/arch/ppc/kernel/m8xx_setup.c Fri Sep 20 08:20:45 2002 @@ -1,7 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - * - * linux/arch/ppc/kernel/setup.c + * arch/ppc/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds * Adapted from 'alpha' version by Gary Thomas diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S --- a/arch/ppc/kernel/misc.S Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/kernel/misc.S Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * This file contains miscellaneous low-level functions. * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * diff -Nru a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c --- a/arch/ppc/kernel/mk_defs.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/mk_defs.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * This program is used to generate definitions needed by * assembly language modules. * diff -Nru a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c --- a/arch/ppc/kernel/open_pic.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/kernel/open_pic.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling * * Copyright (C) 1997 Geert Uytterhoeven diff -Nru a/arch/ppc/kernel/open_pic_defs.h b/arch/ppc/kernel/open_pic_defs.h --- a/arch/ppc/kernel/open_pic_defs.h Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/kernel/open_pic_defs.h Fri Sep 20 08:20:47 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * linux/openpic.h -- OpenPIC definitions + * arch/ppc/kernel/open_pic_defs.h -- OpenPIC definitions * * Copyright (C) 1997 Geert Uytterhoeven * diff -Nru a/arch/ppc/kernel/pci-dma.c b/arch/ppc/kernel/pci-dma.c --- a/arch/ppc/kernel/pci-dma.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/kernel/pci-dma.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Copyright (C) 2000 Ani Joshi * * diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c --- a/arch/ppc/kernel/pci.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/pci.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Common pmac/prep/chrp pci routines. -- Cort */ diff -Nru a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c --- a/arch/ppc/kernel/ppc-stub.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/kernel/ppc-stub.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * ppc-stub.c: KGDB support for the Linux kernel. * * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC diff -Nru a/arch/ppc/kernel/ppc8260_pic.c b/arch/ppc/kernel/ppc8260_pic.c --- a/arch/ppc/kernel/ppc8260_pic.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/ppc8260_pic.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - #include #include #include diff -Nru a/arch/ppc/kernel/ppc8260_pic.h b/arch/ppc/kernel/ppc8260_pic.h --- a/arch/ppc/kernel/ppc8260_pic.h Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/kernel/ppc8260_pic.h Fri Sep 20 08:20:48 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - #ifndef _PPC_KERNEL_PPC8260_H #define _PPC_KERNEL_PPC8260_H diff -Nru a/arch/ppc/kernel/ppc8xx_pic.c b/arch/ppc/kernel/ppc8xx_pic.c --- a/arch/ppc/kernel/ppc8xx_pic.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/kernel/ppc8xx_pic.c Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #include #include #include diff -Nru a/arch/ppc/kernel/ppc8xx_pic.h b/arch/ppc/kernel/ppc8xx_pic.h --- a/arch/ppc/kernel/ppc8xx_pic.h Fri Sep 20 08:20:45 2002 +++ b/arch/ppc/kernel/ppc8xx_pic.h Fri Sep 20 08:20:45 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef _PPC_KERNEL_PPC8xx_H #define _PPC_KERNEL_PPC8xx_H diff -Nru a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c --- a/arch/ppc/kernel/ppc_htab.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/kernel/ppc_htab.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.ppc_htab.c 1.19 10/16/01 15:58:42 trini - */ -/* * PowerPC hash table management proc entry. Will show information * about the current hash table and will allow changes to it. * @@ -118,10 +115,8 @@ unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0; int n = 0; #ifdef CONFIG_PPC_STD_MMU - int valid; - unsigned int kptes = 0, uptes = 0, zombie_ptes = 0; + unsigned int kptes = 0, uptes = 0; PTE *ptr; - struct task_struct *p; #endif /* CONFIG_PPC_STD_MMU */ char buffer[512]; @@ -154,32 +149,18 @@ goto return_string; } - for ( ptr = Hash ; ptr < Hash_end ; ptr++) - { - unsigned int ctx, mctx, vsid; + for (ptr = Hash; ptr < Hash_end; ptr++) { + unsigned int mctx, vsid; if (!ptr->v) continue; - /* make sure someone is using this context/vsid */ - /* first undo the esid skew */ + /* undo the esid skew */ vsid = ptr->vsid; mctx = ((vsid - (vsid & 0xf) * 0x111) >> 4) & 0xfffff; - if (mctx == 0) { + if (mctx == 0) kptes++; - continue; - } - /* now undo the context skew; 801921 * 897 == 1 mod 2^20 */ - ctx = (mctx * 801921) & 0xfffff; - valid = 0; - for_each_task(p) { - if (p->mm != NULL && ctx == p->mm->context) { - valid = 1; - uptes++; - break; - } - } - if (!valid) - zombie_ptes++; + else + uptes++; } n += sprintf( buffer + n, @@ -190,7 +171,6 @@ "Entries\t\t: %lu\n" "User ptes\t: %u\n" "Kernel ptes\t: %u\n" - "Zombies\t\t: %u\n" "Percent full\t: %lu%%\n", (unsigned long)(Hash_size>>10), (Hash_size/(sizeof(PTE)*8)), @@ -198,7 +178,6 @@ Hash_size/sizeof(PTE), uptes, kptes, - zombie_ptes, ((kptes+uptes)*100) / (Hash_size/sizeof(PTE)) ); @@ -212,7 +191,7 @@ primary_pteg_full, htab_evicts); return_string: #endif /* CONFIG_PPC_STD_MMU */ - + n += sprintf( buffer + n, "Non-error misses: %lu\n" "Error misses\t: %lu\n", diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c --- a/arch/ppc/kernel/ppc_ksyms.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/kernel/ppc_ksyms.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #include #include #include diff -Nru a/arch/ppc/kernel/prep_nvram.c b/arch/ppc/kernel/prep_nvram.c --- a/arch/ppc/kernel/prep_nvram.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/prep_nvram.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/kernel/prep_nvram.c * * Copyright (C) 1998 Corey Minyard diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c --- a/arch/ppc/kernel/process.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/process.c Fri Sep 20 08:20:46 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * linux/arch/ppc/kernel/process.c + * arch/ppc/kernel/process.c * * Derived from "arch/i386/kernel/process.c" * Copyright (C) 1995 Linus Torvalds diff -Nru a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c --- a/arch/ppc/kernel/prom.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/kernel/prom.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. * diff -Nru a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c --- a/arch/ppc/kernel/ptrace.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/kernel/ptrace.c Fri Sep 20 08:20:44 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * linux/arch/ppc/kernel/ptrace.c + * arch/ppc/kernel/ptrace.c * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) diff -Nru a/arch/ppc/kernel/qspan_pci.c b/arch/ppc/kernel/qspan_pci.c --- a/arch/ppc/kernel/qspan_pci.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/kernel/qspan_pci.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * QSpan pci routines. * Most 8xx boards use the QSpan PCI bridge. The config address register * is located 0x500 from the base of the bridge control/status registers. diff -Nru a/arch/ppc/kernel/semaphore.c b/arch/ppc/kernel/semaphore.c --- a/arch/ppc/kernel/semaphore.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/kernel/semaphore.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * PowerPC-specific semaphore code. * * Copyright (C) 1999 Cort Dougan diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c --- a/arch/ppc/kernel/setup.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/kernel/setup.c Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Common prep/pmac/chrp boot and setup code. */ diff -Nru a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c --- a/arch/ppc/kernel/signal.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/signal.c Fri Sep 20 08:20:46 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * linux/arch/ppc/kernel/signal.c + * arch/ppc/kernel/signal.c * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) diff -Nru a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c --- a/arch/ppc/kernel/smp.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/kernel/smp.c Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Smp support for ppc. * * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great diff -Nru a/arch/ppc/kernel/softemu8xx.c b/arch/ppc/kernel/softemu8xx.c --- a/arch/ppc/kernel/softemu8xx.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/kernel/softemu8xx.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Software emulation of some PPC instructions for the 8xx core. * * Copyright (C) 1998 Dan Malek (dmalek@jlc.net) diff -Nru a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c --- a/arch/ppc/kernel/syscalls.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/kernel/syscalls.c Fri Sep 20 08:20:48 2002 @@ -1,8 +1,5 @@ /* - * BK Id: SCCS/s.syscalls.c 1.11 10/16/01 15:58:42 trini - */ -/* - * linux/arch/ppc/kernel/sys_ppc.c + * arch/ppc/kernel/sys_ppc.c * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) diff -Nru a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c --- a/arch/ppc/kernel/time.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/kernel/time.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Common time routines among all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge diff -Nru a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c --- a/arch/ppc/kernel/traps.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/kernel/traps.c Fri Sep 20 08:20:43 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * linux/arch/ppc/kernel/traps.c + * arch/ppc/kernel/traps.c * * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * diff -Nru a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile --- a/arch/ppc/lib/Makefile Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/lib/Makefile Fri Sep 20 08:20:41 2002 @@ -1,5 +1,3 @@ -# BK Id: SCCS/s.Makefile 1.10 11/08/01 07:57:40 paulus -# # # Makefile for ppc-specific library files.. # diff -Nru a/arch/ppc/lib/checksum.S b/arch/ppc/lib/checksum.S --- a/arch/ppc/lib/checksum.S Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/lib/checksum.S Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * This file contains assembly-language implementations * of IP-style 1's complement checksum routines. * diff -Nru a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c --- a/arch/ppc/lib/locks.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/lib/locks.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Locks for smp ppc * * Written by Cort Dougan (cort@cs.nmt.edu) diff -Nru a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c --- a/arch/ppc/lib/strcase.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/lib/strcase.c Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.strcase.c 1.5 05/17/01 18:14:22 cort - */ #include int strcasecmp(const char *s1, const char *s2) diff -Nru a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S --- a/arch/ppc/lib/string.S Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/lib/string.S Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * String handling functions for PowerPC. * * Copyright (C) 1996 Paul Mackerras. diff -Nru a/arch/ppc/math-emu/Makefile b/arch/ppc/math-emu/Makefile --- a/arch/ppc/math-emu/Makefile Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/math-emu/Makefile Fri Sep 20 08:20:47 2002 @@ -1,9 +1,3 @@ -# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:22 cort -# -# -# -# - O_TARGET := math-emu.o obj-y := math.o fmr.o lfd.o stfd.o diff -Nru a/arch/ppc/math-emu/double.h b/arch/ppc/math-emu/double.h --- a/arch/ppc/math-emu/double.h Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/math-emu/double.h Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.double.h 1.5 05/17/01 18:14:22 cort - */ -/* * Definitions for IEEE Double Precision */ diff -Nru a/arch/ppc/math-emu/fabs.c b/arch/ppc/math-emu/fabs.c --- a/arch/ppc/math-emu/fabs.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/math-emu/fabs.c Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fabs.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fadd.c b/arch/ppc/math-emu/fadd.c --- a/arch/ppc/math-emu/fadd.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/math-emu/fadd.c Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fadd.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fadds.c b/arch/ppc/math-emu/fadds.c --- a/arch/ppc/math-emu/fadds.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/math-emu/fadds.c Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fadds.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fcmpo.c b/arch/ppc/math-emu/fcmpo.c --- a/arch/ppc/math-emu/fcmpo.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/math-emu/fcmpo.c Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fcmpo.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fcmpu.c b/arch/ppc/math-emu/fcmpu.c --- a/arch/ppc/math-emu/fcmpu.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/math-emu/fcmpu.c Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fcmpu.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fctiw.c b/arch/ppc/math-emu/fctiw.c --- a/arch/ppc/math-emu/fctiw.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/math-emu/fctiw.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fctiw.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fctiwz.c b/arch/ppc/math-emu/fctiwz.c --- a/arch/ppc/math-emu/fctiwz.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/math-emu/fctiwz.c Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fctiwz.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fdiv.c b/arch/ppc/math-emu/fdiv.c --- a/arch/ppc/math-emu/fdiv.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/math-emu/fdiv.c Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fdiv.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fdivs.c b/arch/ppc/math-emu/fdivs.c --- a/arch/ppc/math-emu/fdivs.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/math-emu/fdivs.c Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fdivs.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fmadd.c b/arch/ppc/math-emu/fmadd.c --- a/arch/ppc/math-emu/fmadd.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/math-emu/fmadd.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fmadd.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fmadds.c b/arch/ppc/math-emu/fmadds.c --- a/arch/ppc/math-emu/fmadds.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/math-emu/fmadds.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fmadds.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fmr.c b/arch/ppc/math-emu/fmr.c --- a/arch/ppc/math-emu/fmr.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/math-emu/fmr.c Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fmr.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fmsub.c b/arch/ppc/math-emu/fmsub.c --- a/arch/ppc/math-emu/fmsub.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/math-emu/fmsub.c Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fmsub.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fmsubs.c b/arch/ppc/math-emu/fmsubs.c --- a/arch/ppc/math-emu/fmsubs.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/math-emu/fmsubs.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fmsubs.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fmul.c b/arch/ppc/math-emu/fmul.c --- a/arch/ppc/math-emu/fmul.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/math-emu/fmul.c Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fmul.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fmuls.c b/arch/ppc/math-emu/fmuls.c --- a/arch/ppc/math-emu/fmuls.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/math-emu/fmuls.c Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fmuls.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fnabs.c b/arch/ppc/math-emu/fnabs.c --- a/arch/ppc/math-emu/fnabs.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/math-emu/fnabs.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fnabs.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fneg.c b/arch/ppc/math-emu/fneg.c --- a/arch/ppc/math-emu/fneg.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/math-emu/fneg.c Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fneg.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fnmadd.c b/arch/ppc/math-emu/fnmadd.c --- a/arch/ppc/math-emu/fnmadd.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/math-emu/fnmadd.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fnmadd.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fnmadds.c b/arch/ppc/math-emu/fnmadds.c --- a/arch/ppc/math-emu/fnmadds.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/math-emu/fnmadds.c Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fnmadds.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fnmsub.c b/arch/ppc/math-emu/fnmsub.c --- a/arch/ppc/math-emu/fnmsub.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/math-emu/fnmsub.c Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fnmsub.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fnmsubs.c b/arch/ppc/math-emu/fnmsubs.c --- a/arch/ppc/math-emu/fnmsubs.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/math-emu/fnmsubs.c Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fnmsubs.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fres.c b/arch/ppc/math-emu/fres.c --- a/arch/ppc/math-emu/fres.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/math-emu/fres.c Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fres.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/frsp.c b/arch/ppc/math-emu/frsp.c --- a/arch/ppc/math-emu/frsp.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/math-emu/frsp.c Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.frsp.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/frsqrte.c b/arch/ppc/math-emu/frsqrte.c --- a/arch/ppc/math-emu/frsqrte.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/math-emu/frsqrte.c Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.frsqrte.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fsel.c b/arch/ppc/math-emu/fsel.c --- a/arch/ppc/math-emu/fsel.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/math-emu/fsel.c Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fsel.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fsqrt.c b/arch/ppc/math-emu/fsqrt.c --- a/arch/ppc/math-emu/fsqrt.c Fri Sep 20 08:20:42 2002 +++ b/arch/ppc/math-emu/fsqrt.c Fri Sep 20 08:20:42 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fsqrt.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fsqrts.c b/arch/ppc/math-emu/fsqrts.c --- a/arch/ppc/math-emu/fsqrts.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/math-emu/fsqrts.c Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fsqrts.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fsub.c b/arch/ppc/math-emu/fsub.c --- a/arch/ppc/math-emu/fsub.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/math-emu/fsub.c Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fsub.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/fsubs.c b/arch/ppc/math-emu/fsubs.c --- a/arch/ppc/math-emu/fsubs.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/math-emu/fsubs.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fsubs.c 1.6 05/17/01 18:14:22 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/lfd.c b/arch/ppc/math-emu/lfd.c --- a/arch/ppc/math-emu/lfd.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/math-emu/lfd.c Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.lfd.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/lfs.c b/arch/ppc/math-emu/lfs.c --- a/arch/ppc/math-emu/lfs.c Fri Sep 20 08:20:49 2002 +++ b/arch/ppc/math-emu/lfs.c Fri Sep 20 08:20:49 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.lfs.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/math.c b/arch/ppc/math-emu/math.c --- a/arch/ppc/math-emu/math.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/math-emu/math.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.math.c 1.6 05/17/01 18:14:23 cort - */ -/* * arch/ppc/math-emu/math.c * * Copyright (C) 1999 Eddie C. Dost (ecd@atecom.com) diff -Nru a/arch/ppc/math-emu/mcrfs.c b/arch/ppc/math-emu/mcrfs.c --- a/arch/ppc/math-emu/mcrfs.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/math-emu/mcrfs.c Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.mcrfs.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/mffs.c b/arch/ppc/math-emu/mffs.c --- a/arch/ppc/math-emu/mffs.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/math-emu/mffs.c Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.mffs.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/mtfsb0.c b/arch/ppc/math-emu/mtfsb0.c --- a/arch/ppc/math-emu/mtfsb0.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/math-emu/mtfsb0.c Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.mtfsb0.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/mtfsb1.c b/arch/ppc/math-emu/mtfsb1.c --- a/arch/ppc/math-emu/mtfsb1.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/math-emu/mtfsb1.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.mtfsb1.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/mtfsf.c b/arch/ppc/math-emu/mtfsf.c --- a/arch/ppc/math-emu/mtfsf.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/math-emu/mtfsf.c Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.mtfsf.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/mtfsfi.c b/arch/ppc/math-emu/mtfsfi.c --- a/arch/ppc/math-emu/mtfsfi.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/math-emu/mtfsfi.c Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.mtfsfi.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/op-1.h b/arch/ppc/math-emu/op-1.h --- a/arch/ppc/math-emu/op-1.h Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/math-emu/op-1.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.op-1.h 1.5 05/17/01 18:14:23 cort - */ -/* * Basic one-word fraction declaration and manipulation. */ diff -Nru a/arch/ppc/math-emu/op-2.h b/arch/ppc/math-emu/op-2.h --- a/arch/ppc/math-emu/op-2.h Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/math-emu/op-2.h Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.op-2.h 1.5 05/17/01 18:14:23 cort - */ -/* * Basic two-word fraction declaration and manipulation. */ diff -Nru a/arch/ppc/math-emu/op-4.h b/arch/ppc/math-emu/op-4.h --- a/arch/ppc/math-emu/op-4.h Fri Sep 20 08:20:45 2002 +++ b/arch/ppc/math-emu/op-4.h Fri Sep 20 08:20:45 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.op-4.h 1.5 05/17/01 18:14:23 cort - */ -/* * Basic four-word fraction declaration and manipulation. * * When adding quadword support for 32 bit machines, we need diff -Nru a/arch/ppc/math-emu/op-common.h b/arch/ppc/math-emu/op-common.h --- a/arch/ppc/math-emu/op-common.h Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/math-emu/op-common.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: SCCS/s.op-common.h 1.5 05/17/01 18:14:23 cort - */ - #define _FP_DECL(wc, X) \ _FP_I_TYPE X##_c, X##_s, X##_e; \ _FP_FRAC_DECL_##wc(X) diff -Nru a/arch/ppc/math-emu/sfp-machine.h b/arch/ppc/math-emu/sfp-machine.h --- a/arch/ppc/math-emu/sfp-machine.h Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/math-emu/sfp-machine.h Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.sfp-machine.h 1.5 05/17/01 18:14:23 cort - */ /* Machine-dependent software floating-point definitions. PPC version. Copyright (C) 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. diff -Nru a/arch/ppc/math-emu/single.h b/arch/ppc/math-emu/single.h --- a/arch/ppc/math-emu/single.h Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/math-emu/single.h Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.single.h 1.5 05/17/01 18:14:23 cort - */ -/* * Definitions for IEEE Single Precision */ diff -Nru a/arch/ppc/math-emu/soft-fp.h b/arch/ppc/math-emu/soft-fp.h --- a/arch/ppc/math-emu/soft-fp.h Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/math-emu/soft-fp.h Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.soft-fp.h 1.5 05/17/01 18:14:23 cort - */ #ifndef SOFT_FP_H #define SOFT_FP_H diff -Nru a/arch/ppc/math-emu/stfd.c b/arch/ppc/math-emu/stfd.c --- a/arch/ppc/math-emu/stfd.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/math-emu/stfd.c Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.stfd.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/stfiwx.c b/arch/ppc/math-emu/stfiwx.c --- a/arch/ppc/math-emu/stfiwx.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/math-emu/stfiwx.c Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.stfiwx.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/stfs.c b/arch/ppc/math-emu/stfs.c --- a/arch/ppc/math-emu/stfs.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/math-emu/stfs.c Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.stfs.c 1.6 05/17/01 18:14:23 cort - */ #include #include #include diff -Nru a/arch/ppc/math-emu/types.c b/arch/ppc/math-emu/types.c --- a/arch/ppc/math-emu/types.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/math-emu/types.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: SCCS/s.types.c 1.5 05/17/01 18:14:23 cort - */ - #include "soft-fp.h" #include "double.h" #include "single.h" diff -Nru a/arch/ppc/math-emu/udivmodti4.c b/arch/ppc/math-emu/udivmodti4.c --- a/arch/ppc/math-emu/udivmodti4.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/math-emu/udivmodti4.c Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.udivmodti4.c 1.5 05/17/01 18:14:23 cort - */ /* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */ #include "soft-fp.h" diff -Nru a/arch/ppc/mm/4xx_mmu.c b/arch/ppc/mm/4xx_mmu.c --- a/arch/ppc/mm/4xx_mmu.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/mm/4xx_mmu.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * This file contains the routines for initializing the MMU * on the 4xx series of chips. * -- paulus diff -Nru a/arch/ppc/mm/Makefile b/arch/ppc/mm/Makefile --- a/arch/ppc/mm/Makefile Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/mm/Makefile Fri Sep 20 08:20:43 2002 @@ -1,5 +1,3 @@ -# BK Id: %F% %I% %G% %U% %#% -# # # Makefile for the linux ppc-specific parts of the memory manager. # diff -Nru a/arch/ppc/mm/cachemap.c b/arch/ppc/mm/cachemap.c --- a/arch/ppc/mm/cachemap.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/mm/cachemap.c Fri Sep 20 08:20:48 2002 @@ -1,10 +1,8 @@ /* - * BK Id: %F% %I% %G% %U% %#% - * * PowerPC version derived from arch/arm/mm/consistent.c * Copyright (C) 2001 Dan Malek (dmalek@jlc.net) * - * linux/arch/arm/mm/consistent.c + * arch/arm/mm/consistent.c * * Copyright (C) 2000 Russell King * diff -Nru a/arch/ppc/mm/extable.c b/arch/ppc/mm/extable.c --- a/arch/ppc/mm/extable.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/mm/extable.c Fri Sep 20 08:20:47 2002 @@ -1,10 +1,7 @@ /* - * BK Id: SCCS/s.extable.c 1.5 05/17/01 18:14:23 cort - */ -/* - * linux/arch/ppc/mm/extable.c + * arch/ppc/mm/extable.c * - * from linux/arch/i386/mm/extable.c + * from arch/i386/mm/extable.c */ #include diff -Nru a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c --- a/arch/ppc/mm/fault.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/mm/fault.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/mm/fault.c * * PowerPC version diff -Nru a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S --- a/arch/ppc/mm/hashtable.S Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/mm/hashtable.S Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/kernel/hashtable.S * * $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $ diff -Nru a/arch/ppc/mm/iSeries_mmu.c b/arch/ppc/mm/iSeries_mmu.c --- a/arch/ppc/mm/iSeries_mmu.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/mm/iSeries_mmu.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Procedures for MMU handling on iSeries systems, where we * have to call the hypervisor to change things in the hash * table. diff -Nru a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c --- a/arch/ppc/mm/init.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/mm/init.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * diff -Nru a/arch/ppc/mm/mem_pieces.c b/arch/ppc/mm/mem_pieces.c --- a/arch/ppc/mm/mem_pieces.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/mm/mem_pieces.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Copyright (c) 1996 Paul Mackerras * Changes to accomodate Power Macintoshes. * Cort Dougan diff -Nru a/arch/ppc/mm/mem_pieces.h b/arch/ppc/mm/mem_pieces.h --- a/arch/ppc/mm/mem_pieces.h Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/mm/mem_pieces.h Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.mem_pieces.h 1.5 05/17/01 18:14:23 cort - */ -/* * Copyright (c) 1996 Paul Mackerras * Changes to accomodate Power Macintoshes. * Cort Dougan diff -Nru a/arch/ppc/mm/mmu_context.c b/arch/ppc/mm/mmu_context.c --- a/arch/ppc/mm/mmu_context.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/mm/mmu_context.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * This file contains the routines for handling the MMU on those * PowerPC implementations where the MMU substantially follows the * architecture specification. This includes the 6xx, 7xx, 7xxx, diff -Nru a/arch/ppc/mm/mmu_decl.h b/arch/ppc/mm/mmu_decl.h --- a/arch/ppc/mm/mmu_decl.h Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/mm/mmu_decl.h Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Declarations of procedures and variables shared between files * in arch/ppc/mm/. * diff -Nru a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c --- a/arch/ppc/mm/pgtable.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/mm/pgtable.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * This file contains the routines setting up the linux page tables. * -- paulus * diff -Nru a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c --- a/arch/ppc/mm/ppc_mmu.c Fri Sep 20 08:20:42 2002 +++ b/arch/ppc/mm/ppc_mmu.c Fri Sep 20 08:20:42 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * This file contains the routines for handling the MMU on those * PowerPC implementations where the MMU substantially follows the * architecture specification. This includes the 6xx, 7xx, 7xxx, diff -Nru a/arch/ppc/mm/tlb.c b/arch/ppc/mm/tlb.c --- a/arch/ppc/mm/tlb.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/mm/tlb.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * This file contains the routines for TLB flushing. * On machines where the MMU uses a hash table to store virtual to * physical translations, these routines flush entries from the diff -Nru a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile --- a/arch/ppc/platforms/Makefile Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/platforms/Makefile Fri Sep 20 08:20:48 2002 @@ -1,5 +1,3 @@ -# BK Id: %F% %I% %G% %U% %#% -# # # Makefile for the linux kernel. # diff -Nru a/arch/ppc/platforms/apus_pci.c b/arch/ppc/platforms/apus_pci.c --- a/arch/ppc/platforms/apus_pci.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/apus_pci.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Copyright (C) Michel Dänzer * * APUS PCI routines. diff -Nru a/arch/ppc/platforms/apus_pci.h b/arch/ppc/platforms/apus_pci.h --- a/arch/ppc/platforms/apus_pci.h Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/platforms/apus_pci.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer * driver. * diff -Nru a/arch/ppc/platforms/apus_setup.c b/arch/ppc/platforms/apus_setup.c --- a/arch/ppc/platforms/apus_setup.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/apus_setup.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/platforms/apus_setup.c * * Copyright (C) 1998, 1999 Jesper Skov diff -Nru a/arch/ppc/platforms/bseip.h b/arch/ppc/platforms/bseip.h --- a/arch/ppc/platforms/bseip.h Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/platforms/bseip.h Fri Sep 20 08:20:41 2002 @@ -1,8 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ - -/* * A collection of structures, addresses, and values associated with * the Bright Star Engineering ip-Engine board. Copied from the MBX stuff. * diff -Nru a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c --- a/arch/ppc/platforms/chrp_pci.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/platforms/chrp_pci.c Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * CHRP pci routines. */ diff -Nru a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c --- a/arch/ppc/platforms/chrp_setup.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/platforms/chrp_setup.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/platforms/setup.c * * Copyright (C) 1995 Linus Torvalds diff -Nru a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c --- a/arch/ppc/platforms/chrp_smp.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/platforms/chrp_smp.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Smp support for CHRP machines. * * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great diff -Nru a/arch/ppc/platforms/chrp_time.c b/arch/ppc/platforms/chrp_time.c --- a/arch/ppc/platforms/chrp_time.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/platforms/chrp_time.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/platforms/chrp_time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds diff -Nru a/arch/ppc/platforms/ep405.c b/arch/ppc/platforms/ep405.c --- a/arch/ppc/platforms/ep405.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/platforms/ep405.c Fri Sep 20 08:20:41 2002 @@ -1,19 +1,8 @@ /* - * BK Id: %F% %I% %G% %U% %#% - * * Copyright 2001 MontaVista Software Inc. * * - * Not much needed for the Embedded Planet 405gp board - * - * History: 11/09/2001 - armin - * added board_init to add in additional instuctions needed during platfrom_init - * cleaned up map_irq. - * - * 1/22/2002 - Armin - * converted pci to ocp - * - + * Not much is needed for the Embedded Planet 405gp board * */ #include diff -Nru a/arch/ppc/platforms/error_log.c b/arch/ppc/platforms/error_log.c --- a/arch/ppc/platforms/error_log.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/error_log.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort - */ -/* * arch/ppc/kernel/error_log.c * * Copyright (c) 2000 Tilmann Bitterberg diff -Nru a/arch/ppc/platforms/error_log.h b/arch/ppc/platforms/error_log.h --- a/arch/ppc/platforms/error_log.h Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/error_log.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort - */ #ifndef __ERROR_LOG_H__ #define __ERROR_LOG_H__ diff -Nru a/arch/ppc/platforms/est8260.h b/arch/ppc/platforms/est8260.h --- a/arch/ppc/platforms/est8260.h Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/est8260.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: SCCS/s.est8260.h 1.5 05/17/01 18:14:24 cort - */ - /* Board information for the EST8260, which should be generic for * all 8260 boards. The IMMR is now given to us so the hard define * will soon be removed. All of the clock values are computed from diff -Nru a/arch/ppc/platforms/fads.h b/arch/ppc/platforms/fads.h --- a/arch/ppc/platforms/fads.h Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/platforms/fads.h Fri Sep 20 08:20:41 2002 @@ -1,8 +1,4 @@ /* - * BK Id: SCCS/s.fads.h 1.14 10/26/01 10:14:09 trini - */ - -/* * A collection of structures, addresses, and values associated with * the Motorola 860T FADS board. Copied from the MBX stuff. * diff -Nru a/arch/ppc/platforms/gemini.h b/arch/ppc/platforms/gemini.h --- a/arch/ppc/platforms/gemini.h Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/platforms/gemini.h Fri Sep 20 08:20:46 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * include/asm-ppc/platforms/gemini.h + * arch/ppc/platforms/gemini.h * * * Onboard registers and descriptions for Synergy Microsystems' diff -Nru a/arch/ppc/platforms/gemini_pci.c b/arch/ppc/platforms/gemini_pci.c --- a/arch/ppc/platforms/gemini_pci.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/platforms/gemini_pci.c Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #include #include #include diff -Nru a/arch/ppc/platforms/gemini_prom.S b/arch/ppc/platforms/gemini_prom.S --- a/arch/ppc/platforms/gemini_prom.S Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/gemini_prom.S Fri Sep 20 08:20:47 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * arch/ppc/kernel/gemini_prom.S + * arch/ppc/platforms/gemini_prom.S * * Not really prom support code (yet), but sort of anti-prom code. The current * bootloader does a number of things it shouldn't and doesn't do things that it diff -Nru a/arch/ppc/platforms/gemini_serial.h b/arch/ppc/platforms/gemini_serial.h --- a/arch/ppc/platforms/gemini_serial.h Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/platforms/gemini_serial.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef __ASMPPC_GEMINI_SERIAL_H #define __ASMPPC_GEMINI_SERIAL_H diff -Nru a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c --- a/arch/ppc/platforms/gemini_setup.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/platforms/gemini_setup.c Fri Sep 20 08:20:46 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * arch/ppc/platforms/setup.c + * arch/ppc/platforms/gemini_setup.c * * Copyright (C) 1995 Linus Torvalds * Adapted from 'alpha' version by Gary Thomas diff -Nru a/arch/ppc/platforms/iSeries_pic.c b/arch/ppc/platforms/iSeries_pic.c --- a/arch/ppc/platforms/iSeries_pic.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/iSeries_pic.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/platforms/iSeries_pic.c * */ diff -Nru a/arch/ppc/platforms/iSeries_smp.c b/arch/ppc/platforms/iSeries_smp.c --- a/arch/ppc/platforms/iSeries_smp.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/platforms/iSeries_smp.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * SMP support for iSeries/LPAR. * * Copyright (C) 2001 IBM Corp. diff -Nru a/arch/ppc/platforms/iSeries_time.c b/arch/ppc/platforms/iSeries_time.c --- a/arch/ppc/platforms/iSeries_time.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/platforms/iSeries_time.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Time routes for iSeries LPAR. * * Copyright (C) 2001 IBM Corp. diff -Nru a/arch/ppc/platforms/ivms8.h b/arch/ppc/platforms/ivms8.h --- a/arch/ppc/platforms/ivms8.h Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/platforms/ivms8.h Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.ivms8.h 1.8 10/26/01 10:14:09 trini - */ -/* * Speech Design Integrated Voicemail board specific definitions * - IVMS8 (small, 8 channels) * - IVML24 (large, 24 channels) diff -Nru a/arch/ppc/platforms/mbx.h b/arch/ppc/platforms/mbx.h --- a/arch/ppc/platforms/mbx.h Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/mbx.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.mbx.h 1.11 08/17/01 15:23:17 paulus - */ -/* * A collection of structures, addresses, and values associated with * the Motorola MBX boards. This was originally created for the * MBX860, and probably needs revisions for other boards (like the 821). diff -Nru a/arch/ppc/platforms/oak.h b/arch/ppc/platforms/oak.h --- a/arch/ppc/platforms/oak.h Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/oak.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * * Copyright (c) 1999 Grant Erickson * diff -Nru a/arch/ppc/platforms/oak_setup.c b/arch/ppc/platforms/oak_setup.c --- a/arch/ppc/platforms/oak_setup.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/platforms/oak_setup.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * * Copyright (c) 1999-2000 Grant Erickson * diff -Nru a/arch/ppc/platforms/oak_setup.h b/arch/ppc/platforms/oak_setup.h --- a/arch/ppc/platforms/oak_setup.h Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/platforms/oak_setup.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort - */ -/* * * Copyright (c) 1999-2000 Grant Erickson * diff -Nru a/arch/ppc/platforms/pmac_backlight.c b/arch/ppc/platforms/pmac_backlight.c --- a/arch/ppc/platforms/pmac_backlight.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/platforms/pmac_backlight.c Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Miscellaneous procedures for dealing with the PowerMac hardware. * Contains support for the backlight. * diff -Nru a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c --- a/arch/ppc/platforms/pmac_feature.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/platforms/pmac_feature.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/platforms/pmac_feature.c * * Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au) diff -Nru a/arch/ppc/platforms/pmac_nvram.c b/arch/ppc/platforms/pmac_nvram.c --- a/arch/ppc/platforms/pmac_nvram.c Fri Sep 20 08:20:45 2002 +++ b/arch/ppc/platforms/pmac_nvram.c Fri Sep 20 08:20:45 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/platforms/pmac_nvram.c * * Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org) diff -Nru a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c --- a/arch/ppc/platforms/pmac_pci.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/platforms/pmac_pci.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Support for PCI bridges found on Power Macintoshes. * * This includes support for bandit, chaos, grackle (motorola diff -Nru a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c --- a/arch/ppc/platforms/pmac_pic.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/pmac_pic.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Support for the interrupt controllers found on Power Macintosh, * currently Apple's "Grand Central" interrupt controller in all * it's incarnations. OpenPIC support used on newer machines is diff -Nru a/arch/ppc/platforms/pmac_pic.h b/arch/ppc/platforms/pmac_pic.h --- a/arch/ppc/platforms/pmac_pic.h Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/platforms/pmac_pic.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef __PPC_PLATFORMS_PMAC_PIC_H #define __PPC_PLATFORMS_PMAC_PIC_H diff -Nru a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c --- a/arch/ppc/platforms/pmac_setup.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/pmac_setup.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/platforms/setup.c * * PowerPC version diff -Nru a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c --- a/arch/ppc/platforms/pmac_smp.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/platforms/pmac_smp.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * SMP support for power macintosh. * * We support both the old "powersurge" SMP architecture diff -Nru a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c --- a/arch/ppc/platforms/pmac_time.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/platforms/pmac_time.c Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Support for periodic interrupts (100 per second) and for getting * the current time from the RTC on Power Macintoshes. * diff -Nru a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c --- a/arch/ppc/platforms/prep_pci.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/platforms/prep_pci.c Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * PReP pci functions. * Originally by Gary Thomas * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) diff -Nru a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c --- a/arch/ppc/platforms/prep_setup.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/prep_setup.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/platforms/setup.c * * Copyright (C) 1995 Linus Torvalds diff -Nru a/arch/ppc/platforms/prep_time.c b/arch/ppc/platforms/prep_time.c --- a/arch/ppc/platforms/prep_time.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/platforms/prep_time.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * arch/ppc/platforms/prep_time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds diff -Nru a/arch/ppc/platforms/proc_rtas.c b/arch/ppc/platforms/proc_rtas.c --- a/arch/ppc/platforms/proc_rtas.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/platforms/proc_rtas.c Fri Sep 20 08:20:48 2002 @@ -1,8 +1,5 @@ /* - * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort - */ -/* - * arch/ppc/kernel/proc_rtas.c + * arch/ppc/platforms/proc_rtas.c * Copyright (C) 2000 Tilmann Bitterberg * (tilmann@bitterberg.de) * diff -Nru a/arch/ppc/platforms/residual.c b/arch/ppc/platforms/residual.c --- a/arch/ppc/platforms/residual.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc/platforms/residual.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.residual.c 1.13 09/11/01 16:54:34 trini - */ -/* * Code to deal with the PReP residual data. * * Written by: Cort Dougan (cort@cs.nmt.edu) diff -Nru a/arch/ppc/platforms/rpxclassic.h b/arch/ppc/platforms/rpxclassic.h --- a/arch/ppc/platforms/rpxclassic.h Fri Sep 20 08:20:42 2002 +++ b/arch/ppc/platforms/rpxclassic.h Fri Sep 20 08:20:42 2002 @@ -1,8 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ - -/* * A collection of structures, addresses, and values associated with * the RPCG RPX-Classic board. Copied from the RPX-Lite stuff. * diff -Nru a/arch/ppc/platforms/rpxhiox.h b/arch/ppc/platforms/rpxhiox.h --- a/arch/ppc/platforms/rpxhiox.h Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/rpxhiox.h Fri Sep 20 08:20:47 2002 @@ -1,8 +1,4 @@ /* - * BK Id: SCCS/s.rpxhiox.h 1.3 05/17/01 18:14:25 cort - */ - -/* * The Embedded Planet HIOX expansion card definitions. * There were a few different versions of these cards, but only * the one that escaped real production is defined here. diff -Nru a/arch/ppc/platforms/rpxlite.h b/arch/ppc/platforms/rpxlite.h --- a/arch/ppc/platforms/rpxlite.h Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/platforms/rpxlite.h Fri Sep 20 08:20:41 2002 @@ -1,8 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ - -/* * A collection of structures, addresses, and values associated with * the RPCG RPX-Lite board. Copied from the MBX stuff. * diff -Nru a/arch/ppc/platforms/sleep.S b/arch/ppc/platforms/sleep.S --- a/arch/ppc/platforms/sleep.S Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/platforms/sleep.S Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * This file contains sleep low-level functions for PowerBook G3. * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org) * and Paul Mackerras (paulus@samba.org). diff -Nru a/arch/ppc/platforms/spd8xx.h b/arch/ppc/platforms/spd8xx.h --- a/arch/ppc/platforms/spd8xx.h Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/platforms/spd8xx.h Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.spd8xx.h 1.8 10/27/01 13:39:41 trini - */ -/* * Speech Design SPD8xxTS board specific definitions * * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de) diff -Nru a/arch/ppc/platforms/tqm8xx.h b/arch/ppc/platforms/tqm8xx.h --- a/arch/ppc/platforms/tqm8xx.h Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/platforms/tqm8xx.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.tqm8xx.h 1.8 08/30/01 09:01:04 trini - */ -/* * TQM8xx(L) board specific definitions * * Copyright (c) 1999,2000,2001 Wolfgang Denk (wd@denx.de) diff -Nru a/arch/ppc/xmon/Makefile b/arch/ppc/xmon/Makefile --- a/arch/ppc/xmon/Makefile Fri Sep 20 08:20:42 2002 +++ b/arch/ppc/xmon/Makefile Fri Sep 20 08:20:42 2002 @@ -1,5 +1,3 @@ -# BK Id: SCCS/s.Makefile 1.6 06/27/01 14:49:58 trini -# # Makefile for xmon O_TARGET := x.o diff -Nru a/arch/ppc/xmon/adb.c b/arch/ppc/xmon/adb.c --- a/arch/ppc/xmon/adb.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/xmon/adb.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.adb.c 1.5 05/17/01 18:14:23 cort - */ -/* * Copyright (C) 1996 Paul Mackerras. */ #include "nonstdio.h" diff -Nru a/arch/ppc/xmon/ansidecl.h b/arch/ppc/xmon/ansidecl.h --- a/arch/ppc/xmon/ansidecl.h Fri Sep 20 08:20:48 2002 +++ b/arch/ppc/xmon/ansidecl.h Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.ansidecl.h 1.5 05/17/01 18:14:23 cort - */ /* ANSI and traditional C compatability macros Copyright 1991, 1992 Free Software Foundation, Inc. This file is part of the GNU C Library. diff -Nru a/arch/ppc/xmon/nonstdio.h b/arch/ppc/xmon/nonstdio.h --- a/arch/ppc/xmon/nonstdio.h Fri Sep 20 08:20:46 2002 +++ b/arch/ppc/xmon/nonstdio.h Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ typedef int FILE; extern FILE *xmon_stdin, *xmon_stdout; #define EOF (-1) diff -Nru a/arch/ppc/xmon/ppc-dis.c b/arch/ppc/xmon/ppc-dis.c --- a/arch/ppc/xmon/ppc-dis.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/xmon/ppc-dis.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.ppc-dis.c 1.5 05/17/01 18:14:23 cort - */ /* ppc-dis.c -- Disassemble PowerPC instructions Copyright 1994 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support diff -Nru a/arch/ppc/xmon/ppc-opc.c b/arch/ppc/xmon/ppc-opc.c --- a/arch/ppc/xmon/ppc-opc.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/xmon/ppc-opc.c Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.ppc-opc.c 1.5 05/17/01 18:14:23 cort - */ /* ppc-opc.c -- PowerPC opcode list Copyright 1994 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support diff -Nru a/arch/ppc/xmon/ppc.h b/arch/ppc/xmon/ppc.h --- a/arch/ppc/xmon/ppc.h Fri Sep 20 08:20:45 2002 +++ b/arch/ppc/xmon/ppc.h Fri Sep 20 08:20:45 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.ppc.h 1.5 05/17/01 18:14:23 cort - */ /* ppc.h -- Header file for PowerPC opcode table Copyright 1994 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support diff -Nru a/arch/ppc/xmon/privinst.h b/arch/ppc/xmon/privinst.h --- a/arch/ppc/xmon/privinst.h Fri Sep 20 08:20:44 2002 +++ b/arch/ppc/xmon/privinst.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.privinst.h 1.5 05/17/01 18:14:23 cort - */ -/* * Copyright (C) 1996 Paul Mackerras. */ #include diff -Nru a/arch/ppc/xmon/setjmp.c b/arch/ppc/xmon/setjmp.c --- a/arch/ppc/xmon/setjmp.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/xmon/setjmp.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.setjmp.c 1.5 05/17/01 18:14:23 cort - */ -/* * Copyright (C) 1996 Paul Mackerras. * * NB this file must be compiled with -O2. diff -Nru a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c --- a/arch/ppc/xmon/start.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/xmon/start.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Copyright (C) 1996 Paul Mackerras. */ #include diff -Nru a/arch/ppc/xmon/start_8xx.c b/arch/ppc/xmon/start_8xx.c --- a/arch/ppc/xmon/start_8xx.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/xmon/start_8xx.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.start_8xx.c 1.10 09/14/01 18:01:17 trini - */ -/* * Copyright (C) 1996 Paul Mackerras. * Copyright (C) 2000 Dan Malek. * Quick hack of Paul's code to make XMON work on 8xx processors. Lots diff -Nru a/arch/ppc/xmon/subr_prf.c b/arch/ppc/xmon/subr_prf.c --- a/arch/ppc/xmon/subr_prf.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc/xmon/subr_prf.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Written by Cort Dougan to replace the version originally used * by Paul Mackerras, which came from NetBSD and thus had copyright * conflicts with Linux. diff -Nru a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c --- a/arch/ppc/xmon/xmon.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc/xmon/xmon.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Routines providing a simple monitor for use on the PowerMac. * * Copyright (C) 1996 Paul Mackerras. diff -Nru a/arch/ppc64/Makefile b/arch/ppc64/Makefile --- a/arch/ppc64/Makefile Fri Sep 20 08:20:42 2002 +++ b/arch/ppc64/Makefile Fri Sep 20 08:20:42 2002 @@ -62,7 +62,22 @@ cp -f arch/ppc64/configs/$(@:config=defconfig) arch/ppc64/defconfig archclean: - rm -f arch/ppc64/kernel/{ppc_defs.h,mk_defs.s,mk_defs_out.c,mk_defs_tpl} @$(MAKEBOOT) clean archmrproper: + + +prepare: include/asm-$(ARCH)/offsets.h + +arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ + include/config/MARKER + +include/asm-$(ARCH)/offsets.h.tmp: arch/$(ARCH)/kernel/asm-offsets.s + @$(generate-asm-offsets.h) < $< > $@ + +include/asm-$(ARCH)/offsets.h: include/asm-$(ARCH)/offsets.h.tmp + @echo -n ' Generating $@' + @$(update-if-changed) + +CLEAN_FILES += include/asm-$(ARCH)/offsets.h.tmp \ + include/asm-$(ARCH)/offsets.h diff -Nru a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c --- a/arch/ppc64/kernel/LparData.c Fri Sep 20 08:20:43 2002 +++ b/arch/ppc64/kernel/LparData.c Fri Sep 20 08:20:43 2002 @@ -6,7 +6,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#define __KERNEL__ 1 #include #include #include @@ -248,8 +247,3 @@ return mem; } - - - - - diff -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile --- a/arch/ppc64/kernel/Makefile Fri Sep 20 08:20:48 2002 +++ b/arch/ppc64/kernel/Makefile Fri Sep 20 08:20:48 2002 @@ -40,25 +40,3 @@ include $(TOPDIR)/Rules.make -# -# This is just to get the dependencies... -# - -head.o: head.S ppc_defs.h -misc.o: misc.S ppc_defs.h -entry.o: entry.S ppc_defs.h -hvCall.o: hvCall.S ppc_defs.h -pSeries_hvCall.o: pSeries_hvCall.S ppc_defs.h -sys32.o: sys32.S ppc_defs.h - -ppc_defs.h: mk_defs.c ppc_defs.head \ - $(TOPDIR)/include/asm/mmu.h \ - $(TOPDIR)/include/asm/processor.h \ - $(TOPDIR)/include/asm/pgtable.h \ - $(TOPDIR)/include/asm/ptrace.h - $(CC) $(CFLAGS) -S mk_defs.c - cp ppc_defs.head ppc_defs.h -# for bk, this way we can write to the file even if it's not checked out - chmod u+w ppc_defs.h - grep '^#define' mk_defs.s >> ppc_defs.h - rm mk_defs.s diff -Nru a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc64/kernel/asm-offsets.c Fri Sep 20 08:20:47 2002 @@ -0,0 +1,162 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + /* thread struct on stack */ + DEFINE(THREAD_SHIFT, THREAD_SHIFT); + DEFINE(THREAD_SIZE, THREAD_SIZE); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + + /* task_struct->thread */ + DEFINE(THREAD, offsetof(struct task_struct, thread)); + DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); + DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); + DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); + DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); + DEFINE(KSP, offsetof(struct thread_struct, ksp)); + + DEFINE(MM, offsetof(struct task_struct, mm)); + + /* naca */ + DEFINE(PACA, offsetof(struct naca_struct, paca)); + DEFINE(DCACHEL1LINESIZE, offsetof(struct naca_struct, dCacheL1LineSize)); + DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize)); + DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage)); + DEFINE(ICACHEL1LINESIZE, offsetof(struct naca_struct, iCacheL1LineSize)); + DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize)); + DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage)); + DEFINE(SLBSIZE, offsetof(struct naca_struct, slb_size)); + DEFINE(PLATFORM, offsetof(struct naca_struct, platform)); + + /* paca */ + DEFINE(PACA_SIZE, sizeof(struct paca_struct)); + DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex)); + DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart)); + DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave)); + DEFINE(PACACURRENT, offsetof(struct paca_struct, xCurrent)); + DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr)); + DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real)); + DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt)); + DEFINE(PACASTABRR, offsetof(struct paca_struct, xStab_data.next_round_robin)); + DEFINE(PACAR1, offsetof(struct paca_struct, xR1)); + DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr)); + DEFINE(PACATOC, offsetof(struct paca_struct, xTOC)); + DEFINE(PACAEXCSP, offsetof(struct paca_struct, exception_sp)); + DEFINE(PACAHRDWINTSTACK, offsetof(struct paca_struct, xHrdIntStack)); + DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, xProcEnabled)); + DEFINE(PACAHRDWINTCOUNT, offsetof(struct paca_struct, xHrdIntCount)); + DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); + DEFINE(PACAPROFENABLED, offsetof(struct paca_struct, prof_enabled)); + DEFINE(PACAPROFLEN, offsetof(struct paca_struct, prof_len)); + DEFINE(PACAPROFSHIFT, offsetof(struct paca_struct, prof_shift)); + DEFINE(PACAPROFBUFFER, offsetof(struct paca_struct, prof_buffer)); + DEFINE(PACAPROFSTEXT, offsetof(struct paca_struct, prof_stext)); + DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca)); + DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca)); + DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav)); + DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack)); + DEFINE(PACAGUARD, offsetof(struct paca_struct, guard)); + DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0)); + DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1)); + DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt)); + DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt)); + DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr)); + DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending)); + DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags)); + DEFINE(PROMENTRY, offsetof(struct prom_t, entry)); + + /* RTAS */ + DEFINE(RTASBASE, offsetof(struct rtas_t, base)); + DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); + DEFINE(RTASSIZE, offsetof(struct rtas_t, size)); + + /* Interrupt register frame */ + DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); + + DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); + + /* 288 = # of volatile regs, int & fp, for leaf routines */ + /* which do not stack a frame. See the PPC64 ABI. */ + DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288); + /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */ + DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); + DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); + DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0])); + DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1])); + DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2])); + DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3])); + DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4])); + DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5])); + DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6])); + DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7])); + DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8])); + DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9])); + DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); + DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); + DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); + DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23])); + /* + * Note: these symbols include _ because they overlap with special + * register names + */ + DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); + DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr)); + DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); + DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); + DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); + DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); + DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); + DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); + DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); + DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); + DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); + DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe)); + + /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */ + DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)); + DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); + + DEFINE(CLONE_VM, CLONE_VM); + + return 0; +} diff -Nru a/arch/ppc64/kernel/chrp_setup.c b/arch/ppc64/kernel/chrp_setup.c --- a/arch/ppc64/kernel/chrp_setup.c Fri Sep 20 08:20:42 2002 +++ b/arch/ppc64/kernel/chrp_setup.c Fri Sep 20 08:20:42 2002 @@ -58,7 +58,6 @@ #include #include -#include "local_irq.h" #include "i8259.h" #include "open_pic.h" #include "xics.h" @@ -66,7 +65,6 @@ extern volatile unsigned char *chrp_int_ack_special; -void chrp_setup_pci_ptrs(void); void chrp_progress(char *, unsigned short); void chrp_request_regions(void); @@ -237,8 +235,6 @@ #endif /* CONFIG_BLK_DEV_INITRD */ #endif - ppc_md.ppc_machine = naca->platform; - ppc_md.setup_arch = chrp_setup_arch; ppc_md.setup_residual = NULL; ppc_md.get_cpuinfo = chrp_get_cpuinfo; @@ -265,7 +261,6 @@ ppc_md.power_off = rtas_power_off; ppc_md.halt = rtas_halt; - ppc_md.time_init = NULL; ppc_md.get_boot_time = pSeries_get_rtc_time; ppc_md.get_rtc_time = pSeries_get_rtc_time; ppc_md.set_rtc_time = pSeries_set_rtc_time; diff -Nru a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S --- a/arch/ppc64/kernel/entry.S Fri Sep 20 08:20:41 2002 +++ b/arch/ppc64/kernel/entry.S Fri Sep 20 08:20:41 2002 @@ -20,14 +20,15 @@ * 2 of the License, or (at your option) any later version. */ -#include "ppc_asm.h" +#include +#include +#include #include #include #include #include -#include -#include -#include +#include +#include #ifdef CONFIG_PPC_ISERIES #define DO_SOFT_DISABLE diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S --- a/arch/ppc64/kernel/head.S Fri Sep 20 08:20:46 2002 +++ b/arch/ppc64/kernel/head.S Fri Sep 20 08:20:46 2002 @@ -25,12 +25,12 @@ #define SECONDARY_PROCESSORS -#include "ppc_asm.h" -#include "ppc_defs.h" +#include #include #include -#include #include +#include +#include #ifdef CONFIG_PPC_ISERIES #define DO_SOFT_DISABLE @@ -90,7 +90,9 @@ * between physical addresses and absolute addresses) and * to the pidhash table (also used by the debugger) */ .llong msChunks-KERNELBASE +#ifdef CONFIG_PPC_ISERIES .llong pidhash-KERNELBASE +#endif /* Offset 0x38 - Pointer to start of embedded System.map */ .globl embedded_sysmap_start diff -Nru a/arch/ppc64/kernel/htab.c b/arch/ppc64/kernel/htab.c --- a/arch/ppc64/kernel/htab.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/htab.c Fri Sep 20 08:20:47 2002 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include diff -Nru a/arch/ppc64/kernel/hvCall.S b/arch/ppc64/kernel/hvCall.S --- a/arch/ppc64/kernel/hvCall.S Fri Sep 20 08:20:46 2002 +++ b/arch/ppc64/kernel/hvCall.S Fri Sep 20 08:20:46 2002 @@ -11,9 +11,8 @@ * 2 of the License, or (at your option) any later version. */ -#include "ppc_asm.h" +#include #include -#include .text diff -Nru a/arch/ppc64/kernel/i8259.h b/arch/ppc64/kernel/i8259.h --- a/arch/ppc64/kernel/i8259.h Fri Sep 20 08:20:43 2002 +++ b/arch/ppc64/kernel/i8259.h Fri Sep 20 08:20:43 2002 @@ -9,8 +9,6 @@ #ifndef _PPC_KERNEL_i8259_H #define _PPC_KERNEL_i8259_H -#include "local_irq.h" - extern struct hw_interrupt_type i8259_pic; void i8259_init(void); diff -Nru a/arch/ppc64/kernel/iSeries_VpdInfo.c b/arch/ppc64/kernel/iSeries_VpdInfo.c --- a/arch/ppc64/kernel/iSeries_VpdInfo.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc64/kernel/iSeries_VpdInfo.c Fri Sep 20 08:20:41 2002 @@ -34,7 +34,6 @@ #include #include #include -#include //#include #include #include "pci.h" diff -Nru a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c --- a/arch/ppc64/kernel/iSeries_pci.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc64/kernel/iSeries_pci.c Fri Sep 20 08:20:48 2002 @@ -55,7 +55,6 @@ extern int panic_timeout; extern struct device_node *allnodes; -extern unsigned long phb_tce_table_init(struct pci_controller *phb); extern unsigned long iSeries_Base_Io_Memory; extern struct pci_ops iSeries_pci_ops; diff -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c --- a/arch/ppc64/kernel/iSeries_setup.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/iSeries_setup.c Fri Sep 20 08:20:47 2002 @@ -312,7 +312,6 @@ ppc_md.setup_arch = iSeries_setup_arch; ppc_md.setup_residual = iSeries_setup_residual; ppc_md.get_cpuinfo = iSeries_get_cpuinfo; - ppc_md.irq_cannonicalize = NULL; ppc_md.init_IRQ = iSeries_init_IRQ; ppc_md.init_ras_IRQ = NULL; ppc_md.get_irq = iSeries_get_irq; @@ -325,8 +324,7 @@ ppc_md.power_off = iSeries_power_off; ppc_md.halt = iSeries_halt; - ppc_md.time_init = NULL; - ppc_md.get_boot_time = iSeries_get_boot_time; + ppc_md.get_boot_time = iSeries_get_boot_time; ppc_md.set_rtc_time = iSeries_set_rtc_time; ppc_md.get_rtc_time = iSeries_get_rtc_time; ppc_md.calibrate_decr = iSeries_calibrate_decr; @@ -782,15 +780,6 @@ iSeries_halt(void) { mf_powerOff(); -} - -/* - * Nothing to do here. - */ -void __init -iSeries_time_init(void) -{ - /* Nothing to do */ } /* JDH Hack */ diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c --- a/arch/ppc64/kernel/irq.c Fri Sep 20 08:20:45 2002 +++ b/arch/ppc64/kernel/irq.c Fri Sep 20 08:20:45 2002 @@ -53,8 +53,6 @@ #include #include -#include "local_irq.h" - void enable_irq(unsigned int irq_nr); void disable_irq(unsigned int irq_nr); @@ -69,7 +67,6 @@ { [0 ... NR_IRQS-1] = { 0, NULL, NULL, 0, SPIN_LOCK_UNLOCKED}}; int ppc_spurious_interrupts = 0; -struct irqaction *ppc_irq_action[NR_IRQS]; unsigned long lpEvent_count = 0; /* nasty hack for shared irq's since we need to do kmalloc calls but diff -Nru a/arch/ppc64/kernel/lmb.c b/arch/ppc64/kernel/lmb.c --- a/arch/ppc64/kernel/lmb.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc64/kernel/lmb.c Fri Sep 20 08:20:46 2002 @@ -287,7 +287,7 @@ continue; if ( max_addr == LMB_ALLOC_ANYWHERE ) - base = _ALIGN_DOWN(lmbbase+lmbsize-size, align); + base = _ALIGN_DOWN(lmbbase+lmbsize-size, align); else if ( lmbbase < max_addr ) base = _ALIGN_DOWN(min(lmbbase+lmbsize,max_addr)-size, align); else diff -Nru a/arch/ppc64/kernel/local_irq.h b/arch/ppc64/kernel/local_irq.h --- a/arch/ppc64/kernel/local_irq.h Fri Sep 20 08:20:42 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,26 +0,0 @@ -/* - * c 2001 PowerPC 64 Team, IBM Corp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _PPC_KERNEL_LOCAL_IRQ_H -#define _PPC_KERNEL_LOCAL_IRQ_H - -#include -#include -#include -#include -#include - -void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); - -#define NR_MASK_WORDS ((NR_IRQS + 63) / 64) - -extern int ppc_spurious_interrupts; -extern int ppc_second_irq; -extern struct irqaction *ppc_irq_action[NR_IRQS]; - -#endif /* _PPC_KERNEL_LOCAL_IRQ_H */ diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S --- a/arch/ppc64/kernel/misc.S Fri Sep 20 08:20:44 2002 +++ b/arch/ppc64/kernel/misc.S Fri Sep 20 08:20:44 2002 @@ -25,7 +25,8 @@ #include #include #include -#include "ppc_asm.h" +#include +#include .text @@ -563,7 +564,7 @@ .llong .sys_ni_syscall /* old mpx syscall */ .llong .sys32_setpgid .llong .sys_ni_syscall /* old ulimit syscall */ - .llong .sys_olduname + .llong .sys32_olduname .llong .sys32_umask /* 60 */ .llong .sys_chroot .llong .sys_ustat @@ -736,8 +737,11 @@ .llong .sys_ni_syscall /* reserved for sys_io_getevents */ .llong .sys_ni_syscall /* 230 - reserved for sys_io_submit */ .llong .sys_ni_syscall /* reserved for sys_io_cancel */ + .llong .sys_ni_syscall /* reserved for alloc_hugepages */ + .llong .sys_ni_syscall /* reserved for free_hugepages */ + .llong .sys_exit_group - .rept NR_syscalls-231 + .rept NR_syscalls-234 .llong .sys_ni_syscall .endr #endif @@ -766,7 +770,7 @@ .llong .sys_lseek .llong .sys_getpid /* 20 */ .llong .sys_mount - .llong .sys_oldumount + .llong .sys_ni_syscall /* old umount syscall */ .llong .sys_setuid .llong .sys_getuid .llong .ppc64_sys_stime /* 25 */ @@ -803,7 +807,7 @@ .llong .sys_ni_syscall /* old mpx syscall */ .llong .sys_setpgid .llong .sys_ni_syscall /* old ulimit syscall */ - .llong .sys_olduname + .llong .sys_ni_syscall /* old uname syscall */ .llong .sys_umask /* 60 */ .llong .sys_chroot .llong .sys_ustat @@ -820,7 +824,7 @@ .llong .sys_sigpending .llong .sys_sethostname .llong .sys_setrlimit /* 75 */ - .llong .sys_old_getrlimit + .llong .sys_ni_syscall /* old getrlimit syscall */ .llong .sys_getrusage .llong .sys_gettimeofday .llong .sys_settimeofday @@ -833,7 +837,7 @@ .llong .sys_uselib .llong .sys_swapon .llong .sys_reboot - .llong .old_readdir + .llong .sys_ni_syscall /* old readdir syscall */ .llong .sys_mmap /* 90 */ .llong .sys_munmap .llong .sys_truncate @@ -942,8 +946,8 @@ .llong .sys_ni_syscall /* 195 - 32bit only stat64 */ .llong .sys_ni_syscall /* 32bit only lstat64 */ .llong .sys_ni_syscall /* 32bit only fstat64 */ - .llong .sys_pciconfig_read - .llong .sys_pciconfig_write + .llong .sys_ni_syscall /* 32bit only pciconfig_read */ + .llong .sys_ni_syscall /* 32bit only pciconfig_write */ .llong .sys_ni_syscall /* 200 - reserved - sys_pciconfig_iobase */ .llong .sys_ni_syscall /* reserved for MacOnLinux */ .llong .sys_getdents64 @@ -976,7 +980,10 @@ .llong .sys_io_getevents .llong .sys_io_submit /* 230 */ .llong .sys_io_cancel + .llong .sys_ni_syscall /* reserved for alloc_hugepages */ + .llong .sys_ni_syscall /* reserved for free_hugepages */ + .llong .sys_exit_group - .rept NR_syscalls-231 + .rept NR_syscalls-234 .llong .sys_ni_syscall .endr diff -Nru a/arch/ppc64/kernel/mk_defs.c b/arch/ppc64/kernel/mk_defs.c --- a/arch/ppc64/kernel/mk_defs.c Fri Sep 20 08:20:47 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,162 +0,0 @@ -/* - * This program is used to generate definitions needed by - * assembly language modules. - * - * We use the technique used in the OSF Mach kernel code: - * generate asm statements containing #defines, - * compile this file to assembler, and then extract the - * #defines from the assembly-language output. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define DEFINE(sym, val) \ - asm volatile("\n#define\t" #sym "\t%0" : : "i" (val)) - -int -main(void) -{ - /* thread struct on stack */ - DEFINE(THREAD_SHIFT, THREAD_SHIFT); - DEFINE(THREAD_SIZE, THREAD_SIZE); - DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); - - /* task_struct->thread */ - DEFINE(THREAD, offsetof(struct task_struct, thread)); - DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); - DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); - DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); - DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); - DEFINE(KSP, offsetof(struct thread_struct, ksp)); - - DEFINE(MM, offsetof(struct task_struct, mm)); - - /* naca */ - DEFINE(PACA, offsetof(struct naca_struct, paca)); - DEFINE(DCACHEL1LINESIZE, offsetof(struct naca_struct, dCacheL1LineSize)); - DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize)); - DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage)); - DEFINE(ICACHEL1LINESIZE, offsetof(struct naca_struct, iCacheL1LineSize)); - DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize)); - DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage)); - DEFINE(SLBSIZE, offsetof(struct naca_struct, slb_size)); - DEFINE(PLATFORM, offsetof(struct naca_struct, platform)); - - /* paca */ - DEFINE(PACA_SIZE, sizeof(struct paca_struct)); - DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex)); - DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart)); - DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave)); - DEFINE(PACACURRENT, offsetof(struct paca_struct, xCurrent)); - DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr)); - DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real)); - DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt)); - DEFINE(PACASTABRR, offsetof(struct paca_struct, xStab_data.next_round_robin)); - DEFINE(PACAR1, offsetof(struct paca_struct, xR1)); - DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr)); - DEFINE(PACATOC, offsetof(struct paca_struct, xTOC)); - DEFINE(PACAEXCSP, offsetof(struct paca_struct, exception_sp)); - DEFINE(PACAHRDWINTSTACK, offsetof(struct paca_struct, xHrdIntStack)); - DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, xProcEnabled)); - DEFINE(PACAHRDWINTCOUNT, offsetof(struct paca_struct, xHrdIntCount)); - DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); - DEFINE(PACAPROFENABLED, offsetof(struct paca_struct, prof_enabled)); - DEFINE(PACAPROFLEN, offsetof(struct paca_struct, prof_len)); - DEFINE(PACAPROFSHIFT, offsetof(struct paca_struct, prof_shift)); - DEFINE(PACAPROFBUFFER, offsetof(struct paca_struct, prof_buffer)); - DEFINE(PACAPROFSTEXT, offsetof(struct paca_struct, prof_stext)); - DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca)); - DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca)); - DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav)); - DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack)); - DEFINE(PACAGUARD, offsetof(struct paca_struct, guard)); - DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0)); - DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1)); - DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt)); - DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt)); - DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr)); - DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending)); - DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags)); - DEFINE(PROMENTRY, offsetof(struct prom_t, entry)); - - /* RTAS */ - DEFINE(RTASBASE, offsetof(struct rtas_t, base)); - DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); - DEFINE(RTASSIZE, offsetof(struct rtas_t, size)); - - /* Interrupt register frame */ - DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); - - DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); - - /* 288 = # of volatile regs, int & fp, for leaf routines */ - /* which do not stack a frame. See the PPC64 ABI. */ - DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288); - /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */ - DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); - DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); - DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0])); - DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1])); - DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2])); - DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3])); - DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4])); - DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5])); - DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6])); - DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7])); - DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8])); - DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9])); - DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); - DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); - DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); - DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23])); - /* - * Note: these symbols include _ because they overlap with special - * register names - */ - DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); - DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr)); - DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); - DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); - DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); - DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); - DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); - DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); - DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); - DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); - DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); - DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe)); - - /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */ - DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)); - DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); - - DEFINE(CLONE_VM, CLONE_VM); - - return 0; -} diff -Nru a/arch/ppc64/kernel/open_pic.c b/arch/ppc64/kernel/open_pic.c --- a/arch/ppc64/kernel/open_pic.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/open_pic.c Fri Sep 20 08:20:47 2002 @@ -23,7 +23,6 @@ #include -#include "local_irq.h" #include "open_pic.h" #include "open_pic_defs.h" #include "i8259.h" diff -Nru a/arch/ppc64/kernel/pSeries_hvCall.S b/arch/ppc64/kernel/pSeries_hvCall.S --- a/arch/ppc64/kernel/pSeries_hvCall.S Fri Sep 20 08:20:48 2002 +++ b/arch/ppc64/kernel/pSeries_hvCall.S Fri Sep 20 08:20:48 2002 @@ -11,14 +11,13 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include #include #include #include #include #include #include -#include "ppc_asm.h" +#include /* * hcall interface to pSeries LPAR diff -Nru a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c --- a/arch/ppc64/kernel/pSeries_pci.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc64/kernel/pSeries_pci.c Fri Sep 20 08:20:48 2002 @@ -45,15 +45,13 @@ #include "open_pic.h" #include "pci.h" -extern struct device_node *allnodes; - /******************************************************************* * Forward declares of prototypes. *******************************************************************/ -unsigned long find_and_init_phbs(void); -struct pci_controller* alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ; -void pSeries_pcibios_fixup(void); -static int rtas_fake_read(struct device_node *dn, int offset, int nbytes, unsigned long *returnval); +struct pci_controller *alloc_phb(struct device_node *dev, char *model, + unsigned int addr_size_words) ; +static int rtas_fake_read(struct device_node *dn, int offset, int nbytes, + unsigned long *returnval); /* RTAS tokens */ static int read_pci_config; @@ -467,44 +465,37 @@ * Python ***************************************************************/ if (strstr(model, "Python")) { + unsigned long chip_regs; + volatile u32 *tmp, i; + PPCDBG(PPCDBG_PHBINIT, "\tCreate python\n"); - phb = pci_alloc_pci_controller("PHB PY",phb_type_python); - if (phb == NULL) return NULL; - - phb->cfg_addr = (volatile unsigned long *) - ioremap(reg_struct.address + 0xf8000, PAGE_SIZE); - PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_r = 0x%lx\n", - reg_struct.address + 0xf8000); - PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_v = 0x%lx\n", - phb->cfg_addr); - phb->cfg_data = (char*)(phb->cfg_addr + 0x02); - phb->phb_regs = (volatile unsigned long *) - ioremap(reg_struct.address + 0xf7000, PAGE_SIZE); + + phb = pci_alloc_pci_controller("PHB PY", phb_type_python); + if (phb == NULL) + return NULL; + /* Python's register file is 1 MB in size. */ - phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), - 0x100000); + chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), + 0x100000); /* * Firmware doesn't always clear this bit which is critical * for good performance - Anton */ - { - volatile u32 *tmp, i; #define PRG_CL_RESET_VALID 0x00010000 - tmp = (u32 *)((unsigned long)phb->chip_regs + 0xf6030); + tmp = (u32 *)((unsigned long)chip_regs + 0xf6030); - if (*tmp & PRG_CL_RESET_VALID) { - printk("Python workaround: "); - *tmp &= ~PRG_CL_RESET_VALID; - /* - * We must read it back for changes to - * take effect - */ - i = *tmp; - printk("reg0: %x\n", i); - } + if (*tmp & PRG_CL_RESET_VALID) { + printk("Python workaround: "); + *tmp &= ~PRG_CL_RESET_VALID; + /* + * We must read it back for changes to + * take effect + */ + i = *tmp; + printk("reg0: %x\n", i); } /*************************************************************** @@ -514,28 +505,12 @@ } else if ((strstr(model, "Speedwagon")) || (strstr(model, "Winnipeg"))) { PPCDBG(PPCDBG_PHBINIT, "\tCreate speedwagon\n"); - phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon); - if (phb == NULL) return NULL; - - if (naca->platform == PLATFORM_PSERIES) { - phb->cfg_addr = (volatile unsigned long *) - ioremap(reg_struct.address + 0x140, PAGE_SIZE); - phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */ - phb->phb_regs = (volatile unsigned long *) - ioremap(reg_struct.address, PAGE_SIZE); - /* Speedwagon's register file is 1 MB in size. */ - phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), - 0x100000); - PPCDBG(PPCDBG_PHBINIT, "\tmapping chip_regs from 0x%lx -> 0x%lx\n", - reg_struct.address & 0xfffff, phb->chip_regs); - } else { - phb->cfg_addr = NULL; - phb->cfg_data = NULL; - phb->phb_regs = NULL; - phb->chip_regs = NULL; - } + phb = pci_alloc_pci_controller("PHB SW", phb_type_speedwagon); + if (phb == NULL) + return NULL; phb->local_number = ((reg_struct.address >> 12) & 0xf) - 0x8; + /*************************************************************** * Trying to build a known just gets the code in trouble. ***************************************************************/ @@ -563,7 +538,7 @@ buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len); - if (buid_vals == NULL) { + if (buid_vals == NULL) { phb->buid = 0; } else { struct pci_bus check; diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c --- a/arch/ppc64/kernel/pci.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/pci.c Fri Sep 20 08:20:47 2002 @@ -1,6 +1,4 @@ /* - * - * * Port for PPC64 David Engebretsen, IBM Corp. * Contains common pci routines for ppc64 platform, pSeries and iSeries brands. * @@ -128,7 +126,6 @@ { } - void pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *res, int resource) @@ -200,7 +197,6 @@ } } - /* * Handle resources of PCI devices. If the world were perfect, we could * just allocate all the resource regions and do nothing more. It isn't. @@ -333,64 +329,27 @@ if (!class || class == PCI_CLASS_BRIDGE_HOST) continue; - for(idx=0; idx<6; idx++) { + for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; /* - * Don't touch IDE controllers and I/O ports of video cards! - */ - if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || - (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) - continue; - - /* - * We shall assign a new address to this resource, either because - * the BIOS forgot to do so or because we have decided the old - * address was unusable for some reason. + * We shall assign a new address to this resource, + * either because the BIOS (sic) forgot to do so + * or because we have decided the old address was + * unusable for some reason. */ - if (!r->start && r->end && ppc_md.pcibios_enable_device_hook && - !ppc_md.pcibios_enable_device_hook(dev, 1)) + if (!r->start && r->end) pci_assign_resource(dev, idx); } - if (0) { /* don't assign ROMs */ - r = &dev->resource[PCI_ROM_RESOURCE]; - r->end -= r->start; - r->start = 0; - if (r->end) - pci_assign_resource(dev, PCI_ROM_RESOURCE); - } - } -} - - -int -pcibios_enable_resources(struct pci_dev *dev) -{ - u16 cmd, old_cmd; - int idx; - struct resource *r; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - for(idx=0; idx<6; idx++) { - r = &dev->resource[idx]; - if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - if (dev->resource[PCI_ROM_RESOURCE].start) - cmd |= PCI_COMMAND_MEMORY; - if (cmd != old_cmd) { - printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); +#if 0 /* don't assign ROMs */ + r = &dev->resource[PCI_ROM_RESOURCE]; + r->end -= r->start; + r->start = 0; + if (r->end) + pci_assign_resource(dev, PCI_ROM_RESOURCE); +#endif } - return 0; } /* @@ -407,8 +366,10 @@ return NULL; } memset(hose, 0, sizeof(struct pci_controller)); - if(strlen(model) < 8) strcpy(hose->what,model); - else memcpy(hose->what,model,7); + if(strlen(model) < 8) + strcpy(hose->what,model); + else + memcpy(hose->what,model,7); hose->type = controller_type; hose->global_number = global_phb_number; phbtab[global_phb_number++] = hose; @@ -418,34 +379,12 @@ return hose; } -/* - * This fixup is arch independent and probably should go somewhere else. - */ -void __init -pcibios_generic_fixup(void) -{ - struct pci_dev *dev; - - /* Fix miss-identified vendor AMD pcnet32 adapters. */ - dev = NULL; - while ((dev = pci_find_device(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE, dev)) != NULL && - dev->class == (PCI_CLASS_NETWORK_ETHERNET << 8)) - dev->vendor = PCI_VENDOR_ID_AMD; -} - - - -/*********************************************************************** - * - * - * - ***********************************************************************/ -void __init +static int __init pcibios_init(void) { struct pci_controller *hose; struct pci_bus *bus; - int next_busno; + int next_busno; #ifndef CONFIG_PPC_ISERIES pSeries_pcibios_init(); @@ -455,7 +394,6 @@ printk("PCI: Probing PCI hardware\n"); PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware\n"); - /* Scan all of the recorded PCI controllers. */ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { @@ -467,15 +405,12 @@ next_busno = hose->last_busno+1; } pci_bus_count = next_busno; - + /* Call machine dependant fixup */ if (ppc_md.pcibios_fixup) { ppc_md.pcibios_fixup(); } - /* Generic fixups */ - pcibios_generic_fixup(); - /* Allocate and assign resources */ pcibios_allocate_bus_resources(&pci_root_buses); pcibios_allocate_resources(0); @@ -577,20 +512,22 @@ return str; } -int pcibios_enable_device(struct pci_dev *dev) +int pcibios_enable_device(struct pci_dev *dev, int mask) { u16 cmd, old_cmd; int idx; struct resource *r; - PPCDBG(PPCDBG_BUSWALK,"PCI: %s for device %s \n",__FUNCTION__,dev->slot_name); - if (ppc_md.pcibios_enable_device_hook) - if (ppc_md.pcibios_enable_device_hook(dev, 0)) - return -EINVAL; - + PPCDBG(PPCDBG_BUSWALK,"PCI: %s for device %s \n", __FUNCTION__, + dev->slot_name); + pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for (idx=0; idx<6; idx++) { + for (idx = 0; idx < 6; idx++) { + /* Only set up the requested stuff */ + if (!(mask & (1<resource[idx]; if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); @@ -604,7 +541,8 @@ if (cmd != old_cmd) { printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); - PPCDBG(PPCDBG_BUSWALK,"PCI: Enabling device %s \n",dev->slot_name); + PPCDBG(PPCDBG_BUSWALK,"PCI: Enabling device %s \n", + dev->slot_name); pci_write_config_word(dev, PCI_COMMAND, cmd); } return 0; @@ -985,12 +923,6 @@ udbg_printf("\tio_base_phys = 0x%016LX\n", phb->io_base_phys); udbg_printf("\tpci_mem_offset= 0x%016LX\n", phb->pci_mem_offset); udbg_printf("\tpci_io_offset = 0x%016LX\n", phb->pci_io_offset); - - udbg_printf("\tcfg_addr = 0x%016LX\n", phb->cfg_addr); - udbg_printf("\tcfg_data = 0x%016LX\n", phb->cfg_data); - udbg_printf("\tphb_regs = 0x%016LX\n", phb->phb_regs); - udbg_printf("\tchip_regs = 0x%016LX\n", phb->chip_regs); - udbg_printf("\tResources\n"); dumpResources(&phb->io_resource); diff -Nru a/arch/ppc64/kernel/pci_dma.c b/arch/ppc64/kernel/pci_dma.c --- a/arch/ppc64/kernel/pci_dma.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/pci_dma.c Fri Sep 20 08:20:47 2002 @@ -1438,69 +1438,6 @@ } #endif -/* - * phb_tce_table_init - * - * Function: Display TCE config registers. Could be easily changed - * to initialize the hardware to use TCEs. - */ -unsigned long phb_tce_table_init(struct pci_controller *phb) { - unsigned int r, cfg_rw, i; - unsigned long r64; - phandle node; - - PPCDBG(PPCDBG_TCE, "phb_tce_table_init: start.\n"); - - node = ((struct device_node *)(phb->arch_data))->node; - - PPCDBG(PPCDBG_TCEINIT, "\tphb = 0x%lx\n", phb); - PPCDBG(PPCDBG_TCEINIT, "\tphb->type = 0x%lx\n", phb->type); - PPCDBG(PPCDBG_TCEINIT, "\tphb->phb_regs = 0x%lx\n", phb->phb_regs); - PPCDBG(PPCDBG_TCEINIT, "\tphb->chip_regs = 0x%lx\n", phb->chip_regs); - PPCDBG(PPCDBG_TCEINIT, "\tphb: node = 0x%lx\n", node); - PPCDBG(PPCDBG_TCEINIT, "\tphb->arch_data = 0x%lx\n", phb->arch_data); - - i = 0; - while(of_tce_table[i].node) { - if(of_tce_table[i].node == node) { - if(phb->type == phb_type_python) { - r = *(((unsigned int *)phb->phb_regs) + (0xf10>>2)); - PPCDBG(PPCDBG_TCEINIT, "\tTAR(low) = 0x%x\n", r); - r = *(((unsigned int *)phb->phb_regs) + (0xf00>>2)); - PPCDBG(PPCDBG_TCEINIT, "\tTAR(high) = 0x%x\n", r); - r = *(((unsigned int *)phb->phb_regs) + (0xfd0>>2)); - PPCDBG(PPCDBG_TCEINIT, "\tPHB cfg(rw) = 0x%x\n", r); - break; - } else if(phb->type == phb_type_speedwagon) { - r64 = *(((unsigned long *)phb->chip_regs) + - (0x800>>3)); - PPCDBG(PPCDBG_TCEINIT, "\tNCFG = 0x%lx\n", r64); - r64 = *(((unsigned long *)phb->chip_regs) + - (0x580>>3)); - PPCDBG(PPCDBG_TCEINIT, "\tTAR0 = 0x%lx\n", r64); - r64 = *(((unsigned long *)phb->chip_regs) + - (0x588>>3)); - PPCDBG(PPCDBG_TCEINIT, "\tTAR1 = 0x%lx\n", r64); - r64 = *(((unsigned long *)phb->chip_regs) + - (0x590>>3)); - PPCDBG(PPCDBG_TCEINIT, "\tTAR2 = 0x%lx\n", r64); - r64 = *(((unsigned long *)phb->chip_regs) + - (0x598>>3)); - PPCDBG(PPCDBG_TCEINIT, "\tTAR3 = 0x%lx\n", r64); - cfg_rw = *(((unsigned int *)phb->chip_regs) + - ((0x160 + - (((phb->local_number)+8)<<12))>>2)); - PPCDBG(PPCDBG_TCEINIT, "\tcfg_rw = 0x%x\n", cfg_rw); - } - } - i++; - } - - PPCDBG(PPCDBG_TCEINIT, "phb_tce_table_init: done\n"); - - return(0); -} - /* These are called very early. */ void tce_init_pSeries(void) { diff -Nru a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c --- a/arch/ppc64/kernel/pci_dn.c Fri Sep 20 08:20:48 2002 +++ b/arch/ppc64/kernel/pci_dn.c Fri Sep 20 08:20:48 2002 @@ -215,6 +215,7 @@ return NULL; } + /* Traversal func that looks for a value. * If found, the device_node is returned (thus terminating the traversal). */ @@ -223,7 +224,6 @@ { int busno = ((unsigned long)data >> 8) & 0xff; int devfn = ((unsigned long)data) & 0xff; - return (devfn == dn->devfn && busno == dn->busno) ? dn : NULL; } @@ -249,8 +249,9 @@ *eads = *other_eads; eads->devfn &= ~7; /* make it function zero */ eads->tce_table = NULL; - /* NOTE: share properties. We could copy but for now this should suffice. - * The full_name is also incorrect...but seems harmless. + /* + * NOTE: share properties. We could copy but for now this should + * suffice. The full_name is also incorrect...but seems harmless. */ eads->child = NULL; eads->next = NULL; @@ -285,21 +286,25 @@ dev->sysdata = dn; /* ToDo: call some device init hook here */ } else { - /* Now it is very possible that we can't find the device because it is - * not the zero'th device of a mutifunction device and we don't have - * permission to read the zero'th device. If this is the case, Linux - * would ordinarily skip all the other functions. + /* Now it is very possible that we can't find the device + * because it is not the zero'th device of a mutifunction + * device and we don't have permission to read the zero'th + * device. If this is the case, Linux would ordinarily skip + * all the other functions. */ if ((searchval & 0x7) == 0) { struct device_node *thisdevdn; /* Ok, we are looking for fn == 0. Let's check for other functions. */ thisdevdn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_sub_node, NULL, (void *)searchval); if (thisdevdn) { - /* Ah ha! There does exist a sub function. Now this isn't an exact - * match for searchval, but in order to get Linux to believe the sub - * functions exist we will need to manufacture a fake device_node - * for this zero'th function. To keept this simple for now we only - * handle pci bridges and we just hand back the found node which + /* Ah ha! There does exist a sub function. + * Now this isn't an exact match for + * searchval, but in order to get Linux to + * believe the sub functions exist we will + * need to manufacture a fake device_node for + * this zero'th function. To keept this + * simple for now we only handle pci bridges + * and we just hand back the found node which * isn't correct, but Linux won't care. */ char *device_type = (char *)get_property(thisdevdn, "device_type", 0); @@ -367,7 +372,6 @@ pci_fixup_bus_sysdata_list(&bus->children); } } - /****************************************************************** * Fixup the bus->sysdata ptrs to point to the bus' device_node. diff -Nru a/arch/ppc64/kernel/ppc_asm.h b/arch/ppc64/kernel/ppc_asm.h --- a/arch/ppc64/kernel/ppc_asm.h Fri Sep 20 08:20:44 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,115 +0,0 @@ -/* - * arch/ppc64/kernel/ppc_asm.h - * - * Definitions used by various bits of low-level assembly code on PowerPC. - * - * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include "ppc_defs.h" - -/* - * Macros for storing registers into and loading registers from - * exception frames. - */ -#define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) -#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) -#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) -#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) -#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) -#define REST_GPR(n, base) ld n,GPR0+8*(n)(base) -#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) -#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) -#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) -#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) - -#define SAVE_FPR(n, base) stfd n,THREAD_FPR0+8*(n)(base) -#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) -#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) -#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base) -#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base) -#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base) -#define REST_FPR(n, base) lfd n,THREAD_FPR0+8*(n)(base) -#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base) -#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base) -#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base) -#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) -#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) - -#define CHECKANYINT(ra,rb) \ - mfspr rb,SPRG3; /* Get Paca address */\ - ld ra,PACALPPACA+LPPACAANYINT(rb); /* Get pending interrupt flags */\ - cmpldi 0,ra,0; - -/* Macros to adjust thread priority for Iseries hardware multithreading */ -#define HMT_LOW or 1,1,1 -#define HMT_MEDIUM or 2,2,2 -#define HMT_HIGH or 3,3,3 - -/* Insert the high 32 bits of the MSR into what will be the new - MSR (via SRR1 and rfid) This preserves the MSR.SF and MSR.ISF - bits. */ - -#define FIX_SRR1(ra, rb) \ - mr rb,ra; \ - mfmsr ra; \ - rldimi ra,rb,0,32 - -#define CLR_TOP32(r) rlwinm (r),(r),0,0,31 /* clear top 32 bits */ - -/* - * LOADADDR( rn, name ) - * loads the address of 'name' into 'rn' - * - * LOADBASE( rn, name ) - * loads the address (less the low 16 bits) of 'name' into 'rn' - * suitable for base+disp addressing - */ -#define LOADADDR(rn,name) \ - lis rn,name##@highest; \ - ori rn,rn,name##@higher; \ - rldicr rn,rn,32,31; \ - oris rn,rn,name##@h; \ - ori rn,rn,name##@l - -#define LOADBASE(rn,name) \ - lis rn,name@highest; \ - ori rn,rn,name@higher; \ - rldicr rn,rn,32,31; \ - oris rn,rn,name@ha - - -#define SET_REG_TO_CONST(reg, value) \ - lis reg,(((value)>>48)&0xFFFF); \ - ori reg,reg,(((value)>>32)&0xFFFF); \ - rldicr reg,reg,32,31; \ - oris reg,reg,(((value)>>16)&0xFFFF); \ - ori reg,reg,((value)&0xFFFF); - -#define SET_REG_TO_LABEL(reg, label) \ - lis reg,(label)@highest; \ - ori reg,reg,(label)@higher; \ - rldicr reg,reg,32,31; \ - oris reg,reg,(label)@h; \ - ori reg,reg,(label)@l; - - -/* PPPBBB - DRENG If KERNELBASE is always 0xC0..., - * Then we can easily do this with one asm insn. -Peter - */ -#define tophys(rd,rs) \ - lis rd,((KERNELBASE>>48)&0xFFFF); \ - rldicr rd,rd,32,31; \ - sub rd,rs,rd - -#define tovirt(rd,rs) \ - lis rd,((KERNELBASE>>48)&0xFFFF); \ - rldicr rd,rd,32,31; \ - add rd,rs,rd - diff -Nru a/arch/ppc64/kernel/ppc_defs.head b/arch/ppc64/kernel/ppc_defs.head --- a/arch/ppc64/kernel/ppc_defs.head Fri Sep 20 08:20:44 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,3 +0,0 @@ -/* - * WARNING! This file is automatically generated - DO NOT EDIT! - */ diff -Nru a/arch/ppc64/kernel/proc_pmc.c b/arch/ppc64/kernel/proc_pmc.c --- a/arch/ppc64/kernel/proc_pmc.c Fri Sep 20 08:20:44 2002 +++ b/arch/ppc64/kernel/proc_pmc.c Fri Sep 20 08:20:44 2002 @@ -24,7 +24,6 @@ * End Change Activity */ -#include #include #include diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c --- a/arch/ppc64/kernel/process.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/process.c Fri Sep 20 08:20:47 2002 @@ -169,6 +169,8 @@ extern void ret_from_fork(void); unsigned long sp = (unsigned long)p->thread_info + THREAD_SIZE; + p->user_tid = NULL; + /* Copy registers */ sp -= sizeof(struct pt_regs); childregs = (struct pt_regs *) sp; @@ -260,13 +262,19 @@ u32 p6, struct pt_regs *regs) { struct task_struct *p; - int *user_tid = (int *)p3; + unsigned long tid_ptr = 0; + + if (clone_flags & (CLONE_SETTID | CLONE_CLEARTID)) { + tid_ptr = p3; + if (test_thread_flag(TIF_32BIT)) + tid_ptr &= 0xffffffff; + } if (regs->msr & MSR_FP) giveup_fpu(current); p = do_fork(clone_flags & ~CLONE_IDLETASK, regs->gpr[1], regs, 0, - user_tid); + (int *)tid_ptr); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } diff -Nru a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c --- a/arch/ppc64/kernel/rtas.c Fri Sep 20 08:20:42 2002 +++ b/arch/ppc64/kernel/rtas.c Fri Sep 20 08:20:42 2002 @@ -141,7 +141,7 @@ rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); va_start(list, outputs); for (i = 0; i < nargs; ++i) { - rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong)); + rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong)); PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]); } va_end(list); @@ -164,8 +164,8 @@ spin_unlock_irqrestore(&rtas.lock, s); #endif ifppcdebug(PPCDBG_RTAS) { - for(i=0; i < nret ;i++) - udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); + for(i=0; i < nret ;i++) + udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); } if (nret > 1 && outputs != NULL) diff -Nru a/arch/ppc64/kernel/rtas_flash.c b/arch/ppc64/kernel/rtas_flash.c --- a/arch/ppc64/kernel/rtas_flash.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/rtas_flash.c Fri Sep 20 08:20:47 2002 @@ -14,8 +14,6 @@ */ #include - -#include #include #include #include diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c --- a/arch/ppc64/kernel/signal.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc64/kernel/signal.c Fri Sep 20 08:20:41 2002 @@ -159,11 +159,10 @@ } } - - -long sys_sigaltstack(const stack_t *uss, stack_t *uoss) +long sys_sigaltstack(const stack_t *uss, stack_t *uoss, unsigned long r5, + unsigned long r6, unsigned long r7, unsigned long r8, + struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *)&uss; return do_sigaltstack(uss, uoss, regs->gpr[1]); } @@ -250,7 +249,7 @@ goto badframe; /* This function sets back the stack flags into the current task structure. */ - sys_sigaltstack(&st, NULL); + sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs); return regs->result; diff -Nru a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c --- a/arch/ppc64/kernel/signal32.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/signal32.c Fri Sep 20 08:20:47 2002 @@ -298,7 +298,8 @@ regs->dsisr = 0; regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF; - if (copy_from_user(current->thread.fpr, &sr->fp_regs, sizeof(sr->fp_regs))) + if (copy_from_user(current->thread.fpr, &sr->fp_regs, + sizeof(sr->fp_regs))) goto badframe; ret = regs->result; @@ -392,7 +393,6 @@ return; badframe: - udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); PPCDBG_ENTER_DEBUGGER(); #if DEBUG_SIG printk("badframe in setup_frame32, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); @@ -421,7 +421,6 @@ * siginfo32to64 */ - /* * This code executes after the rt signal handler in 32 bit mode has * completed and returned @@ -438,6 +437,7 @@ sigset_t set; stack_t st; int i; + mm_segment_t old_fs; /* Adjust the inputted reg1 to point to the first rt signal frame */ rt_sf = (struct rt_sigframe_32 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32); @@ -509,6 +509,16 @@ regs->dar = 0; regs->dsisr = 0; regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF; + if (copy_from_user(current->thread.fpr, &sr->fp_regs, + sizeof(sr->fp_regs))) + goto badframe; + /* This function sets back the stack flags into + the current task structure. */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + do_sigaltstack(&st, NULL, regs->gpr[1]); + set_fs(old_fs); + ret = regs->result; return ret; @@ -933,7 +943,6 @@ return; badframe: - udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); PPCDBG_ENTER_DEBUGGER(); #if DEBUG_SIG printk("badframe in setup_frame32, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); @@ -1036,7 +1045,7 @@ */ int sys32_sigaltstack(u32 newstack, u32 oldstack, int p3, - int p4, int p6, int p7, struct pt_regs *regs) + int p4, int p6, int p7, struct pt_regs *regs) { stack_t uss, uoss; int ret; diff -Nru a/arch/ppc64/kernel/stab.c b/arch/ppc64/kernel/stab.c --- a/arch/ppc64/kernel/stab.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/stab.c Fri Sep 20 08:20:47 2002 @@ -303,11 +303,13 @@ */ static void preload_stab(struct task_struct *tsk, struct mm_struct *mm) { - if (ppc64_preload_all_segments && test_tsk_thread_flag(tsk, TIF_32BIT)) { + if (ppc64_preload_all_segments && + test_tsk_thread_flag(tsk, TIF_32BIT)) { unsigned long esid, vsid; for (esid = 0; esid < 16; esid++) { - vsid = get_vsid(mm->context, esid << SID_SHIFT); + unsigned long ea = esid << SID_SHIFT; + vsid = get_vsid(mm->context, ea); __ste_allocate(esid, vsid, 0); } } else { @@ -318,15 +320,17 @@ unsigned long vsid; if (pc) { - if (REGION_ID(pc) >= KERNEL_REGION_ID) - BUG(); + if (!IS_VALID_EA(pc) || + (REGION_ID(pc) >= KERNEL_REGION_ID)) + return; vsid = get_vsid(mm->context, pc); __ste_allocate(GET_ESID(pc), vsid, 0); } if (stack && (pc_segment != stack_segment)) { - if (REGION_ID(stack) >= KERNEL_REGION_ID) - BUG(); + if (!IS_VALID_EA(stack) || + (REGION_ID(stack) >= KERNEL_REGION_ID)) + return; vsid = get_vsid(mm->context, stack); __ste_allocate(GET_ESID(stack), vsid, 0); } diff -Nru a/arch/ppc64/kernel/sys32.S b/arch/ppc64/kernel/sys32.S --- a/arch/ppc64/kernel/sys32.S Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/sys32.S Fri Sep 20 08:20:47 2002 @@ -15,7 +15,7 @@ * 2 of the License, or (at your option) any later version. */ -#include "ppc_asm.h" +#include #include #include diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c --- a/arch/ppc64/kernel/sys_ppc32.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/sys_ppc32.c Fri Sep 20 08:20:47 2002 @@ -213,7 +213,7 @@ goto bad_file; if (file->f_op && (file->f_mode & FMODE_READ) && - (file->f_op->readv || file->f_op->read)) + (file->f_op->readv || file->f_op->read)) ret = do_readv_writev32(VERIFY_WRITE, file, vector, count); fput(file); @@ -238,8 +238,6 @@ return ret; } - - static inline int get_flock(struct flock *kfl, struct flock32 *ufl) { int err; @@ -656,8 +654,8 @@ char *bits; unsigned long nn; long timeout; - int ret, size; - + int ret, size, max_fdset; + timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { time_t sec, usec; @@ -679,8 +677,11 @@ ret = -EINVAL; if (n < 0) goto out_nofds; - if (n > current->files->max_fdset) - n = current->files->max_fdset; + + /* max_fdset can increase, so grab it once to avoid race */ + max_fdset = current->files->max_fdset; + if (n > max_fdset) + n = max_fdset; /* * We need 6 bitmaps (in/out/ex for both incoming and outgoing), @@ -4285,6 +4286,32 @@ return ret; } +int sys32_olduname(struct oldold_utsname * name) +{ + int error; + + if (!name) + return -EFAULT; + if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) + return -EFAULT; + + down_read(&uts_sem); + error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + error -= __put_user(0,name->sysname+__OLD_UTS_LEN); + error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + error -= __put_user(0,name->nodename+__OLD_UTS_LEN); + error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error -= __put_user(0,name->release+__OLD_UTS_LEN); + error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error -= __put_user(0,name->version+__OLD_UTS_LEN); + error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error = __put_user(0,name->machine+__OLD_UTS_LEN); + up_read(&uts_sem); + + error = error ? -EFAULT : 0; + + return error; +} extern unsigned long sys_mmap(unsigned long addr, size_t len, unsigned long prot, unsigned long flags, unsigned long fd, off_t offset); diff -Nru a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c --- a/arch/ppc64/kernel/syscalls.c Fri Sep 20 08:20:42 2002 +++ b/arch/ppc64/kernel/syscalls.c Fri Sep 20 08:20:42 2002 @@ -218,32 +218,6 @@ return err; } -asmlinkage int sys_olduname(struct oldold_utsname * name) -{ - int error; - - if (!name) - return -EFAULT; - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) - return -EFAULT; - - down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); - error -= __put_user(0,name->sysname+__OLD_UTS_LEN); - error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); - error -= __put_user(0,name->nodename+__OLD_UTS_LEN); - error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); - error -= __put_user(0,name->release+__OLD_UTS_LEN); - error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); - error -= __put_user(0,name->version+__OLD_UTS_LEN); - error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); - error = __put_user(0,name->machine+__OLD_UTS_LEN); - up_read(&uts_sem); - - error = error ? -EFAULT : 0; - - return error; -} asmlinkage time_t sys64_time(time_t* tloc) { diff -Nru a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c --- a/arch/ppc64/kernel/time.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/kernel/time.c Fri Sep 20 08:20:47 2002 @@ -469,11 +469,6 @@ last_rtc_update = xtime.tv_sec; write_unlock_irqrestore(&xtime_lock, flags); -#ifdef CONFIG_PPC_ISERIES - /* HACK HACK This allows the iSeries profiling to use /proc/profile */ - prof_shift = 0; -#endif - /* Not exact, but the timer interrupt takes care of this */ set_dec(tb_ticks_per_jiffy); } diff -Nru a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c --- a/arch/ppc64/kernel/traps.c Fri Sep 20 08:20:46 2002 +++ b/arch/ppc64/kernel/traps.c Fri Sep 20 08:20:46 2002 @@ -1,5 +1,5 @@ /* - * linux/arch/ppc/kernel/traps.c + * linux/arch/ppc64/kernel/traps.c * * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * diff -Nru a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c --- a/arch/ppc64/kernel/xics.c Fri Sep 20 08:20:41 2002 +++ b/arch/ppc64/kernel/xics.c Fri Sep 20 08:20:41 2002 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff -Nru a/arch/ppc64/kernel/xics.h b/arch/ppc64/kernel/xics.h --- a/arch/ppc64/kernel/xics.h Fri Sep 20 08:20:46 2002 +++ b/arch/ppc64/kernel/xics.h Fri Sep 20 08:20:46 2002 @@ -12,8 +12,6 @@ #ifndef _PPC_KERNEL_XICS_H #define _PPC_KERNEL_XICS_H -#include "local_irq.h" - extern struct hw_interrupt_type xics_pic; extern struct hw_interrupt_type xics_8259_pic; diff -Nru a/arch/ppc64/lib/checksum.S b/arch/ppc64/lib/checksum.S --- a/arch/ppc64/lib/checksum.S Fri Sep 20 08:20:45 2002 +++ b/arch/ppc64/lib/checksum.S Fri Sep 20 08:20:45 2002 @@ -15,7 +15,7 @@ #include #include #include -#include +#include /* * ip_fast_csum(r3=buf, r4=len) -- Optimized for IP header diff -Nru a/arch/ppc64/lib/copypage.S b/arch/ppc64/lib/copypage.S --- a/arch/ppc64/lib/copypage.S Fri Sep 20 08:20:41 2002 +++ b/arch/ppc64/lib/copypage.S Fri Sep 20 08:20:41 2002 @@ -9,7 +9,7 @@ * 2 of the License, or (at your option) any later version. */ #include -#include "../kernel/ppc_asm.h" +#include _GLOBAL(copy_page) std r31,-8(1) diff -Nru a/arch/ppc64/lib/copyuser.S b/arch/ppc64/lib/copyuser.S --- a/arch/ppc64/lib/copyuser.S Fri Sep 20 08:20:48 2002 +++ b/arch/ppc64/lib/copyuser.S Fri Sep 20 08:20:48 2002 @@ -9,7 +9,7 @@ * 2 of the License, or (at your option) any later version. */ #include -#include "../kernel/ppc_asm.h" +#include .align 7 _GLOBAL(__copy_tofrom_user) diff -Nru a/arch/ppc64/lib/memcpy.S b/arch/ppc64/lib/memcpy.S --- a/arch/ppc64/lib/memcpy.S Fri Sep 20 08:20:41 2002 +++ b/arch/ppc64/lib/memcpy.S Fri Sep 20 08:20:41 2002 @@ -9,7 +9,7 @@ * 2 of the License, or (at your option) any later version. */ #include -#include "../kernel/ppc_asm.h" +#include .align 7 _GLOBAL(memcpy) diff -Nru a/arch/ppc64/lib/string.S b/arch/ppc64/lib/string.S --- a/arch/ppc64/lib/string.S Fri Sep 20 08:20:43 2002 +++ b/arch/ppc64/lib/string.S Fri Sep 20 08:20:43 2002 @@ -8,9 +8,9 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include #include #include +#include _GLOBAL(strcpy) addi r5,r3,-1 diff -Nru a/arch/ppc64/mm/Makefile b/arch/ppc64/mm/Makefile --- a/arch/ppc64/mm/Makefile Fri Sep 20 08:20:41 2002 +++ b/arch/ppc64/mm/Makefile Fri Sep 20 08:20:41 2002 @@ -12,5 +12,6 @@ O_TARGET := mm.o obj-y := fault.o init.o extable.o imalloc.o +obj-$(CONFIG_DISCONTIGMEM) += numa.o include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c --- a/arch/ppc64/mm/init.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/mm/init.c Fri Sep 20 08:20:47 2002 @@ -99,23 +99,26 @@ void show_mem(void) { - int pfn, total = 0, reserved = 0; + int total = 0, reserved = 0; int shared = 0, cached = 0; struct page *page; + pg_data_t *pgdat; + unsigned long i; printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - pfn = max_mapnr; - while (pfn-- > 0) { - page = pfn_to_page(pfn); - total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page) - 1; + for_each_pgdat(pgdat) { + for (i = 0; i < pgdat->node_size; i++) { + page = pgdat->node_mem_map + i; + total++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page) - 1; + } } printk("%d pages of RAM\n",total); printk("%d reserved pages\n",reserved); @@ -382,7 +385,7 @@ free_page(addr); totalram_pages++; } - printk ("Freeing unused kernel memory: %dk freed\n", + printk ("Freeing unused kernel memory: %luk freed\n", (&__init_end - &__init_begin) >> 10); } @@ -498,13 +501,6 @@ } #endif -extern unsigned long prof_shift; -extern unsigned long prof_len; -extern unsigned int * prof_buffer; -extern unsigned long dprof_shift; -extern unsigned long dprof_len; -extern unsigned int * dprof_buffer; - void initialize_paca_hardware_interrupt_stack(void); void __init mem_init(void) @@ -518,9 +514,8 @@ int datapages = 0; int initpages = 0; - max_mapnr = max_low_pfn; + num_physpages = max_low_pfn; /* RAM is assumed contiguous */ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); - num_physpages = max_mapnr; /* RAM is assumed contiguous */ max_pfn = max_low_pfn; #ifdef CONFIG_DISCONTIGMEM @@ -542,6 +537,8 @@ PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM())); } #else + max_mapnr = num_physpages; + totalram_pages += free_all_bootmem(); if ( sysmap_size ) @@ -577,10 +574,6 @@ #ifdef CONFIG_PPC_ISERIES create_virtual_bus_tce_table(); - /* HACK HACK This allows the iSeries profiling to use /proc/profile */ - prof_shift = dprof_shift; - prof_len = dprof_len; - prof_buffer = dprof_buffer; #endif } diff -Nru a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc64/mm/numa.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,171 @@ +/* + * NUMA support + * + * Copyright (C) 2002 Anton Blanchard , IBM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include + +#if 0 +#define dbg(format, arg...) udbg_printf(format, arg) +#else +#define dbg(format, arg...) +#endif + +int numa_cpu_lookup_table[NR_CPUS] = { [ 0 ... (NR_CPUS - 1)] = -1}; +int numa_memory_lookup_table[MAX_MEMORY >> MEMORY_INCREMENT_SHIFT] = + { [ 0 ... ((MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1)] = -1}; +int numa_node_exists[MAX_NUMNODES]; + +struct pglist_data node_data[MAX_NUMNODES]; +bootmem_data_t plat_node_bdata[MAX_NUMNODES]; + +static int __init parse_numa_properties(void) +{ + /* XXX implement */ + return -1; +} + +void __init do_init_bootmem(void) +{ + int nid; + + min_low_pfn = 0; + max_low_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT; + + if (parse_numa_properties()) + BUG(); + + for (nid = 0; nid < MAX_NUMNODES; nid++) { + unsigned long start, end; + unsigned long start_paddr, end_paddr; + int i; + unsigned long bootmem_paddr; + unsigned long bootmap_size; + + if (!numa_node_exists[nid]) + continue; + + /* Find start and end of this zone */ + start = 0; + while (numa_memory_lookup_table[start] != nid) + start++; + + end = (MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1; + while (numa_memory_lookup_table[end] != nid) + end--; + end++; + + start_paddr = start << MEMORY_INCREMENT_SHIFT; + end_paddr = end << MEMORY_INCREMENT_SHIFT; + + dbg("node %d\n", nid); + dbg("start_paddr = %lx\n", start_paddr); + dbg("end_paddr = %lx\n", end_paddr); + + NODE_DATA(nid)->bdata = &plat_node_bdata[nid]; + + /* XXX FIXME: first bitmap hardwired to 1G */ + if (start_paddr == 0) + bootmem_paddr = (1 << 30); + else + bootmem_paddr = start_paddr; + + dbg("bootmap_paddr = %lx\n", bootmem_paddr); + + bootmap_size = init_bootmem_node(NODE_DATA(nid), + bootmem_paddr >> PAGE_SHIFT, + start_paddr >> PAGE_SHIFT, + end_paddr >> PAGE_SHIFT); + + dbg("bootmap_size = %lx\n", bootmap_size); + + for (i = 0; i < lmb.memory.cnt; i++) { + unsigned long physbase, size; + unsigned long type = lmb.memory.region[i].type; + + if (type != LMB_MEMORY_AREA) + continue; + + physbase = lmb.memory.region[i].physbase; + size = lmb.memory.region[i].size; + + if (physbase < end_paddr && + (physbase+size) > start_paddr) { + /* overlaps */ + if (physbase < start_paddr) { + size -= start_paddr - physbase; + physbase = start_paddr; + } + + if (size > end_paddr - start_paddr) + size = end_paddr - start_paddr; + + dbg("free_bootmem %lx %lx\n", physbase, size); + free_bootmem_node(NODE_DATA(nid), physbase, + size); + } + } + + for (i = 0; i < lmb.reserved.cnt; i++) { + unsigned long physbase = lmb.reserved.region[i].physbase; + unsigned long size = lmb.reserved.region[i].size; + + if (physbase < end_paddr && + (physbase+size) > start_paddr) { + /* overlaps */ + if (physbase < start_paddr) { + size -= start_paddr - physbase; + physbase = start_paddr; + } + + if (size > end_paddr - start_paddr) + size = end_paddr - start_paddr; + + dbg("reserve_bootmem %lx %lx\n", physbase, + size); + reserve_bootmem_node(NODE_DATA(nid), physbase, + size); + } + } + + dbg("reserve_bootmem %lx %lx\n", bootmem_paddr, bootmap_size); + reserve_bootmem_node(NODE_DATA(nid), bootmem_paddr, + bootmap_size); + } +} + +void __init paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES]; + int i, nid; + + for (i = 1; i < MAX_NR_ZONES; i++) + zones_size[i] = 0; + + for (nid = 0; nid < MAX_NUMNODES; nid++) { + unsigned long start_pfn; + unsigned long end_pfn; + + if (!numa_node_exists[nid]) + continue; + + start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT; + end_pfn = plat_node_bdata[nid].node_low_pfn; + + zones_size[ZONE_DMA] = end_pfn - start_pfn; + dbg("free_area_init node %d %lx %lx\n", nid, zones_size, + start_pfn); + free_area_init_node(nid, NODE_DATA(nid), NULL, zones_size, + start_pfn, NULL); + } +} diff -Nru a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c --- a/arch/ppc64/xmon/xmon.c Fri Sep 20 08:20:47 2002 +++ b/arch/ppc64/xmon/xmon.c Fri Sep 20 08:20:47 2002 @@ -332,10 +332,10 @@ cmd = cmds(excp); if (cmd == 's') { xmon_trace[smp_processor_id()] = SSTEP; - excp->msr |= 0x400; + excp->msr |= MSR_SE; } else if (at_breakpoint(excp->nip)) { xmon_trace[smp_processor_id()] = BRSTEP; - excp->msr |= 0x400; + excp->msr |= MSR_SE; } else { xmon_trace[smp_processor_id()] = 0; insert_bpts(); @@ -450,7 +450,7 @@ remove_bpts(); excprint(regs); xmon_trace[smp_processor_id()] = BRSTEP; - regs->msr |= 0x400; + regs->msr |= MSR_SE; } else { printf("Stopped at breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname); xmon(regs); @@ -480,7 +480,7 @@ remove_bpts(); excprint(regs); xmon_trace[smp_processor_id()] = BRSTEP; - regs->msr |= 0x400; + regs->msr |= MSR_SE; } else { dabr.instr = regs->nip; xmon(regs); @@ -496,7 +496,7 @@ remove_bpts(); excprint(regs); xmon_trace[smp_processor_id()] = BRSTEP; - regs->msr |= 0x400; + regs->msr |= MSR_SE; } else { xmon(regs); } @@ -734,7 +734,7 @@ printf("cpus stopped:"); for (cpu = 0; cpu < NR_CPUS; ++cpu) { if (test_bit(cpu, &cpus_in_xmon)) { - printf(" %d", cpu); + printf(" %x", cpu); if (cpu == smp_processor_id()) printf("*", cpu); } diff -Nru a/arch/s390/vmlinux.lds.S b/arch/s390/vmlinux.lds.S --- a/arch/s390/vmlinux.lds.S Fri Sep 20 08:20:44 2002 +++ b/arch/s390/vmlinux.lds.S Fri Sep 20 08:20:44 2002 @@ -4,4 +4,4 @@ #include "vmlinux-shared.lds" #else #include "vmlinux.lds" -#endif \ No newline at end of file +#endif diff -Nru a/arch/s390x/vmlinux.lds.S b/arch/s390x/vmlinux.lds.S --- a/arch/s390x/vmlinux.lds.S Fri Sep 20 08:20:44 2002 +++ b/arch/s390x/vmlinux.lds.S Fri Sep 20 08:20:44 2002 @@ -4,4 +4,4 @@ #include "vmlinux-shared.lds" #else #include "vmlinux.lds" -#endif \ No newline at end of file +#endif diff -Nru a/arch/sparc/Makefile b/arch/sparc/Makefile --- a/arch/sparc/Makefile Fri Sep 20 08:20:42 2002 +++ b/arch/sparc/Makefile Fri Sep 20 08:20:42 2002 @@ -40,7 +40,7 @@ CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES) \ arch/sparc/math-emu/math-emu.o -LIBS := $(LIBS) arch/sparc/prom/promlib.a arch/sparc/lib/lib.a +LIBS := $(LIBS) arch/sparc/prom/lib.a arch/sparc/lib/lib.a # This one has to come last SUBDIRS += arch/sparc/boot diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in --- a/arch/sparc/config.in Fri Sep 20 08:20:41 2002 +++ b/arch/sparc/config.in Fri Sep 20 08:20:41 2002 @@ -208,6 +208,8 @@ endmenu fi +source net/ax25/Config.in + # This one must be before the filesystem configs. -DaveM mainmenu_option next_comment comment 'Unix98 PTY support' diff -Nru a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c --- a/arch/sparc/kernel/setup.c Fri Sep 20 08:20:41 2002 +++ b/arch/sparc/kernel/setup.c Fri Sep 20 08:20:41 2002 @@ -171,31 +171,23 @@ /* Process any command switches, otherwise skip it. */ if (*commands == '\0') break; - else if (*commands == '-') { + if (*commands == '-') { commands++; while (*commands && *commands != ' ') process_switch(*commands++); } else { if (!strncmp(commands, "console=", 8)) { commands += 8; - if (!strncmp (commands, "ttya", 4)) { - console_fb = 2; - prom_printf ("Using /dev/ttya as console.\n"); - } else if (!strncmp (commands, "ttyb", 4)) { - console_fb = 3; - prom_printf ("Using /dev/ttyb as console.\n"); #if defined(CONFIG_PROM_CONSOLE) - } else if (!strncmp (commands, "prom", 4)) { + if (!strncmp (commands, "prom", 4)) { char *p; for (p = commands - 8; *p && *p != ' '; p++) *p = ' '; conswitchp = &prom_con; console_fb = 1; -#endif - } else { - console_fb = 1; } +#endif } else if (!strncmp(commands, "mem=", 4)) { /* * "mem=XXX[kKmM] overrides the PROM-reported @@ -342,33 +334,28 @@ #ifndef CONFIG_SERIAL_CONSOLE /* Not CONFIG_SERIAL_SUNCORE: to be gone. */ serial_console = 0; #else - switch (console_fb) { - case 0: /* Let get our io devices from prom */ - { - int idev = prom_query_input_device(); - int odev = prom_query_output_device(); - if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { - serial_console = 0; - } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) { - serial_console = 1; - } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { - serial_console = 2; - } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) { - prom_printf("MrCoffee ttya\n"); - serial_console = 1; - } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) { - serial_console = 0; - prom_printf("MrCoffee keyboard\n"); - } else { - prom_printf("Inconsistent or unknown console\n"); - prom_printf("You cannot mix serial and non serial input/output devices\n"); - prom_halt(); - } + if (console_fb != 0) { + serial_console = 0; + } else { + int idev = prom_query_input_device(); + int odev = prom_query_output_device(); + if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { + serial_console = 0; + } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) { + serial_console = 1; + } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { + serial_console = 2; + } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) { + prom_printf("MrCoffee ttya\n"); + serial_console = 1; + } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) { + serial_console = 0; + prom_printf("MrCoffee keyboard\n"); + } else { + prom_printf("Confusing console (idev %d, odev %d)\n", + idev, odev); + serial_console = 1; } - break; - case 1: serial_console = 0; break; /* Force one of the framebuffers as console */ - case 2: serial_console = 1; break; /* Force ttya as console */ - case 3: serial_console = 2; break; /* Force ttyb as console */ } #endif diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c --- a/arch/sparc/kernel/sparc_ksyms.c Fri Sep 20 08:20:41 2002 +++ b/arch/sparc/kernel/sparc_ksyms.c Fri Sep 20 08:20:41 2002 @@ -46,6 +46,9 @@ #include #include #endif +#ifdef CONFIG_PCI +#include +#endif #include #include @@ -183,10 +186,7 @@ EXPORT_SYMBOL(sbus_ioremap); #endif #if CONFIG_PCI -/* Actually, ioremap/iounmap are not PCI specific. But it is ok for drivers. */ -EXPORT_SYMBOL(ioremap); -EXPORT_SYMBOL(iounmap); - +EXPORT_SYMBOL(ebus_chain); EXPORT_SYMBOL(insl); EXPORT_SYMBOL(outsl); EXPORT_SYMBOL(pci_alloc_consistent); @@ -194,6 +194,9 @@ EXPORT_SYMBOL(pci_map_single); EXPORT_SYMBOL(pci_unmap_single); EXPORT_SYMBOL(pci_dma_sync_single); +/* Actually, ioremap/iounmap are not PCI specific. But it is ok for drivers. */ +EXPORT_SYMBOL(ioremap); +EXPORT_SYMBOL(iounmap); #endif /* Solaris/SunOS binary compatibility */ diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c --- a/arch/sparc/mm/srmmu.c Fri Sep 20 08:20:46 2002 +++ b/arch/sparc/mm/srmmu.c Fri Sep 20 08:20:47 2002 @@ -316,6 +316,14 @@ unsigned long va_tmp, phys_tmp; int lowest_failed = 0; + if (size < SRMMU_NOCACHE_BITMAP_SHIFT) { + printk("Size 0x%x too small for nocache request\n", size); + size = SRMMU_NOCACHE_BITMAP_SHIFT; + } + if (size & (SRMMU_NOCACHE_BITMAP_SHIFT-1)) { + printk("Size 0x%x unaligned int nocache request\n", size); + size += SRMMU_NOCACHE_BITMAP_SHIFT-1; + } size = size >> SRMMU_NOCACHE_BITMAP_SHIFT; spin_lock(&srmmu_nocache_spinlock); @@ -376,8 +384,32 @@ void srmmu_free_nocache(unsigned long vaddr, int size) { - int offset = (vaddr - SRMMU_NOCACHE_VADDR) >> SRMMU_NOCACHE_BITMAP_SHIFT; + int offset; + if (vaddr < SRMMU_NOCACHE_VADDR) { + printk("Vaddr %x is smaller than nocache base 0x%x\n", + vaddr, SRMMU_NOCACHE_VADDR); + BUG(); + } + if (vaddr >= SRMMU_NOCACHE_END) { + printk("Vaddr %x is bigger than nocache end 0x%x\n", + vaddr, SRMMU_NOCACHE_END); + BUG(); + } + if (size & (size-1)) { + printk("Size 0x%x is not a power of 2\n", size); + BUG(); + } + if (size < SRMMU_NOCACHE_BITMAP_SHIFT) { + printk("Size 0x%x is too small\n", size); + BUG(); + } + if (vaddr & (size-1)) { + printk("Vaddr 0x%x is not aligned to size 0x%x\n", vaddr, size); + BUG(); + } + + offset = (vaddr - SRMMU_NOCACHE_VADDR) >> SRMMU_NOCACHE_BITMAP_SHIFT; size = size >> SRMMU_NOCACHE_BITMAP_SHIFT; spin_lock(&srmmu_nocache_spinlock); @@ -501,9 +533,13 @@ static void srmmu_pte_free(struct page *pte) { - unsigned long p = (unsigned long)page_address(pte); + unsigned long p; + + p = (unsigned long)page_address(pte); /* Cached address (for test) */ if (p == 0) BUG(); + p = ((pte - mem_map) << PAGE_SHIFT); /* Physical address */ + p = (unsigned long) __nocache_va(p); /* Nocached virtual */ srmmu_free_nocache(p, SRMMU_PTE_SZ_SOFT); } diff -Nru a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile --- a/arch/sparc/prom/Makefile Fri Sep 20 08:20:45 2002 +++ b/arch/sparc/prom/Makefile Fri Sep 20 08:20:46 2002 @@ -2,13 +2,8 @@ # Makefile for the Sun Boot PROM interface library under # Linux. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now in the main makefile... -L_TARGET = promlib.a +L_TARGET = lib.a obj-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \ palloc.o ranges.o segment.o console.o printf.o tree.o diff -Nru a/arch/sparc64/Config.help b/arch/sparc64/Config.help --- a/arch/sparc64/Config.help Fri Sep 20 08:20:48 2002 +++ b/arch/sparc64/Config.help Fri Sep 20 08:20:48 2002 @@ -25,6 +25,14 @@ If you don't know what to do here, say N. +CONFIG_HUGETLB_PAGE + This enables support for huge pages. User space applications + can make use of this support with the sys_alloc_hugepages and + sys_free_hugepages system calls. If your applications are + huge page aware, then say Y here. + + Otherwise, say N. + CONFIG_PREEMPT This option reduces the latency of the kernel when reacting to real-time or interactive events by allowing a low priority process to diff -Nru a/arch/sparc64/Makefile b/arch/sparc64/Makefile --- a/arch/sparc64/Makefile Fri Sep 20 08:20:48 2002 +++ b/arch/sparc64/Makefile Fri Sep 20 08:20:48 2002 @@ -8,6 +8,8 @@ # Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) # +AFLAGS_vmlinux.lds.o += -Usparc + # If the solaris /bin/sh wasn't so broken, I wouldn't need the following # line... SHELL =/bin/bash @@ -72,7 +74,7 @@ CORE_FILES += arch/sparc64/math-emu/math-emu.o -LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \ +LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/lib.a \ $(TOPDIR)/arch/sparc64/lib/lib.a vmlinux.aout: vmlinux diff -Nru a/arch/sparc64/config.in b/arch/sparc64/config.in --- a/arch/sparc64/config.in Fri Sep 20 08:20:44 2002 +++ b/arch/sparc64/config.in Fri Sep 20 08:20:44 2002 @@ -15,6 +15,8 @@ define_bool CONFIG_VT_CONSOLE y define_bool CONFIG_HW_CONSOLE y +bool 'SPARC64 Huge TLB Page Support' CONFIG_HUGETLB_PAGE + bool 'Symmetric multi-processing support' CONFIG_SMP bool 'Preemptible Kernel' CONFIG_PREEMPT @@ -218,6 +220,8 @@ fi endmenu fi + +source net/ax25/Config.in # This one must be before the filesystem configs. -DaveM mainmenu_option next_comment diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig Fri Sep 20 08:20:44 2002 +++ b/arch/sparc64/defconfig Fri Sep 20 08:20:44 2002 @@ -19,7 +19,7 @@ # Loadable module support # CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set +CONFIG_MODVERSIONS=y CONFIG_KMOD=y # @@ -29,6 +29,7 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y +CONFIG_HUGETLB_PAGE=y CONFIG_SMP=y # CONFIG_PREEMPT is not set CONFIG_SPARC64=y @@ -209,18 +210,8 @@ CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set # CONFIG_IDEDISK_STROKE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDECD_BAILOUT is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_IDE_TASK_IOCTL is not set @@ -254,6 +245,7 @@ # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_PIIX is not set # CONFIG_BLK_DEV_NFORCE is not set CONFIG_BLK_DEV_NS87415=y # CONFIG_BLK_DEV_OPTI621 is not set @@ -493,7 +485,6 @@ # CONFIG_LNE390 is not set CONFIG_FEALNX=m CONFIG_NATSEMI=m -# CONFIG_NATSEMI_CABLE_MAGIC is not set CONFIG_NE2K_PCI=m # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set @@ -575,6 +566,34 @@ # CONFIG_DM9102 is not set # +# Amateur Radio support +# +CONFIG_HAMRADIO=y + +# +# Packet Radio protocols +# +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_NETROM=m +CONFIG_ROSE=m + +# +# AX.25 network device drivers +# +# CONFIG_MKISS is not set +# CONFIG_6PACK is not set +# CONFIG_BPQETHER is not set +# CONFIG_SCC_DELAY is not set +# CONFIG_SCC_TRXECHO is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_SOUNDMODEM is not set +# CONFIG_YAM is not set + +# # Unix 98 PTY support # CONFIG_UNIX98_PTYS=y @@ -727,6 +746,10 @@ CONFIG_UDF_RW=y CONFIG_UFS_FS=m CONFIG_UFS_FS_WRITE=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_QUOTACTL=y # # Network File Systems diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c --- a/arch/sparc64/kernel/setup.c Fri Sep 20 08:20:44 2002 +++ b/arch/sparc64/kernel/setup.c Fri Sep 20 08:20:44 2002 @@ -151,7 +151,7 @@ pmd_t *pmdp; pte_t *ptep; - for_each_task(p) { + for_each_process(p) { mm = p->mm; if (CTX_HWBITS(mm->context) == ctx) break; diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c --- a/arch/sparc64/kernel/sparc64_ksyms.c Fri Sep 20 08:20:47 2002 +++ b/arch/sparc64/kernel/sparc64_ksyms.c Fri Sep 20 08:20:47 2002 @@ -363,7 +363,6 @@ EXPORT_SYMBOL(sun_do_break); EXPORT_SYMBOL(serial_console); EXPORT_SYMBOL(stop_a_enabled); -EXPORT_SYMBOL(kbd_pt_regs); #ifdef CONFIG_DEBUG_BUGVERBOSE EXPORT_SYMBOL(do_BUG); diff -Nru a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c --- a/arch/sparc64/kernel/sys_sparc.c Fri Sep 20 08:20:46 2002 +++ b/arch/sparc64/kernel/sys_sparc.c Fri Sep 20 08:20:46 2002 @@ -681,3 +681,100 @@ }; return err; } + +#ifdef CONFIG_HUGETLB_PAGE +#define HPAGE_ALIGN(x) (((unsigned long)x + (HPAGE_SIZE -1)) & HPAGE_MASK) +extern long sys_munmap(unsigned long, size_t); + +/* get_addr function gets the currently unused virtual range in + * the current process's address space. It returns the LARGE_PAGE_SIZE + * aligned address (in cases of success). Other kernel generic + * routines only could gurantee that allocated address is PAGE_SIZE aligned. + */ +static long get_addr(unsigned long addr, unsigned long len) +{ + struct vm_area_struct *vma; + if (addr) { + addr = HPAGE_ALIGN(addr); + vma = find_vma(current->mm, addr); + if (((TASK_SIZE - len) >= addr) && + (!vma || addr + len <= vma->vm_start)) + goto found_addr; + } + addr = HPAGE_ALIGN(TASK_UNMAPPED_BASE); + for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { + if (TASK_SIZE - len < addr) + return -ENOMEM; + if (!vma || ((addr + len) < vma->vm_start)) + goto found_addr; + addr = vma->vm_end; + } +found_addr: + addr = HPAGE_ALIGN(addr); + return addr; +} + +extern int alloc_hugetlb_pages(int, unsigned long, unsigned long, int, int); + +asmlinkage long +sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag) +{ + struct mm_struct *mm = current->mm; + unsigned long raddr; + int retval; + + if (key < 0) + return -EINVAL; + if (len & (HPAGE_SIZE - 1)) + return -EINVAL; + down_write(&mm->mmap_sem); + raddr = get_addr(addr, len); + retval = 0; + if (raddr == -ENOMEM) { + retval = -ENOMEM; + goto raddr_out; + } + retval = alloc_hugetlb_pages(key, raddr, len, prot, flag); + +raddr_out: + up_write(&mm->mmap_sem); + if (retval < 0) + return (long) retval; + + return raddr; +} + +extern int free_hugepages(struct vm_area_struct *); + +asmlinkage int +sys_free_hugepages(unsigned long addr) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + int retval; + + vma = find_vma(current->mm, addr); + if ((!vma) || (!is_vm_hugetlb_page(vma)) || (vma->vm_start!=addr)) + return -EINVAL; + down_write(&mm->mmap_sem); + spin_lock(&mm->page_table_lock); + retval = free_hugepages(vma); + spin_unlock(&mm->page_table_lock); + up_write(&mm->mmap_sem); + return retval; +} + +#else + +asmlinkage long +sys_alloc_hugepages(int key, unsigned long addr, size_t len, int prot, int flag) +{ + return -ENOSYS; +} +asmlinkage int +sys_free_hugepages(unsigned long addr) +{ + return -ENOSYS; +} + +#endif diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S --- a/arch/sparc64/kernel/systbls.S Fri Sep 20 08:20:45 2002 +++ b/arch/sparc64/kernel/systbls.S Fri Sep 20 08:20:45 2002 @@ -65,8 +65,8 @@ .word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex /*220*/ .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16 -/*230*/ .word sys32_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall - .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall +/*230*/ .word sys32_select, sys_time, sys_nis_syscall, sys_stime, sys_alloc_hugepages + .word sys_free_hugepages, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep /*250*/ .word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c --- a/arch/sparc64/kernel/traps.c Fri Sep 20 08:20:48 2002 +++ b/arch/sparc64/kernel/traps.c Fri Sep 20 08:20:48 2002 @@ -1566,17 +1566,14 @@ printk("\n"); } -void show_trace_task(struct task_struct *tsk) +void show_trace_raw(struct thread_info *tp, unsigned long ksp) { - unsigned long pc, fp; - unsigned long thread_base = (unsigned long) tsk->thread_info; + unsigned long pc, fp, thread_base; struct reg_window *rw; int count = 0; - if (!tsk) - return; - - fp = tsk->thread_info->ksp + STACK_BIAS; + fp = ksp + STACK_BIAS; + thread_base = (unsigned long) tp; do { /* Bogus frame pointer? */ if (fp < (thread_base + sizeof(struct thread_info)) || @@ -1588,6 +1585,13 @@ fp = rw->ins[6] + STACK_BIAS; } while (++count < 16); printk("\n"); +} + +void show_trace_task(struct task_struct *tsk) +{ + if (tsk) + show_trace_raw(tsk->thread_info, + tsk->thread_info->ksp); } void die_if_kernel(char *str, struct pt_regs *regs) diff -Nru a/arch/sparc64/mm/Makefile b/arch/sparc64/mm/Makefile --- a/arch/sparc64/mm/Makefile Fri Sep 20 08:20:47 2002 +++ b/arch/sparc64/mm/Makefile Fri Sep 20 08:20:47 2002 @@ -7,4 +7,6 @@ O_TARGET := mm.o obj-y := ultra.o fault.o init.o generic.o extable.o modutil.o +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o + include $(TOPDIR)/Rules.make diff -Nru a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c --- a/arch/sparc64/mm/fault.c Fri Sep 20 08:20:48 2002 +++ b/arch/sparc64/mm/fault.c Fri Sep 20 08:20:48 2002 @@ -130,8 +130,8 @@ return tally; } -void unhandled_fault(unsigned long address, struct task_struct *tsk, - struct pt_regs *regs) +static void unhandled_fault(unsigned long address, struct task_struct *tsk, + struct pt_regs *regs) { if ((unsigned long) address < PAGE_SIZE) { printk(KERN_ALERT "Unable to handle kernel NULL " @@ -148,6 +148,19 @@ die_if_kernel("Oops", regs); } +extern void show_trace_raw(struct thread_info *, unsigned long); + +static void bad_kernel_pc(struct pt_regs *regs) +{ + unsigned long ksp; + + printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n", + regs->tpc); + __asm__("mov %%sp, %0" : "=r" (ksp)); + show_trace_raw(current_thread_info(), ksp); + unhandled_fault(regs->tpc, current, regs); +} + /* * We now make sure that mmap_sem is held in all paths that call * this. Additionally, to prevent kswapd from ripping ptes from @@ -215,7 +228,7 @@ if (!regs->tpc || (regs->tpc & 0x3)) return 0; if (regs->tstate & TSTATE_PRIV) { - insn = *(unsigned int *)regs->tpc; + insn = *(unsigned int *) regs->tpc; } else { insn = get_user_insn(regs->tpc); } @@ -306,6 +319,20 @@ (fault_code & FAULT_CODE_DTLB)) BUG(); + if (regs->tstate & TSTATE_PRIV) { + unsigned long tpc = regs->tpc; + extern unsigned int _etext; + + /* Sanity check the PC. */ + if ((tpc >= KERNBASE && tpc < (unsigned long) &_etext) || + (tpc >= MODULES_VADDR && tpc < MODULES_END)) { + /* Valid, no problems... */ + } else { + bad_kernel_pc(regs); + return; + } + } + /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -314,7 +341,8 @@ goto intr_or_no_mm; if (test_thread_flag(TIF_32BIT)) { - regs->tpc &= 0xffffffff; + if (!(regs->tstate & TSTATE_PRIV)) + regs->tpc &= 0xffffffff; address &= 0xffffffff; } diff -Nru a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/sparc64/mm/hugetlbpage.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,621 @@ +/* + * SPARC64 Huge TLB page support. + * + * Copyright (C) 2002 David S. Miller (davem@redhat.com) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static struct vm_operations_struct hugetlb_vm_ops; +struct list_head htlbpage_freelist; +spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED; +extern long htlbpagemem; + +static void zap_hugetlb_resources(struct vm_area_struct *); + +#define MAX_ID 32 +struct htlbpagekey { + struct inode *in; + int key; +} htlbpagek[MAX_ID]; + +static struct inode *find_key_inode(int key) +{ + int i; + + for (i = 0; i < MAX_ID; i++) { + if (htlbpagek[i].key == key) + return htlbpagek[i].in; + } + return NULL; +} + +static struct page *alloc_hugetlb_page(void) +{ + struct list_head *curr, *head; + struct page *page; + + spin_lock(&htlbpage_lock); + + head = &htlbpage_freelist; + curr = head->next; + + if (curr == head) { + spin_unlock(&htlbpage_lock); + return NULL; + } + page = list_entry(curr, struct page, list); + list_del(curr); + htlbpagemem--; + + spin_unlock(&htlbpage_lock); + + set_page_count(page, 1); + memset(page_address(page), 0, HPAGE_SIZE); + + return page; +} + +static void free_hugetlb_page(struct page *page) +{ + spin_lock(&htlbpage_lock); + if ((page->mapping != NULL) && (page_count(page) == 2)) { + struct inode *inode = page->mapping->host; + int i; + + ClearPageDirty(page); + remove_from_page_cache(page); + set_page_count(page, 1); + if ((inode->i_size -= HPAGE_SIZE) == 0) { + for (i = 0; i < MAX_ID; i++) { + if (htlbpagek[i].key == inode->i_ino) { + htlbpagek[i].key = 0; + htlbpagek[i].in = NULL; + break; + } + } + kfree(inode); + } + } + if (put_page_testzero(page)) { + list_add(&page->list, &htlbpage_freelist); + htlbpagemem++; + } + spin_unlock(&htlbpage_lock); +} + +static pte_t *huge_pte_alloc_map(struct mm_struct *mm, unsigned long addr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte = NULL; + + pgd = pgd_offset(mm, addr); + if (pgd) { + pmd = pmd_alloc(mm, pgd, addr); + if (pmd) + pte = pte_alloc_map(mm, pmd, addr); + } + return pte; +} + +static pte_t *huge_pte_offset_map(struct mm_struct *mm, unsigned long addr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte = NULL; + + pgd = pgd_offset(mm, addr); + if (pgd) { + pmd = pmd_offset(pgd, addr); + if (pmd) + pte = pte_offset_map(pmd, addr); + } + return pte; +} + +static pte_t *huge_pte_offset_map_nested(struct mm_struct *mm, unsigned long addr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte = NULL; + + pgd = pgd_offset(mm, addr); + if (pgd) { + pmd = pmd_offset(pgd, addr); + if (pmd) + pte = pte_offset_map_nested(pmd, addr); + } + return pte; +} + +#define mk_pte_huge(entry) do { pte_val(entry) |= _PAGE_SZ4MB; } while (0) + +static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, + struct page *page, pte_t * page_table, int write_access) +{ + pte_t entry; + unsigned long i; + + mm->rss += (HPAGE_SIZE / PAGE_SIZE); + + for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { + if (write_access) + entry = pte_mkwrite(pte_mkdirty(mk_pte(page, + vma->vm_page_prot))); + else + entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot)); + entry = pte_mkyoung(entry); + mk_pte_huge(entry); + pte_val(entry) += (i << PAGE_SHIFT); + set_pte(page_table, entry); + page_table++; + } +} + +static int anon_get_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, + int write_access, pte_t * page_table) +{ + struct page *page; + + page = alloc_hugetlb_page(); + if (page == NULL) + return -1; + set_huge_pte(mm, vma, page, page_table, write_access); + return 1; +} + +static int +make_hugetlb_pages_present(unsigned long addr, unsigned long end, int flags) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + pte_t *pte; + int write; + + vma = find_vma(mm, addr); + if (!vma) + goto out_error1; + + write = (vma->vm_flags & VM_WRITE) != 0; + if ((vma->vm_end - vma->vm_start) & (HPAGE_SIZE - 1)) + goto out_error1; + + spin_lock(&mm->page_table_lock); + do { + int err; + + pte = huge_pte_alloc_map(mm, addr); + err = (!pte || + !pte_none(*pte) || + (anon_get_hugetlb_page(mm, vma, + write ? VM_WRITE : VM_READ, + pte) == -1)); + if (pte) + pte_unmap(pte); + if (err) + goto out_error; + + addr += HPAGE_SIZE; + } while (addr < end); + spin_unlock(&mm->page_table_lock); + + vma->vm_flags |= (VM_HUGETLB | VM_RESERVED); + if (flags & MAP_PRIVATE) + vma->vm_flags |= VM_DONTCOPY; + vma->vm_ops = &hugetlb_vm_ops; + return 0; + +out_error: + if (addr > vma->vm_start) { + vma->vm_end = addr; + flush_cache_range(vma, vma->vm_start, vma->vm_end); + zap_hugetlb_resources(vma); + flush_tlb_range(vma, vma->vm_start, vma->vm_end); + vma->vm_end = end; + } + spin_unlock(&mm->page_table_lock); + out_error1: + return -1; +} + +int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, + struct vm_area_struct *vma) +{ + pte_t *src_pte, *dst_pte, entry; + struct page *ptepage; + unsigned long addr = vma->vm_start; + unsigned long end = vma->vm_end; + + while (addr < end) { + unsigned long i; + + dst_pte = huge_pte_alloc_map(dst, addr); + if (!dst_pte) + goto nomem; + + src_pte = huge_pte_offset_map_nested(src, addr); + entry = *src_pte; + pte_unmap_nested(src_pte); + + ptepage = pte_page(entry); + get_page(ptepage); + for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { + set_pte(dst_pte, entry); + pte_val(entry) += PAGE_SIZE; + dst_pte++; + } + pte_unmap(dst_pte - (1 << HUGETLB_PAGE_ORDER)); + + dst->rss += (HPAGE_SIZE / PAGE_SIZE); + addr += HPAGE_SIZE; + } + return 0; + +nomem: + return -ENOMEM; +} + +int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, + struct page **pages, struct vm_area_struct **vmas, + unsigned long *st, int *length, int i) +{ + pte_t *ptep, pte; + unsigned long start = *st; + unsigned long pstart; + int len = *length; + struct page *page; + + do { + pstart = start; + ptep = huge_pte_offset_map(mm, start); + pte = *ptep; + +back1: + page = pte_page(pte); + if (pages) { + page += ((start & ~HPAGE_MASK) >> PAGE_SHIFT); + pages[i] = page; + } + if (vmas) + vmas[i] = vma; + i++; + len--; + start += PAGE_SIZE; + if (((start & HPAGE_MASK) == pstart) && len && + (start < vma->vm_end)) + goto back1; + + pte_unmap(ptep); + } while (len && start < vma->vm_end); + + *length = len; + *st = start; + return i; +} + +static void zap_hugetlb_resources(struct vm_area_struct *mpnt) +{ + struct mm_struct *mm = mpnt->vm_mm; + unsigned long len, addr, end; + struct page *page; + pte_t *ptep; + + addr = mpnt->vm_start; + end = mpnt->vm_end; + len = end - addr; + do { + unsigned long i; + + ptep = huge_pte_offset_map(mm, addr); + page = pte_page(*ptep); + for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { + pte_clear(ptep); + ptep++; + } + pte_unmap(ptep - (1 << HUGETLB_PAGE_ORDER)); + free_hugetlb_page(page); + addr += HPAGE_SIZE; + } while (addr < end); + mm->rss -= (len >> PAGE_SHIFT); + mpnt->vm_ops = NULL; +} + +static void unlink_vma(struct vm_area_struct *mpnt) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + + vma = mm->mmap; + if (vma == mpnt) { + mm->mmap = vma->vm_next; + } else { + while (vma->vm_next != mpnt) { + vma = vma->vm_next; + } + vma->vm_next = mpnt->vm_next; + } + rb_erase(&mpnt->vm_rb, &mm->mm_rb); + mm->mmap_cache = NULL; + mm->map_count--; +} + +int free_hugepages(struct vm_area_struct *mpnt) +{ + unlink_vma(mpnt); + + flush_cache_range(mpnt, mpnt->vm_start, mpnt->vm_end); + zap_hugetlb_resources(mpnt); + flush_tlb_range(mpnt, mpnt->vm_start, mpnt->vm_end); + + kmem_cache_free(vm_area_cachep, mpnt); + return 1; +} + +static struct inode *set_new_inode(unsigned long len, int prot, int flag, int key) +{ + struct inode *inode; + int i; + + for (i = 0; i < MAX_ID; i++) { + if (htlbpagek[i].key == 0) + break; + } + if (i == MAX_ID) + return NULL; + inode = kmalloc(sizeof (struct inode), GFP_KERNEL); + if (inode == NULL) + return NULL; + + inode_init_once(inode); + atomic_inc(&inode->i_writecount); + inode->i_mapping = &inode->i_data; + inode->i_mapping->host = inode; + inode->i_ino = (unsigned long)key; + + htlbpagek[i].key = key; + htlbpagek[i].in = inode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_mode = prot; + inode->i_size = len; + return inode; +} + +static int check_size_prot(struct inode *inode, unsigned long len, int prot, int flag) +{ + if (inode->i_uid != current->fsuid) + return -1; + if (inode->i_gid != current->fsgid) + return -1; + if (inode->i_size != len) + return -1; + return 0; +} + +static int alloc_shared_hugetlb_pages(int key, unsigned long addr, unsigned long len, + int prot, int flag) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + struct inode *inode; + struct address_space *mapping; + struct page *page; + int idx; + int retval = -ENOMEM; + int newalloc = 0; + +try_again: + spin_lock(&htlbpage_lock); + + inode = find_key_inode(key); + if (inode == NULL) { + if (!capable(CAP_SYS_ADMIN)) { + if (!in_group_p(0)) { + retval = -EPERM; + goto out_err; + } + } + if (!(flag & IPC_CREAT)) { + retval = -ENOENT; + goto out_err; + } + inode = set_new_inode(len, prot, flag, key); + if (inode == NULL) + goto out_err; + newalloc = 1; + } else { + if (check_size_prot(inode, len, prot, flag) < 0) { + retval = -EINVAL; + goto out_err; + } else if (atomic_read(&inode->i_writecount)) { + spin_unlock(&htlbpage_lock); + goto try_again; + } + } + spin_unlock(&htlbpage_lock); + mapping = inode->i_mapping; + + addr = do_mmap_pgoff(NULL, addr, len, (unsigned long) prot, + MAP_NORESERVE|MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0); + if (IS_ERR((void *) addr)) + goto freeinode; + + vma = find_vma(mm, addr); + if (!vma) { + retval = -EINVAL; + goto freeinode; + } + + spin_lock(&mm->page_table_lock); + do { + pte_t *pte = huge_pte_alloc_map(mm, addr); + + if (!pte || !pte_none(pte)) { + if (pte) + pte_unmap(pte); + goto out; + } + + idx = (addr - vma->vm_start) >> HPAGE_SHIFT; + page = find_get_page(mapping, idx); + if (page == NULL) { + page = alloc_hugetlb_page(); + if (page == NULL) { + pte_unmap(pte); + goto out; + } + add_to_page_cache(page, mapping, idx); + } + set_huge_pte(mm, vma, page, pte, + (vma->vm_flags & VM_WRITE)); + pte_unmap(pte); + + addr += HPAGE_SIZE; + } while (addr < vma->vm_end); + + retval = 0; + vma->vm_flags |= (VM_HUGETLB | VM_RESERVED); + vma->vm_ops = &hugetlb_vm_ops; + spin_unlock(&mm->page_table_lock); + spin_lock(&htlbpage_lock); + atomic_set(&inode->i_writecount, 0); + spin_unlock(&htlbpage_lock); + + return retval; + +out: + if (addr > vma->vm_start) { + unsigned long raddr; + raddr = vma->vm_end; + vma->vm_end = addr; + + flush_cache_range(vma, vma->vm_start, vma->vm_end); + zap_hugetlb_resources(vma); + flush_tlb_range(vma, vma->vm_start, vma->vm_end); + + vma->vm_end = raddr; + } + spin_unlock(&mm->page_table_lock); + do_munmap(mm, vma->vm_start, len); + if (newalloc) + goto freeinode; + + return retval; + +out_err: + spin_unlock(&htlbpage_lock); + +freeinode: + if (newalloc) { + for (idx = 0; idx < MAX_ID; idx++) { + if (htlbpagek[idx].key == inode->i_ino) { + htlbpagek[idx].key = 0; + htlbpagek[idx].in = NULL; + break; + } + } + kfree(inode); + } + return retval; +} + +static int alloc_private_hugetlb_pages(int key, unsigned long addr, unsigned long len, + int prot, int flag) +{ + if (!capable(CAP_SYS_ADMIN)) { + if (!in_group_p(0)) + return -EPERM; + } + addr = do_mmap_pgoff(NULL, addr, len, prot, + MAP_NORESERVE|MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, 0); + if (IS_ERR((void *) addr)) + return -ENOMEM; + if (make_hugetlb_pages_present(addr, (addr + len), flag) < 0) { + do_munmap(current->mm, addr, len); + return -ENOMEM; + } + return 0; +} + +int alloc_hugetlb_pages(int key, unsigned long addr, unsigned long len, int prot, + int flag) +{ + if (key > 0) + return alloc_shared_hugetlb_pages(key, addr, len, prot, flag); + return alloc_private_hugetlb_pages(key, addr, len, prot, flag); +} + +extern long htlbzone_pages; +extern struct list_head htlbpage_freelist; + +int set_hugetlb_mem_size(int count) +{ + int j, lcount; + struct page *page, *map; + + if (count < 0) + lcount = count; + else + lcount = count - htlbzone_pages; + + if (lcount > 0) { /* Increase the mem size. */ + while (lcount--) { + page = alloc_pages(GFP_ATOMIC, HUGETLB_PAGE_ORDER); + if (page == NULL) + break; + map = page; + for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) { + SetPageReserved(map); + map++; + } + spin_lock(&htlbpage_lock); + list_add(&page->list, &htlbpage_freelist); + htlbpagemem++; + htlbzone_pages++; + spin_unlock(&htlbpage_lock); + } + return (int) htlbzone_pages; + } + + /* Shrink the memory size. */ + while (lcount++) { + page = alloc_hugetlb_page(); + if (page == NULL) + break; + + spin_lock(&htlbpage_lock); + htlbzone_pages--; + spin_unlock(&htlbpage_lock); + + map = page; + for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) { + map->flags &= ~(1UL << PG_locked | 1UL << PG_error | + 1UL << PG_referenced | + 1UL << PG_dirty | 1UL << PG_active | + 1UL << PG_reserved | + 1UL << PG_private | 1UL << PG_writeback); + set_page_count(page, 0); + map++; + } + set_page_count(page, 1); + __free_pages(page, HUGETLB_PAGE_ORDER); + } + return (int) htlbzone_pages; +} + +static struct vm_operations_struct hugetlb_vm_ops = { + .close = zap_hugetlb_resources, +}; diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c --- a/arch/sparc64/mm/init.c Fri Sep 20 08:20:44 2002 +++ b/arch/sparc64/mm/init.c Fri Sep 20 08:20:44 2002 @@ -1690,6 +1690,13 @@ } } +#ifdef CONFIG_HUGETLB_PAGE +long htlbpagemem = 0; +long htlbpage_max; +long htlbzone_pages; +extern struct list_head htlbpage_freelist; +#endif + void __init mem_init(void) { unsigned long codepages, datapages, initpages; @@ -1726,7 +1733,7 @@ * Set up the zero page, mark it reserved, so that page count * is not manipulated when freeing the page from user ptes. */ - mem_map_zero = _alloc_pages(GFP_KERNEL, 0); + mem_map_zero = alloc_pages(GFP_KERNEL, 0); if (mem_map_zero == NULL) { prom_printf("paging_init: Cannot alloc zero page.\n"); prom_halt(); @@ -1766,6 +1773,32 @@ if (tlb_type == cheetah || tlb_type == cheetah_plus) cheetah_ecache_flush_init(); +#ifdef CONFIG_HUGETLB_PAGE + { + long i, j; + struct page *page, *map; + + /* For now reserve quarter for hugetlb_pages. */ + htlbzone_pages = (num_physpages >> ((HPAGE_SHIFT - PAGE_SHIFT) + 2)) ; + + /* Will make this kernel command line. */ + INIT_LIST_HEAD(&htlbpage_freelist); + for (i = 0; i < htlbzone_pages; i++) { + page = alloc_pages(GFP_ATOMIC, HUGETLB_PAGE_ORDER); + if (page == NULL) + break; + map = page; + for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) { + SetPageReserved(map); + map++; + } + list_add(&page->list, &htlbpage_freelist); + } + printk("Total Huge_TLB_Page memory pages allocated %ld\n", i); + htlbzone_pages = htlbpagemem = i; + htlbpage_max = i; + } +#endif } void free_initmem (void) diff -Nru a/arch/sparc64/prom/Makefile b/arch/sparc64/prom/Makefile --- a/arch/sparc64/prom/Makefile Fri Sep 20 08:20:44 2002 +++ b/arch/sparc64/prom/Makefile Fri Sep 20 08:20:44 2002 @@ -5,7 +5,7 @@ EXTRA_AFLAGS := -ansi -L_TARGET = promlib.a +L_TARGET = lib.a obj-y := bootstr.o devops.o init.o memory.o misc.o \ tree.o console.o printf.o p1275.o map.o diff -Nru a/drivers/acpi/Config.help b/drivers/acpi/Config.help --- a/drivers/acpi/Config.help Fri Sep 20 08:20:46 2002 +++ b/drivers/acpi/Config.help Fri Sep 20 08:20:46 2002 @@ -86,6 +86,23 @@ This driver will enable your system to shut down using ACPI, and dump your ACPI DSDT table using /proc/acpi/dsdt. +CONFIG_ACPI_SLEEP + This option adds support for ACPI suspend states. + + With this option, you will be able to put the system "to sleep". + Sleep states are low power states for the system and devices. All + of the system operating state is saved to either memory or disk + (depending on the state), to allow the system to resume operation + quickly at your request. + + Although this option sounds really nifty, barely any of the device + drivers have been converted to the new driver model and hence few + have proper power management support. + + This option is not recommended for anyone except those doing driver + power management development. + + CONFIG_ACPI_DEBUG The ACPI driver can optionally report errors with a great deal of verbosity. Saying Y enables these statements. This will increase diff -Nru a/drivers/acpi/Config.in b/drivers/acpi/Config.in --- a/drivers/acpi/Config.in Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/Config.in Fri Sep 20 08:20:47 2002 @@ -15,6 +15,7 @@ define_bool CONFIG_ACPI_BOOT y if [ "$CONFIG_ACPI_HT_ONLY" != "y" ]; then + bool ' Sleep States' CONFIG_ACPI_SLEEP tristate ' AC Adapter' CONFIG_ACPI_AC tristate ' Battery' CONFIG_ACPI_BATTERY tristate ' Button' CONFIG_ACPI_BUTTON @@ -33,7 +34,6 @@ define_bool CONFIG_ACPI_EC y define_bool CONFIG_ACPI_POWER y define_bool CONFIG_ACPI_PCI $CONFIG_PCI - define_bool CONFIG_ACPI_SLEEP $CONFIG_SOFTWARE_SUSPEND define_bool CONFIG_ACPI_SYSTEM y fi fi @@ -49,6 +49,7 @@ define_bool CONFIG_ACPI_PCI n define_bool CONFIG_ACPI_POWER n define_bool CONFIG_ACPI_SYSTEM n + define_bool CONFIG_ACPI_SLEEP n define_bool CONFIG_ACPI_BUTTON n define_bool CONFIG_ACPI_FAN n define_bool CONFIG_ACPI_PROCESSOR n diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile --- a/drivers/acpi/Makefile Fri Sep 20 08:20:48 2002 +++ b/drivers/acpi/Makefile Fri Sep 20 08:20:48 2002 @@ -19,7 +19,7 @@ # # ACPI Boot-Time Table Parsing # -obj-$(CONFIG_ACPI_BOOT) += tables.o +obj-$(CONFIG_ACPI_BOOT) += tables.o blacklist.o # # ACPI Core Subsystem (Interpreter) @@ -32,7 +32,7 @@ # # ACPI Bus and Device Drivers # -obj-$(CONFIG_ACPI_BUS) += bus.o +obj-$(CONFIG_ACPI_BUS) += bus.o driverfs.o obj-$(CONFIG_ACPI_AC) += ac.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o @@ -42,8 +42,11 @@ obj-$(CONFIG_ACPI_POWER) += power.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o -obj-$(CONFIG_ACPI_SYSTEM) += system.o +obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o +obj-$(CONFIG_ACPI_DEBUG) += debug.o +obj-$(CONFIG_ACPI_SLEEP) += sleep.o obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o +obj-$(CONFIG_ACPI_BUS) += scan.o include $(TOPDIR)/Rules.make diff -Nru a/drivers/acpi/ac.c b/drivers/acpi/ac.c --- a/drivers/acpi/ac.c Fri Sep 20 08:20:44 2002 +++ b/drivers/acpi/ac.c Fri Sep 20 08:20:44 2002 @@ -40,8 +40,16 @@ MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME); MODULE_LICENSE("GPL"); -#define PREFIX "ACPI: " - +#define ACPI_AC_COMPONENT 0x00020000 +#define ACPI_AC_CLASS "ac_adapter" +#define ACPI_AC_HID "ACPI0003" +#define ACPI_AC_DRIVER_NAME "ACPI AC Adapter Driver" +#define ACPI_AC_DEVICE_NAME "AC Adapter" +#define ACPI_AC_FILE_STATE "state" +#define ACPI_AC_NOTIFY_STATUS 0x80 +#define ACPI_AC_STATUS_OFFLINE 0x00 +#define ACPI_AC_STATUS_ONLINE 0x01 +#define ACPI_AC_STATUS_UNKNOWN 0xFF int acpi_ac_add (struct acpi_device *device); int acpi_ac_remove (struct acpi_device *device, int type); diff -Nru a/drivers/acpi/acpi_bus.h b/drivers/acpi/acpi_bus.h --- a/drivers/acpi/acpi_bus.h Fri Sep 20 08:20:44 2002 +++ b/drivers/acpi/acpi_bus.h Fri Sep 20 08:20:44 2002 @@ -27,14 +27,13 @@ #define __ACPI_BUS_H__ #include - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,4)) -#include -#define CONFIG_LDM -#endif +#include #include "include/acpi.h" +#define PREFIX "ACPI: " + +extern int acpi_disabled; /* TBD: Make dynamic */ #define ACPI_MAX_HANDLES 10 @@ -49,7 +48,6 @@ acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *); acpi_status acpi_evaluate_reference (acpi_handle, acpi_string, acpi_object_list *, struct acpi_handle_list *); - #ifdef CONFIG_ACPI_BUS #include @@ -111,31 +109,11 @@ struct list_head node; char name[80]; char class[80]; - int references; + atomic_t references; char *ids; /* Supported Hardware IDs */ struct acpi_device_ops ops; }; -enum acpi_blacklist_predicates -{ - all_versions, - less_than_or_equal, - equal, - greater_than_or_equal, -}; - -struct acpi_blacklist_item -{ - char oem_id[7]; - char oem_table_id[9]; - u32 oem_revision; - acpi_table_type table; - enum acpi_blacklist_predicates oem_revision_predicate; - char *reason; - u32 is_critical_error; -}; - - /* * ACPI Device * ----------- @@ -267,6 +245,7 @@ struct acpi_device *parent; struct list_head children; struct list_head node; + struct list_head g_list; struct acpi_device_status status; struct acpi_device_flags flags; struct acpi_device_pnp pnp; @@ -276,9 +255,7 @@ struct acpi_device_ops ops; struct acpi_driver *driver; void *driver_data; -#ifdef CONFIG_LDM - struct device dev; -#endif + struct driver_dir_entry driverfs_dir; }; #define acpi_driver_data(d) ((d)->driver_data) @@ -310,10 +287,9 @@ int acpi_bus_receive_event (struct acpi_bus_event *event); int acpi_bus_register_driver (struct acpi_driver *driver); int acpi_bus_unregister_driver (struct acpi_driver *driver); -int acpi_bus_scan (struct acpi_device *device); -int acpi_init (void); -void acpi_exit (void); +int acpi_create_dir(struct acpi_device *); +void acpi_remove_dir(struct acpi_device *); #endif /*CONFIG_ACPI_BUS*/ diff -Nru a/drivers/acpi/acpi_drivers.h b/drivers/acpi/acpi_drivers.h --- a/drivers/acpi/acpi_drivers.h Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/acpi_drivers.h Fri Sep 20 08:20:47 2002 @@ -32,116 +32,17 @@ #define ACPI_MAX_STRING 80 - -/* -------------------------------------------------------------------------- - ACPI Bus - -------------------------------------------------------------------------- */ - #define ACPI_BUS_COMPONENT 0x00010000 -#define ACPI_BUS_CLASS "system_bus" -#define ACPI_BUS_HID "ACPI_BUS" -#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver" -#define ACPI_BUS_DEVICE_NAME "System Bus" - - -/* -------------------------------------------------------------------------- - AC Adapter - -------------------------------------------------------------------------- */ - -#define ACPI_AC_COMPONENT 0x00020000 -#define ACPI_AC_CLASS "ac_adapter" -#define ACPI_AC_HID "ACPI0003" -#define ACPI_AC_DRIVER_NAME "ACPI AC Adapter Driver" -#define ACPI_AC_DEVICE_NAME "AC Adapter" -#define ACPI_AC_FILE_STATE "state" -#define ACPI_AC_NOTIFY_STATUS 0x80 -#define ACPI_AC_STATUS_OFFLINE 0x00 -#define ACPI_AC_STATUS_ONLINE 0x01 -#define ACPI_AC_STATUS_UNKNOWN 0xFF - - -/* -------------------------------------------------------------------------- - Battery - -------------------------------------------------------------------------- */ - -#define ACPI_BATTERY_COMPONENT 0x00040000 -#define ACPI_BATTERY_CLASS "battery" -#define ACPI_BATTERY_HID "PNP0C0A" -#define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver" -#define ACPI_BATTERY_DEVICE_NAME "Battery" -#define ACPI_BATTERY_FILE_INFO "info" -#define ACPI_BATTERY_FILE_STATUS "state" -#define ACPI_BATTERY_FILE_ALARM "alarm" -#define ACPI_BATTERY_NOTIFY_STATUS 0x80 -#define ACPI_BATTERY_NOTIFY_INFO 0x81 -#define ACPI_BATTERY_UNITS_WATTS "mW" -#define ACPI_BATTERY_UNITS_AMPS "mA" - - -/* -------------------------------------------------------------------------- - Button - -------------------------------------------------------------------------- */ +#define ACPI_SYSTEM_COMPONENT 0x02000000 -#define ACPI_BUTTON_COMPONENT 0x00080000 -#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver" -#define ACPI_BUTTON_CLASS "button" -#define ACPI_BUTTON_FILE_INFO "info" -#define ACPI_BUTTON_TYPE_UNKNOWN 0x00 -#define ACPI_BUTTON_NOTIFY_STATUS 0x80 +/* _HID definitions */ -#define ACPI_BUTTON_SUBCLASS_POWER "power" -#define ACPI_BUTTON_HID_POWER "PNP0C0C" +#define ACPI_POWER_HID "ACPI_PWR" +#define ACPI_PROCESSOR_HID "ACPI_CPU" +#define ACPI_SYSTEM_HID "ACPI_SYS" +#define ACPI_THERMAL_HID "ACPI_THM" #define ACPI_BUTTON_HID_POWERF "ACPI_FPB" -#define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)" -#define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)" -#define ACPI_BUTTON_TYPE_POWER 0x01 -#define ACPI_BUTTON_TYPE_POWERF 0x02 - -#define ACPI_BUTTON_SUBCLASS_SLEEP "sleep" -#define ACPI_BUTTON_HID_SLEEP "PNP0C0E" #define ACPI_BUTTON_HID_SLEEPF "ACPI_FSB" -#define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)" -#define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)" -#define ACPI_BUTTON_TYPE_SLEEP 0x03 -#define ACPI_BUTTON_TYPE_SLEEPF 0x04 - -#define ACPI_BUTTON_SUBCLASS_LID "lid" -#define ACPI_BUTTON_HID_LID "PNP0C0D" -#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" -#define ACPI_BUTTON_TYPE_LID 0x05 - - -/* -------------------------------------------------------------------------- - Embedded Controller - -------------------------------------------------------------------------- */ - -#define ACPI_EC_COMPONENT 0x00100000 -#define ACPI_EC_CLASS "embedded_controller" -#define ACPI_EC_HID "PNP0C09" -#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" -#define ACPI_EC_DEVICE_NAME "Embedded Controller" -#define ACPI_EC_FILE_INFO "info" - -#ifdef CONFIG_ACPI_EC - -int acpi_ec_ecdt_probe (void); -int acpi_ec_init (void); -void acpi_ec_exit (void); - -#endif - - -/* -------------------------------------------------------------------------- - Fan - -------------------------------------------------------------------------- */ - -#define ACPI_FAN_COMPONENT 0x00200000 -#define ACPI_FAN_CLASS "fan" -#define ACPI_FAN_HID "PNP0C0B" -#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver" -#define ACPI_FAN_DEVICE_NAME "Fan" -#define ACPI_FAN_FILE_STATE "state" -#define ACPI_FAN_NOTIFY_STATUS 0x80 /* -------------------------------------------------------------------------- @@ -154,28 +55,12 @@ /* ACPI PCI Root Bridge (pci_root.c) */ -#define ACPI_PCI_ROOT_CLASS "pci_bridge" -#define ACPI_PCI_ROOT_HID "PNP0A03" -#define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" -#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" - -int acpi_pci_root_init (void); -void acpi_pci_root_exit (void); void acpi_pci_get_translations (acpi_pci_id* id, u64* mem_tra, u64* io_tra); /* ACPI PCI Interrupt Link (pci_link.c) */ -#define ACPI_PCI_LINK_CLASS "pci_irq_routing" -#define ACPI_PCI_LINK_HID "PNP0C0F" -#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" -#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" -#define ACPI_PCI_LINK_FILE_INFO "info" -#define ACPI_PCI_LINK_FILE_STATUS "state" - int acpi_pci_link_check (void); int acpi_pci_link_get_irq (acpi_handle handle, int index); -int acpi_pci_link_init (void); -void acpi_pci_link_exit (void); /* ACPI PCI Interrupt Routing (pci_irq.c) */ @@ -195,98 +80,29 @@ Power Resource -------------------------------------------------------------------------- */ -#define ACPI_POWER_COMPONENT 0x00800000 -#define ACPI_POWER_CLASS "power_resource" -#define ACPI_POWER_HID "ACPI_PWR" -#define ACPI_POWER_DRIVER_NAME "ACPI Power Resource Driver" -#define ACPI_POWER_DEVICE_NAME "Power Resource" -#define ACPI_POWER_FILE_INFO "info" -#define ACPI_POWER_FILE_STATUS "state" -#define ACPI_POWER_RESOURCE_STATE_OFF 0x00 -#define ACPI_POWER_RESOURCE_STATE_ON 0x01 -#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF - #ifdef CONFIG_ACPI_POWER int acpi_power_get_inferred_state (struct acpi_device *device); int acpi_power_transition (struct acpi_device *device, int state); -int acpi_power_init (void); -void acpi_power_exit (void); - #endif /* -------------------------------------------------------------------------- + Embedded Controller + -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_EC +int acpi_ec_ecdt_probe (void); +#endif + +/* -------------------------------------------------------------------------- Processor -------------------------------------------------------------------------- */ -#define ACPI_PROCESSOR_COMPONENT 0x01000000 -#define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_HID "ACPI_CPU" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" -#define ACPI_PROCESSOR_DEVICE_NAME "Processor" -#define ACPI_PROCESSOR_FILE_INFO "info" -#define ACPI_PROCESSOR_FILE_POWER "power" -#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" -#define ACPI_PROCESSOR_FILE_THROTTLING "throttling" -#define ACPI_PROCESSOR_FILE_LIMIT "limit" -#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 -#define ACPI_PROCESSOR_NOTIFY_POWER 0x81 #define ACPI_PROCESSOR_LIMIT_NONE 0x00 #define ACPI_PROCESSOR_LIMIT_INCREMENT 0x01 #define ACPI_PROCESSOR_LIMIT_DECREMENT 0x02 int acpi_processor_set_thermal_limit(acpi_handle handle, int type); - - -/* -------------------------------------------------------------------------- - System - -------------------------------------------------------------------------- */ - -#define ACPI_SYSTEM_COMPONENT 0x02000000 -#define ACPI_SYSTEM_CLASS "system" -#define ACPI_SYSTEM_HID "ACPI_SYS" -#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver" -#define ACPI_SYSTEM_DEVICE_NAME "System" -#define ACPI_SYSTEM_FILE_INFO "info" -#define ACPI_SYSTEM_FILE_EVENT "event" -#define ACPI_SYSTEM_FILE_ALARM "alarm" -#define ACPI_SYSTEM_FILE_DSDT "dsdt" -#define ACPI_SYSTEM_FILE_FADT "fadt" -#define ACPI_SYSTEM_FILE_SLEEP "sleep" -#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" -#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" - -#ifdef CONFIG_ACPI_SYSTEM - -int acpi_system_init (void); -void acpi_system_exit (void); - -#endif - - -/* -------------------------------------------------------------------------- - Thermal Zone - -------------------------------------------------------------------------- */ - -#define ACPI_THERMAL_COMPONENT 0x04000000 -#define ACPI_THERMAL_CLASS "thermal_zone" -#define ACPI_THERMAL_HID "ACPI_THM" -#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver" -#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" -#define ACPI_THERMAL_FILE_STATE "state" -#define ACPI_THERMAL_FILE_TEMPERATURE "temperature" -#define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points" -#define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode" -#define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency" -#define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80 -#define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81 -#define ACPI_THERMAL_NOTIFY_DEVICES 0x82 -#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0 -#define ACPI_THERMAL_NOTIFY_HOT 0xF1 -#define ACPI_THERMAL_MODE_ACTIVE 0x00 -#define ACPI_THERMAL_MODE_PASSIVE 0x01 -#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff" /* -------------------------------------------------------------------------- diff -Nru a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c --- a/drivers/acpi/acpi_ksyms.c Fri Sep 20 08:20:44 2002 +++ b/drivers/acpi/acpi_ksyms.c Fri Sep 20 08:20:44 2002 @@ -124,7 +124,5 @@ EXPORT_SYMBOL(acpi_bus_receive_event); EXPORT_SYMBOL(acpi_bus_register_driver); EXPORT_SYMBOL(acpi_bus_unregister_driver); -EXPORT_SYMBOL(acpi_bus_scan); -EXPORT_SYMBOL(acpi_init); #endif /*CONFIG_ACPI_BUS*/ diff -Nru a/drivers/acpi/battery.c b/drivers/acpi/battery.c --- a/drivers/acpi/battery.c Fri Sep 20 08:20:43 2002 +++ b/drivers/acpi/battery.c Fri Sep 20 08:20:43 2002 @@ -40,13 +40,24 @@ MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME); MODULE_LICENSE("GPL"); -#define PREFIX "ACPI: " - #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF #define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS" #define ACPI_BATTERY_FORMAT_BST "NNNN" + +#define ACPI_BATTERY_COMPONENT 0x00040000 +#define ACPI_BATTERY_CLASS "battery" +#define ACPI_BATTERY_HID "PNP0C0A" +#define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver" +#define ACPI_BATTERY_DEVICE_NAME "Battery" +#define ACPI_BATTERY_FILE_INFO "info" +#define ACPI_BATTERY_FILE_STATUS "state" +#define ACPI_BATTERY_FILE_ALARM "alarm" +#define ACPI_BATTERY_NOTIFY_STATUS 0x80 +#define ACPI_BATTERY_NOTIFY_INFO 0x81 +#define ACPI_BATTERY_UNITS_WATTS "mW" +#define ACPI_BATTERY_UNITS_AMPS "mA" static int acpi_battery_add (struct acpi_device *device); static int acpi_battery_remove (struct acpi_device *device, int type); diff -Nru a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/blacklist.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,141 @@ +/* + * blacklist.c + * + * Check to see if the given machine has a known bad ACPI BIOS + * + * Copyright (C) 2002 Andy Grover + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + + +#include +#include +#include +#include +#include "acpi_bus.h" + +enum acpi_blacklist_predicates +{ + all_versions, + less_than_or_equal, + equal, + greater_than_or_equal, +}; + +struct acpi_blacklist_item +{ + char oem_id[7]; + char oem_table_id[9]; + u32 oem_revision; + acpi_table_type table; + enum acpi_blacklist_predicates oem_revision_predicate; + char *reason; + u32 is_critical_error; +}; + +/* + * POLICY: If *anything* doesn't work, put it on the blacklist. + * If they are critical errors, mark it critical, and abort driver load. + */ +static struct acpi_blacklist_item acpi_blacklist[] __initdata = +{ + /* Portege 7020, BIOS 8.10 */ + {"TOSHIB", "7020CT ", 0x19991112, ACPI_DSDT, all_versions, "Implicit Return", 0}, + /* Portege 4030 */ + {"TOSHIB", "4030 ", 0x19991112, ACPI_DSDT, all_versions, "Implicit Return", 0}, + /* Portege 310/320, BIOS 7.1 */ + {"TOSHIB", "310 ", 0x19990511, ACPI_DSDT, all_versions, "Implicit Return", 0}, + /* Seattle 2, old bios rev. */ + {"INTEL ", "440BX ", 0x00001000, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0}, + /* ASUS K7M */ + {"ASUS ", "K7M ", 0x00001000, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0}, + /* Intel 810 Motherboard? */ + {"MNTRAL", "MO81010A", 0x00000012, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0}, + /* Compaq Presario 711FR */ + {"COMAPQ", "EAGLES", 0x06040000, ACPI_DSDT, less_than_or_equal, "SCI issues (C2 disabled)", 0}, + /* Compaq Presario 1700 */ + {"PTLTD ", " DSDT ", 0x06040000, ACPI_DSDT, less_than_or_equal, "Multiple problems", 1}, + /* Sony FX120, FX140, FX150? */ + {"SONY ", "U0 ", 0x20010313, ACPI_DSDT, less_than_or_equal, "ACPI driver problem", 1}, + /* Compaq Presario 800, Insyde BIOS */ + {"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1}, + /* IBM 600E - _ADR should return 7, but it returns 1 */ + {"IBM ", "TP600E ", 0x00000105, ACPI_DSDT, less_than_or_equal, "Incorrect _ADR", 1}, + {"VIA694", "AWRDACPI", 0, ACPI_DSDT, all_versions, "Bogus table", 1}, + {"ASUS\0\0", "P2B-S ", 0, ACPI_DSDT, all_versions, "Bogus PCI routing", 1}, + {"COMPAQ", "DSDT", 0, ACPI_DSDT, all_versions, "Bogus PCI routing", 1}, + + {""} +}; + + +int __init +acpi_blacklisted(void) +{ + int i = 0; + int blacklisted = 0; + struct acpi_table_header *table_header; + + while (acpi_blacklist[i].oem_id[0] != '\0') + { + if (!acpi_get_table_header_early(acpi_blacklist[i].table, &table_header)) { + i++; + continue; + } + + if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) { + i++; + continue; + } + + if (strncmp(acpi_blacklist[i].oem_table_id, table_header->oem_table_id, 8)) { + i++; + continue; + } + + if ((acpi_blacklist[i].oem_revision_predicate == all_versions) + || (acpi_blacklist[i].oem_revision_predicate == less_than_or_equal + && table_header->oem_revision <= acpi_blacklist[i].oem_revision) + || (acpi_blacklist[i].oem_revision_predicate == greater_than_or_equal + && table_header->oem_revision >= acpi_blacklist[i].oem_revision) + || (acpi_blacklist[i].oem_revision_predicate == equal + && table_header->oem_revision == acpi_blacklist[i].oem_revision)) { + + printk(KERN_ERR PREFIX "Vendor \"%6.6s\" System \"%8.8s\" " + "Revision 0x%x has a known ACPI BIOS problem.\n", + acpi_blacklist[i].oem_id, + acpi_blacklist[i].oem_table_id, + acpi_blacklist[i].oem_revision); + + printk(KERN_ERR PREFIX "Reason: %s. This is a %s error\n", + acpi_blacklist[i].reason, + (acpi_blacklist[i].is_critical_error ? "non-recoverable" : "recoverable")); + + blacklisted = acpi_blacklist[i].is_critical_error; + break; + } + else { + i++; + } + } + + return blacklisted; +} + diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c --- a/drivers/acpi/bus.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/bus.c Fri Sep 20 08:20:47 2002 @@ -22,11 +22,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#include -#include #include -#include -#include #include #include #include @@ -37,244 +33,27 @@ #endif #include "acpi_bus.h" #include "acpi_drivers.h" -#include "include/acinterp.h" /* for acpi_ex_eisa_id_to_string() */ #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME ("acpi_bus") -MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_BUS_DRIVER_NAME); -MODULE_LICENSE("GPL"); - -#define PREFIX "ACPI: " - extern void eisa_set_level_irq(unsigned int irq); -extern int acpi_disabled; - FADT_DESCRIPTOR acpi_fadt; struct acpi_device *acpi_root; struct proc_dir_entry *acpi_root_dir; #define STRUCT_TO_INT(s) (*((int*)&s)) -/* - * POLICY: If *anything* doesn't work, put it on the blacklist. - * If they are critical errors, mark it critical, and abort driver load. - */ -static struct acpi_blacklist_item acpi_blacklist[] __initdata = -{ - /* Portege 7020, BIOS 8.10 */ - {"TOSHIB", "7020CT ", 0x19991112, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0}, - /* Portege 4030 */ - {"TOSHIB", "4030 ", 0x19991112, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0}, - /* Portege 310/320, BIOS 7.1 */ - {"TOSHIB", "310 ", 0x19990511, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0}, - /* Seattle 2, old bios rev. */ - {"INTEL ", "440BX ", 0x00001000, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0}, - /* ASUS K7M */ - {"ASUS ", "K7M ", 0x00001000, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0}, - /* Intel 810 Motherboard? */ - {"MNTRAL", "MO81010A", 0x00000012, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0}, - /* Compaq Presario 711FR */ - {"COMAPQ", "EAGLES", 0x06040000, ACPI_TABLE_DSDT, less_than_or_equal, "SCI issues (C2 disabled)", 0}, - /* Compaq Presario 1700 */ - {"PTLTD ", " DSDT ", 0x06040000, ACPI_TABLE_DSDT, less_than_or_equal, "Multiple problems", 1}, - /* Sony FX120, FX140, FX150? */ - {"SONY ", "U0 ", 0x20010313, ACPI_TABLE_DSDT, less_than_or_equal, "ACPI driver problem", 1}, - /* Compaq Presario 800, Insyde BIOS */ - {"INT440", "SYSFexxx", 0x00001001, ACPI_TABLE_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1}, - /* IBM 600E - _ADR should return 7, but it returns 1 */ - {"IBM ", "TP600E ", 0x00000105, ACPI_TABLE_DSDT, less_than_or_equal, "Incorrect _ADR", 1}, - {""} -}; - - -/* -------------------------------------------------------------------------- - Linux Driver Model (LDM) Support - -------------------------------------------------------------------------- */ - -#ifdef CONFIG_LDM - -static int acpi_device_probe(struct device *dev); -static int acpi_device_remove(struct device *dev); -static int acpi_device_suspend(struct device *dev, u32 state, u32 stage); -static int acpi_device_resume(struct device *dev, u32 stage); - -static struct device_driver acpi_bus_driver = { - .probe = acpi_device_probe, - .remove = acpi_device_remove, - .suspend = acpi_device_suspend, - .resume = acpi_device_resume, -}; - - -static int -acpi_device_probe ( - struct device *dev) -{ - ACPI_FUNCTION_TRACE("acpi_device_probe"); - - if (!dev) - return_VALUE(-EINVAL); - - /* TBD */ - - return_VALUE(0); -} - - -static int -acpi_device_remove ( - struct device *dev) -{ - ACPI_FUNCTION_TRACE("acpi_device_remove"); - - if (!dev) - return_VALUE(-EINVAL); - - /* TBD */ - - return_VALUE(0); -} - - -static int -acpi_device_suspend ( - struct device *dev, - u32 state, - u32 stage) -{ - ACPI_FUNCTION_TRACE("acpi_device_suspend"); - - if (!dev) - return_VALUE(-EINVAL); - - /* TBD */ - - return_VALUE(0); -} - - -static int -acpi_device_resume ( - struct device *dev, - u32 stage) -{ - ACPI_FUNCTION_TRACE("acpi_device_resume"); - - if (!dev) - return_VALUE(-EINVAL); - - /* TBD */ - - return_VALUE(0); -} - -#if 0 /* not used ATM */ -static int -acpi_platform_add ( - struct device *dev) -{ - ACPI_FUNCTION_TRACE("acpi_platform_add"); - - if (!dev) - return -EINVAL; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s (%s) added\n", - dev->name, dev->bus_id)); - - /* TBD */ - - return_VALUE(0); -} - - -static int -acpi_platform_remove ( - struct device *dev) -{ - ACPI_FUNCTION_TRACE("acpi_platform_add"); - - if (!dev) - return -EINVAL; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s (%s) removed\n", - dev->name, dev->bus_id)); - - /* TBD */ - - return_VALUE(0); -} -#endif /* unused */ - - -#endif /*CONFIG_LDM*/ - - -static int -acpi_device_register ( - struct acpi_device *device, - struct acpi_device *parent) -{ - int result = 0; - - ACPI_FUNCTION_TRACE("acpi_device_register"); - - if (!device) - return_VALUE(-EINVAL); - -#ifdef CONFIG_LDM - sprintf(device->dev.name, "ACPI device %s:%s", - device->pnp.hardware_id, device->pnp.unique_id); - strncpy(device->dev.bus_id, device->pnp.bus_id, sizeof(acpi_bus_id)); - if (parent) - device->dev.parent = &parent->dev; - device->dev.driver = &acpi_bus_driver; - - result = device_register(&device->dev); -#endif /*CONFIG_LDM*/ - - return_VALUE(result); -} - - -static int -acpi_device_unregister ( - struct acpi_device *device) -{ - ACPI_FUNCTION_TRACE("acpi_device_unregister"); - - if (!device) - return_VALUE(-EINVAL); - -#ifdef CONFIG_LDM - put_device(&device->dev); -#endif /*CONFIG_LDM*/ - - return_VALUE(0); -} - - /* -------------------------------------------------------------------------- Device Management -------------------------------------------------------------------------- */ -static void -acpi_bus_data_handler ( +extern void acpi_bus_data_handler ( acpi_handle handle, u32 function, - void *context) -{ - ACPI_FUNCTION_TRACE("acpi_bus_data_handler"); - - /* TBD */ - - return_VOID; -} - - + void *context); int acpi_bus_get_device ( acpi_handle handle, @@ -337,57 +116,6 @@ } -/* -static int -acpi_bus_create_device_fs (struct device *device) -{ - ACPI_FUNCTION_TRACE("acpi_bus_create_device_fs"); - - if (!device) - return_VALUE(-EINVAL); - - if (device->dir.entry) - return_VALUE(-EEXIST); - - if (!device->parent) - device->dir.entry = proc_mkdir(device->pnp.bus_id, NULL); - else - device->dir.entry = proc_mkdir(device->pnp.bus_id, - device->parent->fs.entry); - - if (!device->dir.entry) { - printk(KERN_ERR PREFIX "Unable to create fs entry '%s'\n", - device->pnp.bus_id); - return_VALUE(-ENODEV); - } - - return_VALUE(0); -} - - -static int -acpi_bus_remove_device_fs (struct device *device) -{ - ACPI_FUNCTION_TRACE("acpi_bus_create_device_fs"); - - if (!device) - return_VALUE(-EINVAL); - - if (!device->dir.entry) - return_VALUE(-ENODEV); - - if (!device->parent) - remove_proc_entry(device->pnp_bus_id, NULL); - else - remove_proc_entry(device->pnp.bus_id, device->parent->fs.entry); - - device->dir.entry = NULL; - - return_VALUE(0); -} -*/ - - /* -------------------------------------------------------------------------- Power Management -------------------------------------------------------------------------- */ @@ -533,110 +261,6 @@ } -static int -acpi_bus_get_power_flags ( - struct acpi_device *device) -{ - acpi_status status = 0; - acpi_handle handle = 0; - u32 i = 0; - - ACPI_FUNCTION_TRACE("acpi_bus_get_power_flags"); - - if (!device) - return -ENODEV; - - /* - * Power Management Flags - */ - status = acpi_get_handle(device->handle, "_PSC", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.explicit_get = 1; - status = acpi_get_handle(device->handle, "_IRC", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.inrush_current = 1; - status = acpi_get_handle(device->handle, "_PRW", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.wake_capable = 1; - - /* - * Enumerate supported power management states - */ - for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { - struct acpi_device_power_state *ps = &device->power.states[i]; - char object_name[5] = {'_','P','R','0'+i,'\0'}; - - /* Evaluate "_PRx" to se if power resources are referenced */ - acpi_evaluate_reference(device->handle, object_name, NULL, - &ps->resources); - if (ps->resources.count) { - device->power.flags.power_resources = 1; - ps->flags.valid = 1; - } - - /* Evaluate "_PSx" to see if we can do explicit sets */ - object_name[2] = 'S'; - status = acpi_get_handle(device->handle, object_name, &handle); - if (ACPI_SUCCESS(status)) { - ps->flags.explicit_set = 1; - ps->flags.valid = 1; - } - - /* State is valid if we have some power control */ - if (ps->resources.count || ps->flags.explicit_set) - ps->flags.valid = 1; - - ps->power = -1; /* Unknown - driver assigned */ - ps->latency = -1; /* Unknown - driver assigned */ - } - - /* Set defaults for D0 and D3 states (always valid) */ - device->power.states[ACPI_STATE_D0].flags.valid = 1; - device->power.states[ACPI_STATE_D0].power = 100; - device->power.states[ACPI_STATE_D3].flags.valid = 1; - device->power.states[ACPI_STATE_D3].power = 0; - - /* - * System Power States - * ------------------- - */ - /* TBD: S1-S4 power state support and resource requirements. */ - /* - for (i=ACPI_STATE_S1; ihandle, name, NULL, - &state); - if (ACPI_FAILURE(status)) - continue; - } - */ - - /* TBD: System wake support and resource requirements. */ - - device->power.state = ACPI_STATE_UNKNOWN; - - return 0; -} - - -/* -------------------------------------------------------------------------- - Performance Management - -------------------------------------------------------------------------- */ - -static int -acpi_bus_get_perf_flags ( - struct acpi_device *device) -{ - ACPI_FUNCTION_TRACE("acpi_bus_get_perf_flags"); - - if (!device) - return -ENODEV; - - device->performance.state = ACPI_STATE_UNKNOWN; - - return 0; -} - /* -------------------------------------------------------------------------- Event Management @@ -732,100 +356,6 @@ /* -------------------------------------------------------------------------- - Namespace Management - -------------------------------------------------------------------------- */ - -#define WALK_UP 0 -#define WALK_DOWN 1 - -typedef int (*acpi_bus_walk_callback)(struct acpi_device*, int, void*); - -#define HAS_CHILDREN(d) ((d)->children.next != &((d)->children)) -#define HAS_SIBLINGS(d) (((d)->parent) && ((d)->node.next != &(d)->parent->children)) -#define NODE_TO_DEVICE(n) (list_entry(n, struct acpi_device, node)) - - -/** - * acpi_bus_walk - * ------------- - * Used to walk the ACPI Bus's device namespace. Can walk down (depth-first) - * or up. Able to parse starting at any node in the namespace. Note that a - * callback return value of -ELOOP will terminate the walk. - * - * @start: starting point - * callback: function to call for every device encountered while parsing - * direction: direction to parse (up or down) - * @data: context for this search operation - */ -static int -acpi_bus_walk ( - struct acpi_device *start, - acpi_bus_walk_callback callback, - int direction, - void *data) -{ - int result = 0; - int level = 0; - struct acpi_device *device = NULL; - - if (!start || !callback) - return -EINVAL; - - device = start; - - /* - * Parse Namespace - * --------------- - * Parse a given subtree (specified by start) in the given direction. - * Walking 'up' simply means that we execute the callback on leaf - * devices prior to their parents (useful for things like removing - * or powering down a subtree). - */ - - while (device) { - - if (direction == WALK_DOWN) - if (-ELOOP == callback(device, level, data)) - break; - - /* Depth First */ - - if (HAS_CHILDREN(device)) { - device = NODE_TO_DEVICE(device->children.next); - ++level; - continue; - } - - if (direction == WALK_UP) - if (-ELOOP == callback(device, level, data)) - break; - - /* Now Breadth */ - - if (HAS_SIBLINGS(device)) { - device = NODE_TO_DEVICE(device->node.next); - continue; - } - - /* Scope Exhausted - Find Next */ - - while ((device = device->parent)) { - --level; - if (HAS_SIBLINGS(device)) { - device = NODE_TO_DEVICE(device->node.next); - break; - } - } - } - - if ((direction == WALK_UP) && (result == 0)) - callback(start, level, data); - - return result; -} - - -/* -------------------------------------------------------------------------- Notification Handling -------------------------------------------------------------------------- */ @@ -1001,896 +531,10 @@ return_VOID; } - -/* -------------------------------------------------------------------------- - Driver Management - -------------------------------------------------------------------------- */ - -static LIST_HEAD(acpi_bus_drivers); -static DECLARE_MUTEX(acpi_bus_drivers_lock); - - -/** - * acpi_bus_match - * -------------- - * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it - * matches the specified driver's criteria. - */ -static int -acpi_bus_match ( - struct acpi_device *device, - struct acpi_driver *driver) -{ - - if (!device || !driver) - return -EINVAL; - - if (device->flags.hardware_id) { - if (strstr(driver->ids, device->pnp.hardware_id)) - return 0; - } - - if (device->flags.compatible_ids) { - acpi_status status = AE_OK; - acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_object *object = NULL; - char cid[256]; - - memset(cid, 0, sizeof(cid)); - - status = acpi_evaluate_object(device->handle, "_CID", NULL, - &buffer); - if (ACPI_FAILURE(status) || !buffer.pointer) - return -ENOENT; - - object = (acpi_object *) buffer.pointer; - - switch (object->type) { - case ACPI_TYPE_INTEGER: - acpi_ex_eisa_id_to_string((u32) object->integer.value, - cid); - break; - case ACPI_TYPE_STRING: - strncpy(cid, object->string.pointer, sizeof(cid) - 1); - break; - case ACPI_TYPE_PACKAGE: - /* TBD: Support CID packages */ - break; - } - - if (!cid[0]) { - acpi_os_free(buffer.pointer); - return -ENOENT; - } - - if (strstr(driver->ids, cid)) { - acpi_os_free(buffer.pointer); - return 0; - } - - acpi_os_free(buffer.pointer); - } - - return -ENOENT; -} - - -/** - * acpi_bus_driver_init - * -------------------- - * Used to initialize a device via its device driver. Called whenever a - * driver is bound to a device. Invokes the driver's add() and start() ops. - */ -static int -acpi_bus_driver_init ( - struct acpi_device *device, - struct acpi_driver *driver) -{ - int result = 0; - - ACPI_FUNCTION_TRACE("acpi_bus_driver_init"); - - if (!device || !driver) - return_VALUE(-EINVAL); - - if (!driver->ops.add) - return_VALUE(-ENOSYS); - - result = driver->ops.add(device); - if (result) { - device->driver = NULL; - acpi_driver_data(device) = NULL; - return_VALUE(result); - } - - /* - * TBD - Configuration Management: Assign resources to device based - * upon possible configuration and currently allocated resources. - */ - - if (driver->ops.start) { - result = driver->ops.start(device); - if (result && driver->ops.remove) - driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); - return_VALUE(result); - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); - -#ifdef CONFIG_LDM - /* - * Update the device information (in the global device hierarchy) now - * that there's a driver bound to it. - */ - strncpy(device->dev.name, device->pnp.device_name, - sizeof(device->dev.name)); -#endif - - if (driver->ops.scan) { - driver->ops.scan(device); - } - - return_VALUE(0); -} - - -/** - * acpi_bus_attach - * ------------- - * Callback for acpi_bus_walk() used to find devices that match a specific - * driver's criteria and then attach the driver. - */ -static int -acpi_bus_attach ( - struct acpi_device *device, - int level, - void *data) -{ - int result = 0; - struct acpi_driver *driver = NULL; - - ACPI_FUNCTION_TRACE("acpi_bus_attach"); - - if (!device || !data) - return_VALUE(-EINVAL); - - driver = (struct acpi_driver *) data; - - if (device->driver) - return_VALUE(-EEXIST); - - if (!device->status.present) - return_VALUE(-ENODEV); - - result = acpi_bus_match(device, driver); - if (result) - return_VALUE(result); - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", - driver->name, device->pnp.bus_id)); - - result = acpi_bus_driver_init(device, driver); - if (result) - return_VALUE(result); - - down(&acpi_bus_drivers_lock); - ++driver->references; - up(&acpi_bus_drivers_lock); - - return_VALUE(0); -} - - -/** - * acpi_bus_unattach - * ----------------- - * Callback for acpi_bus_walk() used to find devices that match a specific - * driver's criteria and unattach the driver. - */ -static int -acpi_bus_unattach ( - struct acpi_device *device, - int level, - void *data) -{ - int result = 0; - struct acpi_driver *driver = (struct acpi_driver *) data; - - ACPI_FUNCTION_TRACE("acpi_bus_unattach"); - - if (!device || !driver) - return_VALUE(-EINVAL); - - if (device->driver != driver) - return_VALUE(-ENOENT); - - if (!driver->ops.remove) - return_VALUE(-ENOSYS); - - result = driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); - if (result) - return_VALUE(result); - - device->driver = NULL; - acpi_driver_data(device) = NULL; - - down(&acpi_bus_drivers_lock); - driver->references--; - up(&acpi_bus_drivers_lock); - - return_VALUE(0); -} - - -/** - * acpi_bus_find_driver - * -------------------- - * Parses the list of registered drivers looking for a driver applicable for - * the specified device. - */ -static int -acpi_bus_find_driver ( - struct acpi_device *device) -{ - int result = -ENODEV; - struct list_head *entry = NULL; - struct acpi_driver *driver = NULL; - - ACPI_FUNCTION_TRACE("acpi_bus_find_driver"); - - if (!device || device->driver) - return_VALUE(-EINVAL); - - down(&acpi_bus_drivers_lock); - - list_for_each(entry, &acpi_bus_drivers) { - - driver = list_entry(entry, struct acpi_driver, node); - - if (acpi_bus_match(device, driver)) - continue; - - result = acpi_bus_driver_init(device, driver); - if (!result) - ++driver->references; - - break; - } - - up(&acpi_bus_drivers_lock); - - return_VALUE(result); -} - - -/** - * acpi_bus_register_driver - * ------------------------ - * Registers a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and binds. - */ -int -acpi_bus_register_driver ( - struct acpi_driver *driver) -{ - ACPI_FUNCTION_TRACE("acpi_bus_register_driver"); - - if (!driver) - return_VALUE(-EINVAL); - - down(&acpi_bus_drivers_lock); - list_add_tail(&driver->node, &acpi_bus_drivers); - up(&acpi_bus_drivers_lock); - - acpi_bus_walk(acpi_root, acpi_bus_attach, - WALK_DOWN, driver); - - return_VALUE(driver->references); -} - - -/** - * acpi_bus_unregister_driver - * -------------------------- - * Unregisters a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and unbinds. - */ -int -acpi_bus_unregister_driver ( - struct acpi_driver *driver) -{ - ACPI_FUNCTION_TRACE("acpi_bus_unregister_driver"); - - if (!driver) - return_VALUE(-EINVAL); - - acpi_bus_walk(acpi_root, acpi_bus_unattach, WALK_UP, driver); - - if (driver->references) - return_VALUE(driver->references); - - down(&acpi_bus_drivers_lock); - list_del(&driver->node); - up(&acpi_bus_drivers_lock); - - return_VALUE(0); -} - - -/* -------------------------------------------------------------------------- - Device Enumeration - -------------------------------------------------------------------------- */ - -static int -acpi_bus_get_flags ( - struct acpi_device *device) -{ - acpi_status status = AE_OK; - acpi_handle temp = NULL; - - ACPI_FUNCTION_TRACE("acpi_bus_get_flags"); - - /* Presence of _STA indicates 'dynamic_status' */ - status = acpi_get_handle(device->handle, "_STA", &temp); - if (ACPI_SUCCESS(status)) - device->flags.dynamic_status = 1; - - /* Presence of _CID indicates 'compatible_ids' */ - status = acpi_get_handle(device->handle, "_CID", &temp); - if (ACPI_SUCCESS(status)) - device->flags.compatible_ids = 1; - - /* Presence of _RMV indicates 'removable' */ - status = acpi_get_handle(device->handle, "_RMV", &temp); - if (ACPI_SUCCESS(status)) - device->flags.removable = 1; - - /* Presence of _EJD|_EJ0 indicates 'ejectable' */ - status = acpi_get_handle(device->handle, "_EJD", &temp); - if (ACPI_SUCCESS(status)) - device->flags.ejectable = 1; - else { - status = acpi_get_handle(device->handle, "_EJ0", &temp); - if (ACPI_SUCCESS(status)) - device->flags.ejectable = 1; - } - - /* Presence of _LCK indicates 'lockable' */ - status = acpi_get_handle(device->handle, "_LCK", &temp); - if (ACPI_SUCCESS(status)) - device->flags.lockable = 1; - - /* Presence of _PS0|_PR0 indicates 'power manageable' */ - status = acpi_get_handle(device->handle, "_PS0", &temp); - if (ACPI_FAILURE(status)) - status = acpi_get_handle(device->handle, "_PR0", &temp); - if (ACPI_SUCCESS(status)) - device->flags.power_manageable = 1; - - /* TBD: Peformance management */ - - return_VALUE(0); -} - - -static int -acpi_bus_add ( - struct acpi_device **child, - struct acpi_device *parent, - acpi_handle handle, - int type) -{ - int result = 0; - acpi_status status = AE_OK; - struct acpi_device *device = NULL; - char bus_id[5] = {'?',0}; - acpi_buffer buffer = {sizeof(bus_id), bus_id}; - acpi_device_info info; - char *hid = NULL; - char *uid = NULL; - int i = 0; - - ACPI_FUNCTION_TRACE("acpi_bus_add"); - - if (!child) - return_VALUE(-EINVAL); - - device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL); - if (!device) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n")); - return_VALUE(-ENOMEM); - } - memset(device, 0, sizeof(struct acpi_device)); - - device->handle = handle; - device->parent = parent; - - memset(&info, 0, sizeof(acpi_device_info)); - - /* - * Bus ID - * ------ - * The device's Bus ID is simply the object name. - * TBD: Shouldn't this value be unique (within the ACPI namespace)? - */ - switch (type) { - case ACPI_BUS_TYPE_SYSTEM: - sprintf(device->pnp.bus_id, "%s", "ACPI"); - break; - case ACPI_BUS_TYPE_POWER_BUTTON: - sprintf(device->pnp.bus_id, "%s", "PWRF"); - break; - case ACPI_BUS_TYPE_SLEEP_BUTTON: - sprintf(device->pnp.bus_id, "%s", "SLPF"); - break; - default: - acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); - /* Clean up trailing underscores (if any) */ - for (i = 3; i > 1; i--) { - if (bus_id[i] == '_') - bus_id[i] = '\0'; - else - break; - } - sprintf(device->pnp.bus_id, "%s", bus_id); - break; - } - - /* - * Flags - * ----- - * Get prior to calling acpi_bus_get_status() so we know whether - * or not _STA is present. Note that we only look for object - * handles -- cannot evaluate objects until we know the device is - * present and properly initialized. - */ - result = acpi_bus_get_flags(device); - if (result) - goto end; - - /* - * Status - * ------ - * See if the device is present. We always assume that non-Device() - * objects (e.g. thermal zones, power resources, processors, etc.) are - * present, functioning, etc. (at least when parent object is present). - * Note that _STA has a different meaning for some objects (e.g. - * power resources) so we need to be careful how we use it. - */ - switch (type) { - case ACPI_BUS_TYPE_DEVICE: - result = acpi_bus_get_status(device); - if (result) - goto end; - break; - default: - STRUCT_TO_INT(device->status) = 0x0F; - break; - } - if (!device->status.present) { - result = -ENOENT; - goto end; - } - - /* - * Initialize Device - * ----------------- - * TBD: Synch with Core's enumeration/initialization process. - */ - - /* - * Hardware ID, Unique ID, & Bus Address - * ------------------------------------- - */ - switch (type) { - case ACPI_BUS_TYPE_DEVICE: - status = acpi_get_object_info(handle, &info); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Error reading device info\n")); - result = -ENODEV; - goto end; - } - /* Clean up info strings (not NULL terminated) */ - info.hardware_id[sizeof(info.hardware_id)-1] = '\0'; - info.unique_id[sizeof(info.unique_id)-1] = '\0'; - if (info.valid & ACPI_VALID_HID) - hid = info.hardware_id; - if (info.valid & ACPI_VALID_UID) - uid = info.unique_id; - if (info.valid & ACPI_VALID_ADR) { - device->pnp.bus_address = info.address; - device->flags.bus_address = 1; - } - break; - case ACPI_BUS_TYPE_POWER: - hid = ACPI_POWER_HID; - break; - case ACPI_BUS_TYPE_PROCESSOR: - hid = ACPI_PROCESSOR_HID; - break; - case ACPI_BUS_TYPE_SYSTEM: - hid = ACPI_SYSTEM_HID; - break; - case ACPI_BUS_TYPE_THERMAL: - hid = ACPI_THERMAL_HID; - break; - case ACPI_BUS_TYPE_POWER_BUTTON: - hid = ACPI_BUTTON_HID_POWERF; - break; - case ACPI_BUS_TYPE_SLEEP_BUTTON: - hid = ACPI_BUTTON_HID_SLEEPF; - break; - } - - /* - * \_SB - * ---- - * Fix for the system root bus device -- the only root-level device. - */ - if ((parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) { - hid = ACPI_BUS_HID; - sprintf(device->pnp.device_name, "%s", ACPI_BUS_DEVICE_NAME); - sprintf(device->pnp.device_class, "%s", ACPI_BUS_CLASS); - } - - if (hid) { - sprintf(device->pnp.hardware_id, "%s", hid); - device->flags.hardware_id = 1; - } - if (uid) { - sprintf(device->pnp.unique_id, "%s", uid); - device->flags.unique_id = 1; - } - - /* - * Power Management - * ---------------- - */ - if (device->flags.power_manageable) { - result = acpi_bus_get_power_flags(device); - if (result) - goto end; - } - - /* - * Performance Management - * ---------------------- - */ - if (device->flags.performance_manageable) { - result = acpi_bus_get_perf_flags(device); - if (result) - goto end; - } - - /* - * Context - * ------- - * Attach this 'struct acpi_device' to the ACPI object. This makes - * resolutions from handle->device very efficient. Note that we need - * to be careful with fixed-feature devices as they all attach to the - * root object. - */ - switch (type) { - case ACPI_BUS_TYPE_POWER_BUTTON: - case ACPI_BUS_TYPE_SLEEP_BUTTON: - break; - default: - status = acpi_attach_data(device->handle, - acpi_bus_data_handler, device); - break; - } - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Error attaching device data\n")); - result = -ENODEV; - goto end; - } - - /* - * Linkage - * ------- - * Link this device to its parent and siblings. - */ - INIT_LIST_HEAD(&device->children); - if (!device->parent) - INIT_LIST_HEAD(&device->node); - else - list_add_tail(&device->node, &device->parent->children); - -#ifdef CONFIG_ACPI_DEBUG - { - char *type_string = NULL; - char name[80] = {'?','\0'}; - acpi_buffer buffer = {sizeof(name), name}; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - switch (type) { - case ACPI_BUS_TYPE_DEVICE: - type_string = "Device"; - break; - case ACPI_BUS_TYPE_POWER: - type_string = "Power Resource"; - break; - case ACPI_BUS_TYPE_PROCESSOR: - type_string = "Processor"; - break; - case ACPI_BUS_TYPE_SYSTEM: - type_string = "System"; - break; - case ACPI_BUS_TYPE_THERMAL: - type_string = "Thermal Zone"; - break; - case ACPI_BUS_TYPE_POWER_BUTTON: - type_string = "Power Button"; - sprintf(name, "PWRB"); - break; - case ACPI_BUS_TYPE_SLEEP_BUTTON: - type_string = "Sleep Button"; - sprintf(name, "SLPB"); - break; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s %s [%p]\n", - type_string, name, handle)); - } -#endif /*CONFIG_ACPI_DEBUG*/ - - /* - * Global Device Hierarchy: - * ------------------------ - * Register this device with the global device hierarchy. - */ - acpi_device_register(device, parent); - - /* - * Bind _ADR-Based Devices - * ----------------------- - * If there's a a bus address (_ADR) then we utilize the parent's - * 'bind' function (if exists) to bind the ACPI- and natively- - * enumerated device representations. - */ - if (device->flags.bus_address) { - if (device->parent && device->parent->ops.bind) - device->parent->ops.bind(device); - } - - /* - * Locate & Attach Driver - * ---------------------- - * If there's a hardware id (_HID) or compatible ids (_CID) we check - * to see if there's a driver installed for this kind of device. Note - * that drivers can install before or after a device in enumerated. - * - * TBD: Assumes LDM provides driver hot-plug capability. - */ - if (device->flags.hardware_id || device->flags.compatible_ids) - acpi_bus_find_driver(device); - -end: - if (result) { - kfree(device); - return_VALUE(result); - } - - *child = device; - - return_VALUE(0); -} - - -static int -acpi_bus_remove ( - struct acpi_device *device, - int type) -{ - ACPI_FUNCTION_TRACE("acpi_bus_remove"); - - if (!device) - return_VALUE(-ENODEV); - - acpi_device_unregister(device); - - kfree(device); - - return_VALUE(0); -} - - -int -acpi_bus_scan ( - struct acpi_device *start) -{ - acpi_status status = AE_OK; - struct acpi_device *parent = NULL; - struct acpi_device *child = NULL; - acpi_handle phandle = 0; - acpi_handle chandle = 0; - acpi_object_type type = 0; - u32 level = 1; - - ACPI_FUNCTION_TRACE("acpi_bus_scan"); - - if (!start) - return_VALUE(-EINVAL); - - parent = start; - phandle = start->handle; - - /* - * Parse through the ACPI namespace, identify all 'devices', and - * create a new 'struct acpi_device' for each. - */ - while ((level > 0) && parent) { - - status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, - chandle, &chandle); - - /* - * If this scope is exhausted then move our way back up. - */ - if (ACPI_FAILURE(status)) { - level--; - chandle = phandle; - acpi_get_parent(phandle, &phandle); - if (parent->parent) - parent = parent->parent; - continue; - } - - status = acpi_get_type(chandle, &type); - if (ACPI_FAILURE(status)) - continue; - - /* - * If this is a scope object then parse it (depth-first). - */ - if (type == ACPI_TYPE_ANY) { - /* Hack to get around scope identity problem */ - status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, 0, NULL); - if (ACPI_SUCCESS(status)) { - level++; - phandle = chandle; - chandle = 0; - } - continue; - } - - /* - * We're only interested in objects that we consider 'devices'. - */ - switch (type) { - case ACPI_TYPE_DEVICE: - type = ACPI_BUS_TYPE_DEVICE; - break; - case ACPI_TYPE_PROCESSOR: - type = ACPI_BUS_TYPE_PROCESSOR; - break; - case ACPI_TYPE_THERMAL: - type = ACPI_BUS_TYPE_THERMAL; - break; - case ACPI_TYPE_POWER: - type = ACPI_BUS_TYPE_POWER; - break; - default: - continue; - } - - status = acpi_bus_add(&child, parent, chandle, type); - if (ACPI_FAILURE(status)) - continue; - - /* - * If the device is present, enabled, and functioning then - * parse its scope (depth-first). Note that we need to - * represent absent devices to facilitate PnP notifications - * -- but only the subtree head (not all of its children, - * which will be enumerated when the parent is inserted). - * - * TBD: Need notifications and other detection mechanisms - * in place before we can fully implement this. - */ - if (child->status.present) { - status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, - 0, NULL); - if (ACPI_SUCCESS(status)) { - level++; - phandle = chandle; - chandle = 0; - parent = child; - } - } - } - - return_VALUE(0); -} - - -static int -acpi_bus_scan_fixed ( - struct acpi_device *root) -{ - int result = 0; - struct acpi_device *device = NULL; - - ACPI_FUNCTION_TRACE("acpi_bus_scan_fixed"); - - if (!root) - return_VALUE(-ENODEV); - - /* - * Enumerate all fixed-feature devices. - */ - if (acpi_fadt.pwr_button == 0) - result = acpi_bus_add(&device, acpi_root, - ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_POWER_BUTTON); - - if (acpi_fadt.sleep_button == 0) - result = acpi_bus_add(&device, acpi_root, - ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SLEEP_BUTTON); - - return_VALUE(result); -} - - /* -------------------------------------------------------------------------- Initialization/Cleanup -------------------------------------------------------------------------- */ -int __init -acpi_blacklisted(void) -{ - int i = 0; - int blacklisted = 0; - acpi_table_header table_header; - - while (acpi_blacklist[i].oem_id[0] != '\0') - { - if (!ACPI_SUCCESS(acpi_get_table_header(acpi_blacklist[i].table, 1, &table_header))) { - i++; - continue; - } - - if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) { - i++; - continue; - } - - if (strncmp(acpi_blacklist[i].oem_table_id, table_header.oem_table_id, 8)) { - i++; - continue; - } - - if ((acpi_blacklist[i].oem_revision_predicate == all_versions) - || (acpi_blacklist[i].oem_revision_predicate == less_than_or_equal - && table_header.oem_revision <= acpi_blacklist[i].oem_revision) - || (acpi_blacklist[i].oem_revision_predicate == greater_than_or_equal - && table_header.oem_revision >= acpi_blacklist[i].oem_revision) - || (acpi_blacklist[i].oem_revision_predicate == equal - && table_header.oem_revision == acpi_blacklist[i].oem_revision)) { - - printk(KERN_ERR PREFIX "Vendor \"%6.6s\" System \"%8.8s\" " - "Revision 0x%x has a known ACPI BIOS problem.\n", - acpi_blacklist[i].oem_id, - acpi_blacklist[i].oem_table_id, - acpi_blacklist[i].oem_revision); - - printk(KERN_ERR PREFIX "Reason: %s. This is a %s error\n", - acpi_blacklist[i].reason, - (acpi_blacklist[i].is_critical_error ? "non-recoverable" : "recoverable")); - - blacklisted = acpi_blacklist[i].is_critical_error; - break; - } - else { - i++; - } - } - - return blacklisted; -} - static int __init acpi_bus_init_irq (void) { @@ -1956,10 +600,6 @@ goto error0; } - if (acpi_blacklisted()) { - goto error1; - } - /* * Get a separate copy of the FADT for use by other drivers. */ @@ -1972,7 +612,7 @@ #ifdef CONFIG_X86 /* Ensure the SCI is set to level-triggered, active-low */ if (acpi_ioapic) - mp_override_legacy_irq(acpi_fadt.sci_int, 3, 3, acpi_fadt.sci_int); + mp_config_ioapic_for_sci(acpi_fadt.sci_int); else eisa_set_level_irq(acpi_fadt.sci_int); #endif @@ -1986,14 +626,15 @@ #ifdef CONFIG_ACPI_EC /* * ACPI 2.0 requires the EC driver to be loaded and work before - * the EC device is found in the namespace. This is accomplished - * by looking for the ECDT table, and getting the EC parameters out - * of that. + * the EC device is found in the namespace (i.e. before acpi_initialize_objects() + * is called). + * + * This is accomplished by looking for the ECDT table, and getting + * the EC parameters out of that. */ - result = acpi_ec_ecdt_probe(); - if (result) { + status = acpi_ec_ecdt_probe(); + if (ACPI_FAILURE(status)) goto error1; - } #endif status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION); @@ -2017,61 +658,17 @@ status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, &acpi_bus_notify, NULL); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to register for device notifications\n"); - result = -ENODEV; goto error1; } /* - * Create the root device in the bus's device tree - */ - result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, - ACPI_BUS_TYPE_SYSTEM); - if (result) - goto error2; - - /* * Create the top ACPI proc directory */ - acpi_device_dir(acpi_root) = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL); - if (!acpi_root) { - result = -ENODEV; - goto error3; - } - acpi_root_dir = acpi_device_dir(acpi_root); - - /* - * Install drivers required for proper enumeration of the - * ACPI namespace. - */ - acpi_system_init(); /* ACPI System */ - acpi_power_init(); /* ACPI Bus Power Management */ -#ifdef CONFIG_ACPI_EC - acpi_ec_init(); /* ACPI Embedded Controller */ -#endif -#ifdef CONFIG_ACPI_PCI - acpi_pci_link_init(); /* ACPI PCI Interrupt Link */ - acpi_pci_root_init(); /* ACPI PCI Root Bridge */ -#endif - /* - * Enumerate devices in the ACPI namespace. - */ - result = acpi_bus_scan_fixed(acpi_root); - if (result) - goto error4; - result = acpi_bus_scan(acpi_root); - if (result) - goto error4; + acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL); return_VALUE(0); /* Mimic structured exception handling */ -error4: - remove_proc_entry(ACPI_BUS_FILE_ROOT, NULL); -error3: - acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL); -error2: - acpi_remove_notify_handler(ACPI_ROOT_OBJECT, - ACPI_SYSTEM_NOTIFY, &acpi_bus_notify); error1: acpi_terminate(); error0: @@ -2079,45 +676,7 @@ } -static void __exit -acpi_bus_exit (void) -{ - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE("acpi_bus_exit"); - - status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, - ACPI_SYSTEM_NOTIFY, acpi_bus_notify); - if (ACPI_FAILURE(status)) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Error removing notify handler\n")); - -#ifdef CONFIG_ACPI_PCI - acpi_pci_root_exit(); - acpi_pci_link_exit(); -#endif -#ifdef CONFIG_ACPI_EC - acpi_ec_exit(); -#endif - acpi_power_exit(); - acpi_system_exit(); - - acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL); - - remove_proc_entry(ACPI_BUS_FILE_ROOT, NULL); - - status = acpi_terminate(); - if (ACPI_FAILURE(status)) - printk(KERN_ERR PREFIX "Unable to terminate the ACPI Interpreter\n"); - else - printk(KERN_ERR PREFIX "Interpreter disabled\n"); - - return_VOID; -} - - -int __init -acpi_init (void) +static int __init acpi_init (void) { int result = 0; @@ -2134,42 +693,26 @@ return -ENODEV; } -#ifdef CONFIG_PM - if (PM_IS_ACTIVE()) { - printk(KERN_INFO PREFIX "APM is already active, exiting\n"); - return -ENODEV; - } -#endif - result = acpi_bus_init(); - if (result) - return_VALUE(result); - -#ifdef CONFIG_PM - pm_active = 1; -#endif - - return_VALUE(0); -} - - -void __exit -acpi_exit (void) -{ - ACPI_FUNCTION_TRACE("acpi_exit"); + if (!result) { #ifdef CONFIG_PM - pm_active = 0; + if (!PM_IS_ACTIVE()) + pm_active = 1; + else { + printk(KERN_INFO PREFIX "APM is already active, exiting\n"); + acpi_disabled = 1; + result = -ENODEV; + } #endif + } else + acpi_disabled = 1; - acpi_bus_exit(); - - return_VOID; + return_VALUE(result); } -int __init -acpi_setup(char *str) +static int __init acpi_setup(char *str) { while (str && *str) { if (strncmp(str, "off", 3) == 0) diff -Nru a/drivers/acpi/button.c b/drivers/acpi/button.c --- a/drivers/acpi/button.c Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/button.c Fri Sep 20 08:20:41 2002 @@ -40,7 +40,31 @@ MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME); MODULE_LICENSE("GPL"); -#define PREFIX "ACPI: " +#define ACPI_BUTTON_COMPONENT 0x00080000 +#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver" +#define ACPI_BUTTON_CLASS "button" +#define ACPI_BUTTON_FILE_INFO "info" +#define ACPI_BUTTON_TYPE_UNKNOWN 0x00 +#define ACPI_BUTTON_NOTIFY_STATUS 0x80 + +#define ACPI_BUTTON_SUBCLASS_POWER "power" +#define ACPI_BUTTON_HID_POWER "PNP0C0C" +#define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)" +#define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)" +#define ACPI_BUTTON_TYPE_POWER 0x01 +#define ACPI_BUTTON_TYPE_POWERF 0x02 + +#define ACPI_BUTTON_SUBCLASS_SLEEP "sleep" +#define ACPI_BUTTON_HID_SLEEP "PNP0C0E" +#define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)" +#define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)" +#define ACPI_BUTTON_TYPE_SLEEP 0x03 +#define ACPI_BUTTON_TYPE_SLEEPF 0x04 + +#define ACPI_BUTTON_SUBCLASS_LID "lid" +#define ACPI_BUTTON_HID_LID "PNP0C0D" +#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" +#define ACPI_BUTTON_TYPE_LID 0x05 int acpi_button_add (struct acpi_device *device); diff -Nru a/drivers/acpi/debug.c b/drivers/acpi/debug.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/debug.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,130 @@ +/* + * debug.c - ACPI debug interface to userspace. + */ + +#include +#include +#include +#include "acpi_drivers.h" + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("debug") + +#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" +#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" + +static int +acpi_system_read_debug ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + char *p = page; + int size = 0; + + if (off != 0) + goto end; + + switch ((unsigned long) data) { + case 0: + p += sprintf(p, "0x%08x\n", acpi_dbg_layer); + break; + case 1: + p += sprintf(p, "0x%08x\n", acpi_dbg_level); + break; + default: + p += sprintf(p, "Invalid debug option\n"); + break; + } + +end: + size = (p - page); + if (size <= off+count) *eof = 1; + *start = page + off; + size -= off; + if (size>count) size = count; + if (size<0) size = 0; + + return size; +} + + +static int +acpi_system_write_debug ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + char debug_string[12] = {'\0'}; + + ACPI_FUNCTION_TRACE("acpi_system_write_debug"); + + if (count > sizeof(debug_string) - 1) + return_VALUE(-EINVAL); + + if (copy_from_user(debug_string, buffer, count)) + return_VALUE(-EFAULT); + + debug_string[count] = '\0'; + + switch ((unsigned long) data) { + case 0: + acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0); + break; + case 1: + acpi_dbg_level = simple_strtoul(debug_string, NULL, 0); + break; + default: + return_VALUE(-EINVAL); + } + + return_VALUE(count); +} + +static int __init acpi_debug_init(void) +{ + struct proc_dir_entry *entry; + int error = 0; + char * name; + + ACPI_FUNCTION_TRACE("acpi_debug_init"); + + if (acpi_disabled) + return_VALUE(0); + + /* 'debug_layer' [R/W] */ + name = ACPI_SYSTEM_FILE_DEBUG_LAYER; + entry = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir, + acpi_system_read_debug,(void *)0); + if (entry) + entry->write_proc = acpi_system_write_debug; + else + goto Error; + + /* 'debug_level' [R/W] */ + name = ACPI_SYSTEM_FILE_DEBUG_LEVEL; + entry = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir, + acpi_system_read_debug, (void *)1); + if (entry) + entry->write_proc = acpi_system_write_debug; + else + goto Error; + + Done: + return_VALUE(error); + + Error: + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' proc fs entry\n", name)); + + remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, acpi_root_dir); + remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, acpi_root_dir); + error = -EFAULT; + goto Done; +} + +subsys_initcall(acpi_debug_init); diff -Nru a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c --- a/drivers/acpi/dispatcher/dsfield.c Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/dispatcher/dsfield.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: dsfield - Dispatcher field routines - * $Revision: 66 $ + * $Revision: 67 $ * *****************************************************************************/ @@ -250,7 +250,7 @@ } ACPI_REPORT_ERROR (("Field name [%4.4s] already exists in current scope\n", - &arg->named.name)); + (char *) &arg->named.name)); } else { arg->common.node = info->field_node; @@ -271,7 +271,7 @@ if (position > ACPI_UINT32_MAX) { ACPI_REPORT_ERROR (("Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n", - &info->field_node->name)); + (char *) &info->field_node->name)); return_ACPI_STATUS (AE_SUPPORT); } @@ -417,7 +417,7 @@ } ACPI_REPORT_ERROR (("Field name [%4.4s] already exists in current scope\n", - &arg->named.name)); + (char *) &arg->named.name)); /* Name already exists, just ignore this error */ diff -Nru a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c --- a/drivers/acpi/dispatcher/dsobject.c Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/dispatcher/dsobject.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: dsobject - Dispatcher object management routines - * $Revision: 106 $ + * $Revision: 107 $ * *****************************************************************************/ @@ -746,9 +746,10 @@ obj_desc->reference.opcode = AML_LOCAL_OP; obj_desc->reference.offset = opcode - AML_LOCAL_OP; + #ifndef ACPI_NO_METHOD_EXECUTION - acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset, - walk_state, (acpi_namespace_node **) &obj_desc->reference.object); + status = acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset, + walk_state, (acpi_namespace_node **) &obj_desc->reference.object); #endif break; diff -Nru a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c --- a/drivers/acpi/dispatcher/dswload.c Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/dispatcher/dswload.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: dswload - Dispatcher namespace load callbacks - * $Revision: 71 $ + * $Revision: 73 $ * *****************************************************************************/ @@ -202,7 +202,26 @@ /* These are acceptable types */ break; - default: + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* + * These types we will allow, but we will change the type. This + * enables some existing code of the form: + * + * Name (DEB, 0) + * Scope (DEB) { ... } + */ + + ACPI_REPORT_WARNING (("Invalid type (%s) for target of Scope operator [%4.4s], changing type to ANY\n", + acpi_ut_get_type_name (node->type), path)); + + node->type = ACPI_TYPE_ANY; + walk_state->scope_info->common.value = ACPI_TYPE_ANY; + break; + + default: /* All other types are an error */ @@ -440,6 +459,51 @@ } if (ACPI_SUCCESS (status)) { + /* + * For the scope op, we must check to make sure that the target is + * one of the opcodes that actually opens a scope + */ + if (walk_state->opcode == AML_SCOPE_OP) { + switch (node->type) { + case ACPI_TYPE_ANY: /* Scope nodes are untyped (ANY) */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_METHOD: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* These are acceptable types */ + break; + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* + * These types we will allow, but we will change the type. This + * enables some existing code of the form: + * + * Name (DEB, 0) + * Scope (DEB) { ... } + */ + + ACPI_REPORT_WARNING (("Invalid type (%s) for target of Scope operator [%4.4s], changing type to ANY\n", + acpi_ut_get_type_name (node->type), buffer_ptr)); + + node->type = ACPI_TYPE_ANY; + walk_state->scope_info->common.value = ACPI_TYPE_ANY; + break; + + default: + + /* All other types are an error */ + + ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n", + acpi_ut_get_type_name (node->type), buffer_ptr)); + + return (AE_AML_OPERAND_TYPE); + } + } if (!op) { /* Create a new op */ diff -Nru a/drivers/acpi/driverfs.c b/drivers/acpi/driverfs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/driverfs.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,46 @@ +/* + * driverfs.c - ACPI bindings for driverfs. + * + * Copyright (c) 2002 Patrick Mochel + * Copyright (c) 2002 The Open Source Development Lab + * + */ + +#include +#include +#include + +#include "acpi_bus.h" + +static struct driver_dir_entry acpi_dir = { + .name = "acpi", + .mode = (S_IRWXU | S_IRUGO | S_IXUGO), +}; + +/* driverfs ops for ACPI attribute files go here, when/if + * there are ACPI attribute files. + * For now, we just have directory creation and removal. + */ + +void acpi_remove_dir(struct acpi_device * dev) +{ + if (dev) + driverfs_remove_dir(&dev->driverfs_dir); +} + +int acpi_create_dir(struct acpi_device * dev) +{ + struct driver_dir_entry * parent; + + parent = dev->parent ? &dev->parent->driverfs_dir : &acpi_dir; + dev->driverfs_dir.name = dev->pnp.bus_id; + dev->driverfs_dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO); + return driverfs_create_dir(&dev->driverfs_dir,parent); +} + +static int __init acpi_driverfs_init(void) +{ + return driverfs_create_dir(&acpi_dir,NULL); +} + +subsys_initcall(acpi_driverfs_init); diff -Nru a/drivers/acpi/ec.c b/drivers/acpi/ec.c --- a/drivers/acpi/ec.c Fri Sep 20 08:20:46 2002 +++ b/drivers/acpi/ec.c Fri Sep 20 08:20:46 2002 @@ -38,7 +38,12 @@ #define _COMPONENT ACPI_EC_COMPONENT ACPI_MODULE_NAME ("acpi_ec") -#define PREFIX "ACPI: " +#define ACPI_EC_COMPONENT 0x00100000 +#define ACPI_EC_CLASS "embedded_controller" +#define ACPI_EC_HID "PNP0C09" +#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" +#define ACPI_EC_DEVICE_NAME "Embedded Controller" +#define ACPI_EC_FILE_INFO "info" #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ @@ -784,23 +789,23 @@ } -int __init -acpi_ec_init (void) +static int __init acpi_ec_init (void) { int result = 0; ACPI_FUNCTION_TRACE("acpi_ec_init"); - result = acpi_bus_register_driver(&acpi_ec_driver); - if (result < 0) { - remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir); - return_VALUE(-ENODEV); - } + if (acpi_disabled) + return_VALUE(0); - return_VALUE(0); + /* Now register the driver for the EC */ + result = acpi_bus_register_driver(&acpi_ec_driver); + return_VALUE(result); } -void __exit +subsys_initcall(acpi_ec_init); + +static void __exit acpi_ec_ecdt_exit (void) { if (!ec_ecdt) @@ -814,7 +819,7 @@ kfree(ec_ecdt); } -void __exit +static void __exit acpi_ec_exit (void) { int result = 0; diff -Nru a/drivers/acpi/event.c b/drivers/acpi/event.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/event.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,140 @@ +/* + * event.c - exporting ACPI events via procfs + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + */ + +#include +#include +#include +#include +#include "acpi_drivers.h" + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("event") + +/* Global vars for handling event proc entry */ +static spinlock_t acpi_system_event_lock = SPIN_LOCK_UNLOCKED; +int event_is_open = 0; +extern struct list_head acpi_bus_event_list; +extern wait_queue_head_t acpi_bus_event_queue; + +static int +acpi_system_open_event(struct inode *inode, struct file *file) +{ + spin_lock_irq (&acpi_system_event_lock); + + if(event_is_open) + goto out_busy; + + event_is_open = 1; + + spin_unlock_irq (&acpi_system_event_lock); + return 0; + +out_busy: + spin_unlock_irq (&acpi_system_event_lock); + return -EBUSY; +} + +static ssize_t +acpi_system_read_event ( + struct file *file, + char *buffer, + size_t count, + loff_t *ppos) +{ + int result = 0; + struct acpi_bus_event event; + static char str[ACPI_MAX_STRING]; + static int chars_remaining = 0; + static char *ptr; + + + ACPI_FUNCTION_TRACE("acpi_system_read_event"); + + if (!chars_remaining) { + memset(&event, 0, sizeof(struct acpi_bus_event)); + + if ((file->f_flags & O_NONBLOCK) + && (list_empty(&acpi_bus_event_list))) + return_VALUE(-EAGAIN); + + result = acpi_bus_receive_event(&event); + if (result) { + return_VALUE(-EIO); + } + + chars_remaining = sprintf(str, "%s %s %08x %08x\n", + event.device_class?event.device_class:"", + event.bus_id?event.bus_id:"", + event.type, event.data); + ptr = str; + } + + if (chars_remaining < count) { + count = chars_remaining; + } + + if (copy_to_user(buffer, ptr, count)) + return_VALUE(-EFAULT); + + *ppos += count; + chars_remaining -= count; + ptr += count; + + return_VALUE(count); +} + +static int +acpi_system_close_event(struct inode *inode, struct file *file) +{ + spin_lock_irq (&acpi_system_event_lock); + event_is_open = 0; + spin_unlock_irq (&acpi_system_event_lock); + return 0; +} + +static unsigned int +acpi_system_poll_event( + struct file *file, + poll_table *wait) +{ + poll_wait(file, &acpi_bus_event_queue, wait); + if (!list_empty(&acpi_bus_event_list)) + return POLLIN | POLLRDNORM; + return 0; +} + +static struct file_operations acpi_system_event_ops = { + .open = acpi_system_open_event, + .read = acpi_system_read_event, + .release = acpi_system_close_event, + .poll = acpi_system_poll_event, +}; + +static int __init acpi_event_init(void) +{ + struct proc_dir_entry *entry; + int error = 0; + + ACPI_FUNCTION_TRACE("acpi_event_init"); + + if (acpi_disabled) + return_VALUE(0); + + /* 'event' [R] */ + entry = create_proc_entry("event", S_IRUSR, acpi_root_dir); + if (entry) + entry->proc_fops = &acpi_system_event_ops; + else { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' proc fs entry\n","event" )); + error = -EFAULT; + } + return_VALUE(error); +} + +subsys_initcall(acpi_event_init); diff -Nru a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c --- a/drivers/acpi/executer/exconvrt.c Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/executer/exconvrt.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: exconvrt - Object conversion routines - * $Revision: 37 $ + * $Revision: 38 $ * *****************************************************************************/ @@ -230,7 +230,33 @@ case ACPI_TYPE_STRING: - *result_desc = obj_desc; + /* + * Create a new Buffer object + */ + ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); + if (!ret_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Need enough space for one integer */ + + new_buf = ACPI_MEM_CALLOCATE (obj_desc->string.length); + if (!new_buf) { + ACPI_REPORT_ERROR + (("Ex_convert_to_buffer: Buffer allocation failure\n")); + acpi_ut_remove_reference (ret_desc); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + ACPI_STRNCPY ((char *) new_buf, (char *) obj_desc->string.pointer, obj_desc->string.length); + ret_desc->buffer.flags |= AOPOBJ_DATA_VALID; + ret_desc->buffer.pointer = new_buf; + ret_desc->buffer.length = obj_desc->string.length; + + /* Return the new buffer descriptor */ + + *result_desc = ret_desc; + break; diff -Nru a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c --- a/drivers/acpi/executer/exmisc.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/executer/exmisc.c Fri Sep 20 08:20:47 2002 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes - * $Revision: 108 $ + * $Revision: 109 $ * *****************************************************************************/ @@ -28,7 +28,6 @@ #include "acpi.h" #include "acinterp.h" #include "amlcode.h" -#include "acdispat.h" #define _COMPONENT ACPI_EXECUTER diff -Nru a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c --- a/drivers/acpi/executer/exoparg1.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/executer/exoparg1.c Fri Sep 20 08:20:47 2002 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exoparg1 - AML execution - opcodes with 1 argument - * $Revision: 142 $ + * $Revision: 143 $ * *****************************************************************************/ @@ -59,7 +59,6 @@ * fully resolved operands. !*/ - /******************************************************************************* * * FUNCTION: Acpi_ex_opcode_1A_0T_0R @@ -561,73 +560,11 @@ case AML_TYPE_OP: /* Object_type (Source_object) */ - if (ACPI_GET_OBJECT_TYPE (operand[0]) == INTERNAL_TYPE_REFERENCE) { - /* - * Not a Name -- an indirect name pointer would have - * been converted to a direct name pointer in Resolve_operands - */ - switch (operand[0]->reference.opcode) { - case AML_DEBUG_OP: - - /* The Debug Object is of type "Debug_object" */ - - type = ACPI_TYPE_DEBUG_OBJECT; - break; - - - case AML_INDEX_OP: - - /* Get the type of this reference (index into another object) */ - - type = operand[0]->reference.target_type; - if (type == ACPI_TYPE_PACKAGE) { - /* - * The main object is a package, we want to get the type - * of the individual package element that is referenced by - * the index. - */ - type = ACPI_GET_OBJECT_TYPE (*(operand[0]->reference.where)); - } - break; - - - case AML_LOCAL_OP: - case AML_ARG_OP: - - type = acpi_ds_method_data_get_type (operand[0]->reference.opcode, - operand[0]->reference.offset, walk_state); - break; - - - default: - - ACPI_REPORT_ERROR (("Acpi_ex_opcode_1A_0T_1R/Type_op: Unknown Reference subtype %X\n", - operand[0]->reference.opcode)); - status = AE_AML_INTERNAL; - goto cleanup; - } - } - else { - /* - * It's not a Reference, so it must be a direct name pointer. - */ - type = acpi_ns_get_type ((acpi_namespace_node *) operand[0]); - - /* Convert internal types to external types */ - - switch (type) { - case INTERNAL_TYPE_REGION_FIELD: - case INTERNAL_TYPE_BANK_FIELD: - case INTERNAL_TYPE_INDEX_FIELD: - - type = ACPI_TYPE_FIELD_UNIT; - break; - - default: - /* No change to Type required */ - break; - } + /* Get the type of the base object */ + status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, NULL); + if (ACPI_FAILURE (status)) { + goto cleanup; } /* Allocate a descriptor to hold the type. */ @@ -644,39 +581,36 @@ case AML_SIZE_OF_OP: /* Size_of (Source_object) */ - temp_desc = operand[0]; - if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) == ACPI_DESC_TYPE_NAMED) { - temp_desc = acpi_ns_get_attached_object ((acpi_namespace_node *) operand[0]); - } + /* Get the base object */ - if (!temp_desc) { - value = 0; + status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, &temp_desc); + if (ACPI_FAILURE (status)) { + goto cleanup; } - else { - /* - * Type is guaranteed to be a buffer, string, or package at this - * point (even if the original operand was an object reference, it - * will be resolved and typechecked during operand resolution.) - */ - switch (ACPI_GET_OBJECT_TYPE (temp_desc)) { - case ACPI_TYPE_BUFFER: - value = temp_desc->buffer.length; - break; - - case ACPI_TYPE_STRING: - value = temp_desc->string.length; - break; - - case ACPI_TYPE_PACKAGE: - value = temp_desc->package.count; - break; - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Size_of, Not Buf/Str/Pkg - found type %s\n", - acpi_ut_get_object_type_name (temp_desc))); - status = AE_AML_OPERAND_TYPE; - goto cleanup; - } + + /* + * Type is guaranteed to be a buffer, string, or package at this + * point (even if the original operand was an object reference, it + * will be resolved and typechecked during operand resolution.) + */ + switch (type) { + case ACPI_TYPE_BUFFER: + value = temp_desc->buffer.length; + break; + + case ACPI_TYPE_STRING: + value = temp_desc->string.length; + break; + + case ACPI_TYPE_PACKAGE: + value = temp_desc->package.count; + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Size_of, Not Buf/Str/Pkg - found type %s\n", + acpi_ut_get_type_name (type))); + status = AE_AML_OPERAND_TYPE; + goto cleanup; } /* diff -Nru a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c --- a/drivers/acpi/executer/exresnte.c Fri Sep 20 08:20:43 2002 +++ b/drivers/acpi/executer/exresnte.c Fri Sep 20 08:20:43 2002 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exresnte - AML Interpreter object resolution - * $Revision: 57 $ + * $Revision: 58 $ * *****************************************************************************/ @@ -26,7 +26,6 @@ #include "acpi.h" -#include "amlcode.h" #include "acdispat.h" #include "acinterp.h" #include "acnamesp.h" diff -Nru a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c --- a/drivers/acpi/executer/exresolv.c Fri Sep 20 08:20:44 2002 +++ b/drivers/acpi/executer/exresolv.c Fri Sep 20 08:20:44 2002 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exresolv - AML Interpreter object resolution - * $Revision: 115 $ + * $Revision: 116 $ * *****************************************************************************/ @@ -29,6 +29,7 @@ #include "amlcode.h" #include "acdispat.h" #include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER @@ -277,6 +278,172 @@ } return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ex_resolve_multiple + * + * PARAMETERS: Walk_state - Current state (contains AML opcode) + * Operand - Starting point for resolution + * Return_type - Where the object type is returned + * Return_desc - Where the resolved object is returned + * + * RETURN: Status + * + * DESCRIPTION: Return the base object and type. Traverse a reference list if + * necessary to get to the base object. + * + ******************************************************************************/ + +acpi_status +acpi_ex_resolve_multiple ( + acpi_walk_state *walk_state, + acpi_operand_object *operand, + acpi_object_type *return_type, + acpi_operand_object **return_desc) +{ + acpi_operand_object *obj_desc = (void *) operand; + acpi_namespace_node *node; + acpi_object_type type; + + + ACPI_FUNCTION_TRACE ("Ex_get_object_type"); + + + /* + * For reference objects created via the Ref_of or Index operators, + * we need to get to the base object (as per the ACPI specification + * of the Object_type and Size_of operators). This means traversing + * the list of possibly many nested references. + */ + while (ACPI_GET_OBJECT_TYPE (obj_desc) == INTERNAL_TYPE_REFERENCE) { + switch (obj_desc->reference.opcode) { + case AML_REF_OF_OP: + + /* Dereference the reference pointer */ + + node = obj_desc->reference.object; + + /* All "References" point to a NS node */ + + if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* Get the attached object */ + + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + /* No object, use the NS node type */ + + type = acpi_ns_get_type (node); + goto exit; + } + + /* Check for circular references */ + + if (obj_desc == operand) { + return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE); + } + break; + + + case AML_INDEX_OP: + + /* Get the type of this reference (index into another object) */ + + type = obj_desc->reference.target_type; + if (type != ACPI_TYPE_PACKAGE) { + goto exit; + } + + /* + * The main object is a package, we want to get the type + * of the individual package element that is referenced by + * the index. + * + * This could of course in turn be another reference object. + */ + obj_desc = *(obj_desc->reference.where); + break; + + + case AML_INT_NAMEPATH_OP: + + /* Dereference the reference pointer */ + + node = obj_desc->reference.node; + + /* All "References" point to a NS node */ + + if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* Get the attached object */ + + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + /* No object, use the NS node type */ + + type = acpi_ns_get_type (node); + goto exit; + } + + /* Check for circular references */ + + if (obj_desc == operand) { + return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE); + } + break; + + + case AML_DEBUG_OP: + + /* The Debug Object is of type "Debug_object" */ + + type = ACPI_TYPE_DEBUG_OBJECT; + goto exit; + + + default: + + ACPI_REPORT_ERROR (("Acpi_ex_resolve_multiple: Unknown Reference subtype %X\n", + obj_desc->reference.opcode)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + } + + /* + * Now we are guaranteed to have an object that has not been created + * via the Ref_of or Index operators. + */ + type = ACPI_GET_OBJECT_TYPE (obj_desc); + + +exit: + /* Convert internal types to external types */ + + switch (type) { + case INTERNAL_TYPE_REGION_FIELD: + case INTERNAL_TYPE_BANK_FIELD: + case INTERNAL_TYPE_INDEX_FIELD: + + type = ACPI_TYPE_FIELD_UNIT; + break; + + default: + /* No change to Type required */ + break; + } + + *return_type = type; + if (return_desc) { + *return_desc = obj_desc; + } + return_ACPI_STATUS (AE_OK); } diff -Nru a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c --- a/drivers/acpi/executer/exresop.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/executer/exresop.c Fri Sep 20 08:20:47 2002 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exresop - AML Interpreter operand/object resolution - * $Revision: 55 $ + * $Revision: 57 $ * *****************************************************************************/ @@ -29,7 +29,6 @@ #include "amlcode.h" #include "acparser.h" #include "acinterp.h" -#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER @@ -463,11 +462,12 @@ case ARGI_DATAOBJECT: /* * ARGI_DATAOBJECT is only used by the Size_of operator. - * Need a buffer, string, package, or Node reference. + * Need a buffer, string, package, or Ref_of reference. * * The only reference allowed here is a direct reference to * a namespace node. */ +#if 0 if (ACPI_GET_OBJECT_TYPE (*stack_ptr) == INTERNAL_TYPE_REFERENCE) { if (!(*stack_ptr)->reference.node) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, @@ -497,13 +497,14 @@ acpi_ut_remove_reference (*stack_ptr); (*stack_ptr) = temp_node; } - +#endif /* Need a buffer, string, package */ switch (ACPI_GET_OBJECT_TYPE (*stack_ptr)) { case ACPI_TYPE_PACKAGE: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: + case INTERNAL_TYPE_REFERENCE: /* Valid operand */ break; diff -Nru a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c --- a/drivers/acpi/executer/exstore.c Fri Sep 20 08:20:45 2002 +++ b/drivers/acpi/executer/exstore.c Fri Sep 20 08:20:45 2002 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exstore - AML Interpreter object store support - * $Revision: 169 $ + * $Revision: 171 $ * *****************************************************************************/ @@ -103,7 +103,7 @@ return_ACPI_STATUS (AE_OK); } - /*lint: -fallthrough */ + /*lint -fallthrough */ default: @@ -286,6 +286,12 @@ if (new_desc != obj_desc) { acpi_ut_remove_reference (obj_desc); *(index_desc->reference.where) = new_desc; + + /* If same as the original source, add a reference */ + + if (new_desc == source_desc) { + acpi_ut_add_reference (new_desc); + } } break; diff -Nru a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c --- a/drivers/acpi/executer/exstoren.c Fri Sep 20 08:20:42 2002 +++ b/drivers/acpi/executer/exstoren.c Fri Sep 20 08:20:42 2002 @@ -3,7 +3,7 @@ * * Module Name: exstoren - AML Interpreter object store support, * Store to Node (namespace object) - * $Revision: 50 $ + * $Revision: 51 $ * *****************************************************************************/ @@ -209,6 +209,15 @@ &actual_src_desc, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); + } + + if (source_desc == actual_src_desc) { + /* + * No conversion was performed. Return the Source_desc as the + * new object. + */ + *new_desc = source_desc; + return_ACPI_STATUS (AE_OK); } } diff -Nru a/drivers/acpi/fan.c b/drivers/acpi/fan.c --- a/drivers/acpi/fan.c Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/fan.c Fri Sep 20 08:20:41 2002 @@ -40,8 +40,13 @@ MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME); MODULE_LICENSE("GPL"); -#define PREFIX "ACPI: " - +#define ACPI_FAN_COMPONENT 0x00200000 +#define ACPI_FAN_CLASS "fan" +#define ACPI_FAN_HID "PNP0C0B" +#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver" +#define ACPI_FAN_DEVICE_NAME "Fan" +#define ACPI_FAN_FILE_STATE "state" +#define ACPI_FAN_NOTIFY_STATUS 0x80 int acpi_fan_add (struct acpi_device *device); int acpi_fan_remove (struct acpi_device *device, int type); diff -Nru a/drivers/acpi/include/acconfig.h b/drivers/acpi/include/acconfig.h --- a/drivers/acpi/include/acconfig.h Fri Sep 20 08:20:43 2002 +++ b/drivers/acpi/include/acconfig.h Fri Sep 20 08:20:43 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acconfig.h - Global configuration constants - * $Revision: 110 $ + * $Revision: 111 $ * *****************************************************************************/ @@ -54,7 +54,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20020829 +#define ACPI_CA_VERSION 0x20020918 /* Version of ACPI supported */ diff -Nru a/drivers/acpi/include/acdebug.h b/drivers/acpi/include/acdebug.h --- a/drivers/acpi/include/acdebug.h Fri Sep 20 08:20:43 2002 +++ b/drivers/acpi/include/acdebug.h Fri Sep 20 08:20:43 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acdebug.h - ACPI/AML debugger - * $Revision: 63 $ + * $Revision: 64 $ * *****************************************************************************/ @@ -196,6 +196,10 @@ acpi_db_decode_and_display_object ( NATIVE_CHAR *target, NATIVE_CHAR *output_type); + +void +acpi_db_decode_node ( + acpi_namespace_node *node); void acpi_db_display_result_object ( diff -Nru a/drivers/acpi/include/acexcep.h b/drivers/acpi/include/acexcep.h --- a/drivers/acpi/include/acexcep.h Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/include/acexcep.h Fri Sep 20 08:20:41 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acexcep.h - Exception codes returned by the ACPI subsystem - * $Revision: 63 $ + * $Revision: 64 $ * *****************************************************************************/ @@ -142,8 +142,9 @@ #define AE_AML_ALIGNMENT (acpi_status) (0x001D | AE_CODE_AML) #define AE_AML_NO_RESOURCE_END_TAG (acpi_status) (0x001E | AE_CODE_AML) #define AE_AML_BAD_RESOURCE_VALUE (acpi_status) (0x001F | AE_CODE_AML) +#define AE_AML_CIRCULAR_REFERENCE (acpi_status) (0x0020 | AE_CODE_AML) -#define AE_CODE_AML_MAX 0x001F +#define AE_CODE_AML_MAX 0x0020 /* * Internal exceptions used for control @@ -158,8 +159,9 @@ #define AE_CTRL_TRANSFER (acpi_status) (0x0008 | AE_CODE_CONTROL) #define AE_CTRL_BREAK (acpi_status) (0x0009 | AE_CODE_CONTROL) #define AE_CTRL_CONTINUE (acpi_status) (0x000A | AE_CODE_CONTROL) +#define AE_CTRL_SKIP (acpi_status) (0x000B | AE_CODE_CONTROL) -#define AE_CODE_CTRL_MAX 0x000A +#define AE_CODE_CTRL_MAX 0x000B #ifdef DEFINE_ACPI_GLOBALS @@ -255,7 +257,8 @@ "AE_AML_NO_WHILE", "AE_AML_ALIGNMENT", "AE_AML_NO_RESOURCE_END_TAG", - "AE_AML_BAD_RESOURCE_VALUE" + "AE_AML_BAD_RESOURCE_VALUE", + "AE_AML_CIRCULAR_REFERENCE" }; NATIVE_CHAR const *acpi_gbl_exception_names_ctrl[] = @@ -269,7 +272,8 @@ "AE_CTRL_END", "AE_CTRL_TRANSFER", "AE_CTRL_BREAK", - "AE_CTRL_CONTINUE" + "AE_CTRL_CONTINUE", + "AE_CTRL_SKIP" }; #endif /* ACPI GLOBALS */ diff -Nru a/drivers/acpi/include/acinterp.h b/drivers/acpi/include/acinterp.h --- a/drivers/acpi/include/acinterp.h Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/include/acinterp.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acinterp.h - Interpreter subcomponent prototypes and defines - * $Revision: 138 $ + * $Revision: 139 $ * *****************************************************************************/ @@ -193,6 +193,13 @@ acpi_operand_object *obj_desc, acpi_operand_object **return_desc, acpi_walk_state *walk_state); + +acpi_status +acpi_ex_resolve_multiple ( + acpi_walk_state *walk_state, + acpi_operand_object *operand, + acpi_object_type *return_type, + acpi_operand_object **return_desc); acpi_status acpi_ex_concat_template ( diff -Nru a/drivers/acpi/include/acpiosxf.h b/drivers/acpi/include/acpiosxf.h --- a/drivers/acpi/include/acpiosxf.h Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/include/acpiosxf.h Fri Sep 20 08:20:41 2002 @@ -261,6 +261,10 @@ void *pointer, u32 length); +u32 +acpi_os_get_timer ( + void); + acpi_status acpi_os_signal ( u32 function, @@ -280,6 +284,10 @@ const NATIVE_CHAR *format, va_list args); +void +acpi_os_redirect_output ( + void *destination); + /* * Debug input @@ -288,6 +296,18 @@ u32 acpi_os_get_line ( NATIVE_CHAR *buffer); + + +/* + * Debug + */ + +void +acpi_os_dbg_assert( + void *failed_assertion, + void *file_name, + u32 line_number, + NATIVE_CHAR *message); #endif /* __ACPIOSXF_H__ */ diff -Nru a/drivers/acpi/include/actypes.h b/drivers/acpi/include/actypes.h --- a/drivers/acpi/include/actypes.h Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/include/actypes.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: actypes.h - Common data types for the entire ACPI subsystem - * $Revision: 238 $ + * $Revision: 239 $ * *****************************************************************************/ diff -Nru a/drivers/acpi/include/acutils.h b/drivers/acpi/include/acutils.h --- a/drivers/acpi/include/acutils.h Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/include/acutils.h Fri Sep 20 08:20:41 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures - * $Revision: 143 $ + * $Revision: 144 $ * *****************************************************************************/ @@ -138,7 +138,7 @@ #ifndef ACPI_USE_SYSTEM_CLIBRARY -u32 +ACPI_SIZE acpi_ut_strlen ( const NATIVE_CHAR *string); @@ -151,15 +151,15 @@ acpi_ut_strncpy ( NATIVE_CHAR *dst_string, const NATIVE_CHAR *src_string, - NATIVE_UINT count); + ACPI_SIZE count); int acpi_ut_strncmp ( const NATIVE_CHAR *string1, const NATIVE_CHAR *string2, - NATIVE_UINT count); + ACPI_SIZE count); -u32 +int acpi_ut_strcmp ( const NATIVE_CHAR *string1, const NATIVE_CHAR *string2); @@ -173,7 +173,7 @@ acpi_ut_strncat ( NATIVE_CHAR *dst_string, const NATIVE_CHAR *src_string, - NATIVE_UINT count); + ACPI_SIZE count); u32 acpi_ut_strtoul ( @@ -190,13 +190,13 @@ acpi_ut_memcpy ( void *dest, const void *src, - NATIVE_UINT count); + ACPI_SIZE count); void * acpi_ut_memset ( void *dest, NATIVE_UINT value, - NATIVE_UINT count); + ACPI_SIZE count); int acpi_ut_to_upper ( diff -Nru a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c --- a/drivers/acpi/namespace/nsdump.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/namespace/nsdump.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: nsdump - table dumping routines for debug - * $Revision: 139 $ + * $Revision: 140 $ * *****************************************************************************/ @@ -116,7 +116,7 @@ status = acpi_ns_handle_to_pathname (handle, &buffer); if (ACPI_SUCCESS (status)) { - acpi_os_printf ("%s %s (Node %p)\n", msg, buffer.pointer, handle); + acpi_os_printf ("%s %s (Node %p)\n", msg, (char *) buffer.pointer, handle); ACPI_MEM_FREE (buffer.pointer); } @@ -254,10 +254,10 @@ switch (type) { case ACPI_TYPE_PROCESSOR: - acpi_os_printf (" ID %hd Addr %.4X Len %.4X\n", + acpi_os_printf (" ID %X Len %.4X Addr %p\n", obj_desc->processor.proc_id, - obj_desc->processor.address, - obj_desc->processor.length); + obj_desc->processor.length, + (char *) obj_desc->processor.address); break; @@ -269,8 +269,8 @@ case ACPI_TYPE_METHOD: - acpi_os_printf (" Args %hd Len %.4X Aml %p \n", - obj_desc->method.param_count, + acpi_os_printf (" Args %X Len %.4X Aml %p\n", + (u32) obj_desc->method.param_count, obj_desc->method.aml_length, obj_desc->method.aml_start); break; diff -Nru a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c --- a/drivers/acpi/namespace/nsdumpdv.c Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/namespace/nsdumpdv.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: nsdump - table dumping routines for debug - * $Revision: 3 $ + * $Revision: 4 $ * *****************************************************************************/ @@ -26,7 +26,6 @@ #include "acpi.h" #include "acnamesp.h" -#include "acparser.h" #define _COMPONENT ACPI_NAMESPACE diff -Nru a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c --- a/drivers/acpi/namespace/nsload.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/namespace/nsload.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: nsload - namespace loading/expanding/contracting procedures - * $Revision: 58 $ + * $Revision: 59 $ * *****************************************************************************/ @@ -26,7 +26,6 @@ #include "acpi.h" #include "acnamesp.h" -#include "amlcode.h" #include "acparser.h" #include "acdispat.h" diff -Nru a/drivers/acpi/numa.c b/drivers/acpi/numa.c --- a/drivers/acpi/numa.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/numa.c Fri Sep 20 08:20:47 2002 @@ -30,8 +30,6 @@ #include #include -#define PREFIX "ACPI: " - extern int __init acpi_table_parse_madt_family (enum acpi_table_id id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler); void __init diff -Nru a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c --- a/drivers/acpi/parser/psxface.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/parser/psxface.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: psxface - Parser external interfaces - * $Revision: 65 $ + * $Revision: 66 $ * *****************************************************************************/ @@ -28,7 +28,6 @@ #include "acparser.h" #include "acdispat.h" #include "acinterp.h" -#include "amlcode.h" #include "acnamesp.h" diff -Nru a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c --- a/drivers/acpi/pci_bind.c Fri Sep 20 08:20:43 2002 +++ b/drivers/acpi/pci_bind.c Fri Sep 20 08:20:43 2002 @@ -39,9 +39,6 @@ #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME ("pci_bind") -#define PREFIX "ACPI: " - - struct acpi_pci_data { acpi_pci_id id; struct pci_bus *bus; diff -Nru a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c --- a/drivers/acpi/pci_irq.c Fri Sep 20 08:20:46 2002 +++ b/drivers/acpi/pci_irq.c Fri Sep 20 08:20:46 2002 @@ -41,8 +41,6 @@ #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME ("pci_irq") -#define PREFIX "PCI: " - struct acpi_prt_list acpi_prt; #ifdef CONFIG_X86 diff -Nru a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c --- a/drivers/acpi/pci_link.c Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/pci_link.c Fri Sep 20 08:20:41 2002 @@ -45,8 +45,12 @@ #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME ("pci_link") -#define PREFIX "ACPI: " - +#define ACPI_PCI_LINK_CLASS "pci_irq_routing" +#define ACPI_PCI_LINK_HID "PNP0C0F" +#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" +#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" +#define ACPI_PCI_LINK_FILE_INFO "info" +#define ACPI_PCI_LINK_FILE_STATUS "state" #define ACPI_PCI_LINK_MAX_POSSIBLE 16 @@ -570,11 +574,13 @@ } -int __init -acpi_pci_link_init (void) +static int __init acpi_pci_link_init (void) { ACPI_FUNCTION_TRACE("acpi_pci_link_init"); + if (acpi_disabled) + return_VALUE(0); + acpi_link.count = 0; INIT_LIST_HEAD(&acpi_link.entries); @@ -583,3 +589,5 @@ return_VALUE(0); } + +subsys_initcall(acpi_pci_link_init); diff -Nru a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c --- a/drivers/acpi/pci_root.c Fri Sep 20 08:20:44 2002 +++ b/drivers/acpi/pci_root.c Fri Sep 20 08:20:44 2002 @@ -39,9 +39,12 @@ #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME ("pci_root") -extern struct pci_ops *pci_root_ops; +#define ACPI_PCI_ROOT_CLASS "pci_bridge" +#define ACPI_PCI_ROOT_HID "PNP0A03" +#define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" +#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" -#define PREFIX "ACPI: " +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); @@ -318,11 +321,13 @@ } -int __init -acpi_pci_root_init (void) +static int __init acpi_pci_root_init (void) { ACPI_FUNCTION_TRACE("acpi_pci_root_init"); + if (acpi_disabled) + return_VALUE(0); + /* DEBUG: acpi_dbg_layer = ACPI_PCI_COMPONENT; acpi_dbg_level = 0xFFFFFFFF; @@ -336,13 +341,5 @@ return_VALUE(0); } +subsys_initcall(acpi_pci_root_init); -void __exit -acpi_pci_root_exit (void) -{ - ACPI_FUNCTION_TRACE("acpi_pci_root_exit"); - - acpi_bus_unregister_driver(&acpi_pci_root_driver); - - return_VOID; -} diff -Nru a/drivers/acpi/power.c b/drivers/acpi/power.c --- a/drivers/acpi/power.c Fri Sep 20 08:20:46 2002 +++ b/drivers/acpi/power.c Fri Sep 20 08:20:46 2002 @@ -36,8 +36,15 @@ #define _COMPONENT ACPI_POWER_COMPONENT ACPI_MODULE_NAME ("acpi_power") -#define PREFIX "ACPI: " - +#define ACPI_POWER_COMPONENT 0x00800000 +#define ACPI_POWER_CLASS "power_resource" +#define ACPI_POWER_DRIVER_NAME "ACPI Power Resource Driver" +#define ACPI_POWER_DEVICE_NAME "Power Resource" +#define ACPI_POWER_FILE_INFO "info" +#define ACPI_POWER_FILE_STATUS "state" +#define ACPI_POWER_RESOURCE_STATE_OFF 0x00 +#define ACPI_POWER_RESOURCE_STATE_ON 0x01 +#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF int acpi_power_add (struct acpi_device *device); int acpi_power_remove (struct acpi_device *device, int type); @@ -573,13 +580,15 @@ } -int __init -acpi_power_init (void) +static int __init acpi_power_init (void) { int result = 0; ACPI_FUNCTION_TRACE("acpi_power_init"); + if (acpi_disabled) + return_VALUE(0); + INIT_LIST_HEAD(&acpi_power_resource_list); result = acpi_bus_register_driver(&acpi_power_driver); @@ -591,19 +600,5 @@ return_VALUE(0); } +subsys_initcall(acpi_power_init); -void __exit -acpi_power_exit (void) -{ - int result = 0; - - ACPI_FUNCTION_TRACE("acpi_power_exit"); - - /* TBD: Empty acpi_power_resource_list */ - - result = acpi_bus_unregister_driver(&acpi_power_driver); - if (!result) - remove_proc_entry(ACPI_POWER_CLASS, acpi_root_dir); - - return_VOID; -} diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c --- a/drivers/acpi/processor.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/processor.c Fri Sep 20 08:20:47 2002 @@ -51,7 +51,17 @@ MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME); MODULE_LICENSE("GPL"); -#define PREFIX "ACPI: " +#define ACPI_PROCESSOR_COMPONENT 0x01000000 +#define ACPI_PROCESSOR_CLASS "processor" +#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" +#define ACPI_PROCESSOR_DEVICE_NAME "Processor" +#define ACPI_PROCESSOR_FILE_INFO "info" +#define ACPI_PROCESSOR_FILE_POWER "power" +#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" +#define ACPI_PROCESSOR_FILE_THROTTLING "throttling" +#define ACPI_PROCESSOR_FILE_LIMIT "limit" +#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 +#define ACPI_PROCESSOR_NOTIFY_POWER 0x81 #define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000) #define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */ diff -Nru a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c --- a/drivers/acpi/resources/rsdump.c Fri Sep 20 08:20:46 2002 +++ b/drivers/acpi/resources/rsdump.c Fri Sep 20 08:20:46 2002 @@ -1,7 +1,7 @@ /******************************************************************************* * * Module Name: rsdump - Functions to display the resource structures. - * $Revision: 33 $ + * $Revision: 34 $ * ******************************************************************************/ @@ -865,20 +865,25 @@ ACPI_ADDRESS_FIXED == address64_data->max_address_fixed ? "" : "not "); - acpi_os_printf (" Granularity: %16X\n", - address64_data->granularity); - - acpi_os_printf (" Address range min: %16X\n", - address64_data->min_address_range); - - acpi_os_printf (" Address range max: %16X\n", - address64_data->max_address_range); - - acpi_os_printf (" Address translation offset: %16X\n", - address64_data->address_translation_offset); - - acpi_os_printf (" Address Length: %16X\n", - address64_data->address_length); + acpi_os_printf (" Granularity: %8.8X%8.8X\n", + ACPI_HIDWORD (address64_data->granularity), + ACPI_LODWORD (address64_data->granularity)); + + acpi_os_printf (" Address range min: %8.8X%8.8X\n", + ACPI_HIDWORD (address64_data->min_address_range), + ACPI_HIDWORD (address64_data->min_address_range)); + + acpi_os_printf (" Address range max: %8.8X%8.8X\n", + ACPI_HIDWORD (address64_data->max_address_range), + ACPI_HIDWORD (address64_data->max_address_range)); + + acpi_os_printf (" Address translation offset: %8.8X%8.8X\n", + ACPI_HIDWORD (address64_data->address_translation_offset), + ACPI_HIDWORD (address64_data->address_translation_offset)); + + acpi_os_printf (" Address Length: %8.8X%8.8X\n", + ACPI_HIDWORD (address64_data->address_length), + ACPI_HIDWORD (address64_data->address_length)); if(0xFF != address64_data->resource_source.index) { acpi_os_printf (" Resource Source Index: %X\n", diff -Nru a/drivers/acpi/scan.c b/drivers/acpi/scan.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/scan.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,944 @@ +/* + * scan.c - support for transforming the ACPI namespace into individual objects + */ + +#include +#include + +#include "acpi_drivers.h" +#include "include/acinterp.h" /* for acpi_ex_eisa_id_to_string() */ + + +#define _COMPONENT ACPI_BUS_COMPONENT +ACPI_MODULE_NAME ("scan") + +#define STRUCT_TO_INT(s) (*((int*)&s)) + +extern struct acpi_device *acpi_root; + + +#define ACPI_BUS_CLASS "system_bus" +#define ACPI_BUS_HID "ACPI_BUS" +#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver" +#define ACPI_BUS_DEVICE_NAME "System Bus" + +static LIST_HEAD(acpi_device_list); +static spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED; + +static int +acpi_device_register ( + struct acpi_device *device, + struct acpi_device *parent) +{ + return acpi_create_dir(device); +} + + +static int +acpi_device_unregister ( + struct acpi_device *device) +{ + acpi_remove_dir(device); + return 0; +} + +void +acpi_bus_data_handler ( + acpi_handle handle, + u32 function, + void *context) +{ + ACPI_FUNCTION_TRACE("acpi_bus_data_handler"); + + /* TBD */ + + return_VOID; +} + +static int +acpi_bus_get_power_flags ( + struct acpi_device *device) +{ + acpi_status status = 0; + acpi_handle handle = 0; + u32 i = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_get_power_flags"); + + /* + * Power Management Flags + */ + status = acpi_get_handle(device->handle, "_PSC", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.explicit_get = 1; + status = acpi_get_handle(device->handle, "_IRC", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.inrush_current = 1; + status = acpi_get_handle(device->handle, "_PRW", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.wake_capable = 1; + + /* + * Enumerate supported power management states + */ + for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { + struct acpi_device_power_state *ps = &device->power.states[i]; + char object_name[5] = {'_','P','R','0'+i,'\0'}; + + /* Evaluate "_PRx" to se if power resources are referenced */ + acpi_evaluate_reference(device->handle, object_name, NULL, + &ps->resources); + if (ps->resources.count) { + device->power.flags.power_resources = 1; + ps->flags.valid = 1; + } + + /* Evaluate "_PSx" to see if we can do explicit sets */ + object_name[2] = 'S'; + status = acpi_get_handle(device->handle, object_name, &handle); + if (ACPI_SUCCESS(status)) { + ps->flags.explicit_set = 1; + ps->flags.valid = 1; + } + + /* State is valid if we have some power control */ + if (ps->resources.count || ps->flags.explicit_set) + ps->flags.valid = 1; + + ps->power = -1; /* Unknown - driver assigned */ + ps->latency = -1; /* Unknown - driver assigned */ + } + + /* Set defaults for D0 and D3 states (always valid) */ + device->power.states[ACPI_STATE_D0].flags.valid = 1; + device->power.states[ACPI_STATE_D0].power = 100; + device->power.states[ACPI_STATE_D3].flags.valid = 1; + device->power.states[ACPI_STATE_D3].power = 0; + + /* TBD: System wake support and resource requirements. */ + + device->power.state = ACPI_STATE_UNKNOWN; + + return 0; +} + + +/* -------------------------------------------------------------------------- + Performance Management + -------------------------------------------------------------------------- */ + +static int +acpi_bus_get_perf_flags ( + struct acpi_device *device) +{ + device->performance.state = ACPI_STATE_UNKNOWN; + return 0; +} + +/* -------------------------------------------------------------------------- + Driver Management + -------------------------------------------------------------------------- */ + +static LIST_HEAD(acpi_bus_drivers); +static DECLARE_MUTEX(acpi_bus_drivers_lock); + + +/** + * acpi_bus_match + * -------------- + * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it + * matches the specified driver's criteria. + */ +static int +acpi_bus_match ( + struct acpi_device *device, + struct acpi_driver *driver) +{ + int error = 0; + acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + + if (device->flags.hardware_id) + if (strstr(driver->ids, device->pnp.hardware_id)) + goto Done; + + if (device->flags.compatible_ids) { + acpi_status status = AE_OK; + acpi_object *object = NULL; + char cid[256] = {}; + + status = acpi_evaluate_object(device->handle, "_CID", NULL, + &buffer); + if (ACPI_FAILURE(status) || !buffer.pointer) + return -ENOENT; + + object = (acpi_object *) buffer.pointer; + + switch (object->type) { + case ACPI_TYPE_INTEGER: + acpi_ex_eisa_id_to_string((u32) object->integer.value, + cid); + break; + case ACPI_TYPE_STRING: + strncpy(cid, object->string.pointer, sizeof(cid) - 1); + break; + case ACPI_TYPE_PACKAGE: + /* TBD: Support CID packages */ + break; + } + + if (strlen(cid) && strstr(driver->ids,cid)) + goto Done; + } + error = -ENOENT; + + Done: + if (buffer.pointer) + acpi_os_free(buffer.pointer); + return error; +} + + +/** + * acpi_bus_driver_init + * -------------------- + * Used to initialize a device via its device driver. Called whenever a + * driver is bound to a device. Invokes the driver's add() and start() ops. + */ +static int +acpi_bus_driver_init ( + struct acpi_device *device, + struct acpi_driver *driver) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_driver_init"); + + if (!device || !driver) + return_VALUE(-EINVAL); + + if (!driver->ops.add) + return_VALUE(-ENOSYS); + + result = driver->ops.add(device); + if (result) { + device->driver = NULL; + acpi_driver_data(device) = NULL; + return_VALUE(result); + } + + /* + * TBD - Configuration Management: Assign resources to device based + * upon possible configuration and currently allocated resources. + */ + + if (driver->ops.start) { + result = driver->ops.start(device); + if (result && driver->ops.remove) + driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); + return_VALUE(result); + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); + + if (driver->ops.scan) { + driver->ops.scan(device); + } + + return_VALUE(0); +} + +static int acpi_driver_attach(struct acpi_driver * drv) +{ + struct list_head * node, * next; + + ACPI_FUNCTION_TRACE("acpi_driver_attach"); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node,next,&acpi_device_list) { + struct acpi_device * dev = container_of(node,struct acpi_device,g_list); + + if (dev->driver || !dev->status.present) + continue; + spin_unlock(&acpi_device_lock); + + if (!acpi_bus_match(dev,drv)) { + if (!acpi_bus_driver_init(dev,drv)) { + atomic_inc(&drv->references); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", + drv->name, dev->pnp.bus_id)); + } + } + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); + return_VALUE(0); +} + +static int acpi_driver_detach(struct acpi_driver * drv) +{ + struct list_head * node, * next; + + ACPI_FUNCTION_TRACE("acpi_driver_detach"); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node,next,&acpi_device_list) { + struct acpi_device * dev = container_of(node,struct acpi_device,g_list); + + if (dev->driver == drv) { + if (drv->ops.remove) + drv->ops.remove(dev,ACPI_BUS_REMOVAL_NORMAL); + dev->driver = NULL; + dev->driver_data = NULL; + atomic_dec(&drv->references); + } + } + spin_unlock(&acpi_device_lock); + return_VALUE(0); +} + +/** + * acpi_bus_register_driver + * ------------------------ + * Registers a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and binds. + */ +int +acpi_bus_register_driver ( + struct acpi_driver *driver) +{ + int error = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_register_driver"); + + if (driver) { + spin_lock(&acpi_device_lock); + list_add_tail(&driver->node, &acpi_bus_drivers); + spin_unlock(&acpi_device_lock); + acpi_driver_attach(driver); + } else + error = -EINVAL; + + return_VALUE(error); +} + + +/** + * acpi_bus_unregister_driver + * -------------------------- + * Unregisters a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and unbinds. + */ +int +acpi_bus_unregister_driver ( + struct acpi_driver *driver) +{ + int error = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_unregister_driver"); + + if (driver) { + acpi_driver_detach(driver); + + if (!atomic_read(&driver->references)) { + spin_lock(&acpi_device_lock); + list_del_init(&driver->node); + spin_unlock(&acpi_device_lock); + } + } else + error = -EINVAL; + return_VALUE(error); +} + +/** + * acpi_bus_find_driver + * -------------------- + * Parses the list of registered drivers looking for a driver applicable for + * the specified device. + */ +static int +acpi_bus_find_driver ( + struct acpi_device *device) +{ + int result = 0; + struct list_head * node, *next; + + ACPI_FUNCTION_TRACE("acpi_bus_find_driver"); + + if (!device->flags.hardware_id && !device->flags.compatible_ids) + goto Done; + + spin_lock(&acpi_device_lock); + list_for_each_safe(node,next,&acpi_bus_drivers) { + struct acpi_driver * driver = container_of(node,struct acpi_driver,node); + + atomic_inc(&driver->references); + spin_unlock(&acpi_device_lock); + if (!acpi_bus_match(device, driver)) { + result = acpi_bus_driver_init(device, driver); + if (!result) + goto Done; + } + atomic_dec(&driver->references); + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); + + Done: + return_VALUE(result); +} + + +/* -------------------------------------------------------------------------- + Device Enumeration + -------------------------------------------------------------------------- */ + +static int +acpi_bus_get_flags ( + struct acpi_device *device) +{ + acpi_status status = AE_OK; + acpi_handle temp = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_get_flags"); + + /* Presence of _STA indicates 'dynamic_status' */ + status = acpi_get_handle(device->handle, "_STA", &temp); + if (ACPI_SUCCESS(status)) + device->flags.dynamic_status = 1; + + /* Presence of _CID indicates 'compatible_ids' */ + status = acpi_get_handle(device->handle, "_CID", &temp); + if (ACPI_SUCCESS(status)) + device->flags.compatible_ids = 1; + + /* Presence of _RMV indicates 'removable' */ + status = acpi_get_handle(device->handle, "_RMV", &temp); + if (ACPI_SUCCESS(status)) + device->flags.removable = 1; + + /* Presence of _EJD|_EJ0 indicates 'ejectable' */ + status = acpi_get_handle(device->handle, "_EJD", &temp); + if (ACPI_SUCCESS(status)) + device->flags.ejectable = 1; + else { + status = acpi_get_handle(device->handle, "_EJ0", &temp); + if (ACPI_SUCCESS(status)) + device->flags.ejectable = 1; + } + + /* Presence of _LCK indicates 'lockable' */ + status = acpi_get_handle(device->handle, "_LCK", &temp); + if (ACPI_SUCCESS(status)) + device->flags.lockable = 1; + + /* Presence of _PS0|_PR0 indicates 'power manageable' */ + status = acpi_get_handle(device->handle, "_PS0", &temp); + if (ACPI_FAILURE(status)) + status = acpi_get_handle(device->handle, "_PR0", &temp); + if (ACPI_SUCCESS(status)) + device->flags.power_manageable = 1; + + /* TBD: Peformance management */ + + return_VALUE(0); +} + +static int +acpi_bus_remove ( + struct acpi_device *device, + int type) +{ + acpi_device_unregister(device); + kfree(device); + return 0; +} + +static void acpi_device_get_busid(struct acpi_device * device, acpi_handle handle, int type) +{ + char bus_id[5] = {'?',0}; + acpi_buffer buffer = {sizeof(bus_id), bus_id}; + int i = 0; + + /* + * Bus ID + * ------ + * The device's Bus ID is simply the object name. + * TBD: Shouldn't this value be unique (within the ACPI namespace)? + */ + switch (type) { + case ACPI_BUS_TYPE_SYSTEM: + sprintf(device->pnp.bus_id, "%s", "ACPI"); + break; + case ACPI_BUS_TYPE_POWER_BUTTON: + sprintf(device->pnp.bus_id, "%s", "PWRF"); + break; + case ACPI_BUS_TYPE_SLEEP_BUTTON: + sprintf(device->pnp.bus_id, "%s", "SLPF"); + break; + default: + acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + /* Clean up trailing underscores (if any) */ + for (i = 3; i > 1; i--) { + if (bus_id[i] == '_') + bus_id[i] = '\0'; + else + break; + } + sprintf(device->pnp.bus_id, "%s", bus_id); + break; + } +} + +static void acpi_device_set_id(struct acpi_device * device, struct acpi_device * parent, + acpi_handle handle, int type) +{ + acpi_device_info info; + char *hid = NULL; + char *uid = NULL; + acpi_status status; + + switch (type) { + case ACPI_BUS_TYPE_DEVICE: + status = acpi_get_object_info(handle, &info); + if (ACPI_FAILURE(status)) { + printk("%s: Error reading device info\n",__FUNCTION__); + return; + } + /* Clean up info strings (not NULL terminated) */ + info.hardware_id[sizeof(info.hardware_id)-1] = '\0'; + info.unique_id[sizeof(info.unique_id)-1] = '\0'; + if (info.valid & ACPI_VALID_HID) + hid = info.hardware_id; + if (info.valid & ACPI_VALID_UID) + uid = info.unique_id; + if (info.valid & ACPI_VALID_ADR) { + device->pnp.bus_address = info.address; + device->flags.bus_address = 1; + } + break; + case ACPI_BUS_TYPE_POWER: + hid = ACPI_POWER_HID; + break; + case ACPI_BUS_TYPE_PROCESSOR: + hid = ACPI_PROCESSOR_HID; + break; + case ACPI_BUS_TYPE_SYSTEM: + hid = ACPI_SYSTEM_HID; + break; + case ACPI_BUS_TYPE_THERMAL: + hid = ACPI_THERMAL_HID; + break; + case ACPI_BUS_TYPE_POWER_BUTTON: + hid = ACPI_BUTTON_HID_POWERF; + break; + case ACPI_BUS_TYPE_SLEEP_BUTTON: + hid = ACPI_BUTTON_HID_SLEEPF; + break; + } + + /* + * \_SB + * ---- + * Fix for the system root bus device -- the only root-level device. + */ + if ((parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) { + hid = ACPI_BUS_HID; + sprintf(device->pnp.device_name, "%s", ACPI_BUS_DEVICE_NAME); + sprintf(device->pnp.device_class, "%s", ACPI_BUS_CLASS); + } + + if (hid) { + sprintf(device->pnp.hardware_id, "%s", hid); + device->flags.hardware_id = 1; + } + if (uid) { + sprintf(device->pnp.unique_id, "%s", uid); + device->flags.unique_id = 1; + } +} + +int acpi_device_set_context(struct acpi_device * device, int type) +{ + acpi_status status = AE_OK; + int result = 0; + /* + * Context + * ------- + * Attach this 'struct acpi_device' to the ACPI object. This makes + * resolutions from handle->device very efficient. Note that we need + * to be careful with fixed-feature devices as they all attach to the + * root object. + */ + if (type != ACPI_BUS_TYPE_POWER_BUTTON && + type != ACPI_BUS_TYPE_SLEEP_BUTTON) { + status = acpi_attach_data(device->handle, + acpi_bus_data_handler, device); + + if (ACPI_FAILURE(status)) { + printk("Error attaching device data\n"); + result = -ENODEV; + } + } + return result; +} + +void acpi_device_get_debug_info(struct acpi_device * device, acpi_handle handle, int type) +{ +#ifdef CONFIG_ACPI_DEBUG + char *type_string = NULL; + char name[80] = {'?','\0'}; + acpi_buffer buffer = {sizeof(name), name}; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + switch (type) { + case ACPI_BUS_TYPE_DEVICE: + type_string = "Device"; + break; + case ACPI_BUS_TYPE_POWER: + type_string = "Power Resource"; + break; + case ACPI_BUS_TYPE_PROCESSOR: + type_string = "Processor"; + break; + case ACPI_BUS_TYPE_SYSTEM: + type_string = "System"; + break; + case ACPI_BUS_TYPE_THERMAL: + type_string = "Thermal Zone"; + break; + case ACPI_BUS_TYPE_POWER_BUTTON: + type_string = "Power Button"; + sprintf(name, "PWRB"); + break; + case ACPI_BUS_TYPE_SLEEP_BUTTON: + type_string = "Sleep Button"; + sprintf(name, "SLPB"); + break; + } + + pr_debug("Found %s %s [%p]\n", type_string, name, handle); +#endif /*CONFIG_ACPI_DEBUG*/ +} + +static void acpi_device_attach(struct acpi_device * device, struct acpi_device * parent) +{ + /* + * Linkage + * ------- + * Link this device to its parent and siblings. + */ + INIT_LIST_HEAD(&device->children); + INIT_LIST_HEAD(&device->node); + INIT_LIST_HEAD(&device->g_list); + + spin_lock(&acpi_device_lock); + if (device->parent) { + list_add_tail(&device->node, &device->parent->children); + list_add_tail(&device->g_list,&device->parent->g_list); + } else + list_add_tail(&device->g_list,&acpi_device_list); + spin_unlock(&acpi_device_lock); + + acpi_device_register(device, parent); +} + +static int +acpi_bus_add ( + struct acpi_device **child, + struct acpi_device *parent, + acpi_handle handle, + int type) +{ + int result = 0; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_add"); + + if (!child) + return_VALUE(-EINVAL); + + device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL); + if (!device) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n")); + return_VALUE(-ENOMEM); + } + memset(device, 0, sizeof(struct acpi_device)); + + device->handle = handle; + device->parent = parent; + + acpi_device_get_busid(device,handle,type); + + /* + * Flags + * ----- + * Get prior to calling acpi_bus_get_status() so we know whether + * or not _STA is present. Note that we only look for object + * handles -- cannot evaluate objects until we know the device is + * present and properly initialized. + */ + result = acpi_bus_get_flags(device); + if (result) + goto end; + + /* + * Status + * ------ + * See if the device is present. We always assume that non-Device() + * objects (e.g. thermal zones, power resources, processors, etc.) are + * present, functioning, etc. (at least when parent object is present). + * Note that _STA has a different meaning for some objects (e.g. + * power resources) so we need to be careful how we use it. + */ + switch (type) { + case ACPI_BUS_TYPE_DEVICE: + result = acpi_bus_get_status(device); + if (!result) + break; + if (!device->status.present) + result = -ENOENT; + goto end; + default: + STRUCT_TO_INT(device->status) = 0x0F; + break; + } + + /* + * Initialize Device + * ----------------- + * TBD: Synch with Core's enumeration/initialization process. + */ + + /* + * Hardware ID, Unique ID, & Bus Address + * ------------------------------------- + */ + acpi_device_set_id(device,parent,handle,type); + + /* + * Power Management + * ---------------- + */ + if (device->flags.power_manageable) { + result = acpi_bus_get_power_flags(device); + if (result) + goto end; + } + + /* + * Performance Management + * ---------------------- + */ + if (device->flags.performance_manageable) { + result = acpi_bus_get_perf_flags(device); + if (result) + goto end; + } + + if ((result = acpi_device_set_context(device,type))) + goto end; + + acpi_device_get_debug_info(device,handle,type); + + acpi_device_attach(device,parent); + + /* + * Bind _ADR-Based Devices + * ----------------------- + * If there's a a bus address (_ADR) then we utilize the parent's + * 'bind' function (if exists) to bind the ACPI- and natively- + * enumerated device representations. + */ + if (device->flags.bus_address) { + if (device->parent && device->parent->ops.bind) + device->parent->ops.bind(device); + } + + /* + * Locate & Attach Driver + * ---------------------- + * If there's a hardware id (_HID) or compatible ids (_CID) we check + * to see if there's a driver installed for this kind of device. Note + * that drivers can install before or after a device in enumerated. + * + * TBD: Assumes LDM provides driver hot-plug capability. + */ + acpi_bus_find_driver(device); + +end: + if (!result) + *child = device; + else + kfree(device); + return_VALUE(result); +} + + + +static int acpi_bus_scan (struct acpi_device *start) +{ + acpi_status status = AE_OK; + struct acpi_device *parent = NULL; + struct acpi_device *child = NULL; + acpi_handle phandle = 0; + acpi_handle chandle = 0; + acpi_object_type type = 0; + u32 level = 1; + + ACPI_FUNCTION_TRACE("acpi_bus_scan"); + + if (!start) + return_VALUE(-EINVAL); + + parent = start; + phandle = start->handle; + + /* + * Parse through the ACPI namespace, identify all 'devices', and + * create a new 'struct acpi_device' for each. + */ + while ((level > 0) && parent) { + + status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, + chandle, &chandle); + + /* + * If this scope is exhausted then move our way back up. + */ + if (ACPI_FAILURE(status)) { + level--; + chandle = phandle; + acpi_get_parent(phandle, &phandle); + if (parent->parent) + parent = parent->parent; + continue; + } + + status = acpi_get_type(chandle, &type); + if (ACPI_FAILURE(status)) + continue; + + /* + * If this is a scope object then parse it (depth-first). + */ + if (type == ACPI_TYPE_ANY) { + /* Hack to get around scope identity problem */ + status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, 0, NULL); + if (ACPI_SUCCESS(status)) { + level++; + phandle = chandle; + chandle = 0; + } + continue; + } + + /* + * We're only interested in objects that we consider 'devices'. + */ + switch (type) { + case ACPI_TYPE_DEVICE: + type = ACPI_BUS_TYPE_DEVICE; + break; + case ACPI_TYPE_PROCESSOR: + type = ACPI_BUS_TYPE_PROCESSOR; + break; + case ACPI_TYPE_THERMAL: + type = ACPI_BUS_TYPE_THERMAL; + break; + case ACPI_TYPE_POWER: + type = ACPI_BUS_TYPE_POWER; + break; + default: + continue; + } + + status = acpi_bus_add(&child, parent, chandle, type); + if (ACPI_FAILURE(status)) + continue; + + /* + * If the device is present, enabled, and functioning then + * parse its scope (depth-first). Note that we need to + * represent absent devices to facilitate PnP notifications + * -- but only the subtree head (not all of its children, + * which will be enumerated when the parent is inserted). + * + * TBD: Need notifications and other detection mechanisms + * in place before we can fully implement this. + */ + if (child->status.present) { + status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, + 0, NULL); + if (ACPI_SUCCESS(status)) { + level++; + phandle = chandle; + chandle = 0; + parent = child; + } + } + } + + return_VALUE(0); +} + + +static int +acpi_bus_scan_fixed ( + struct acpi_device *root) +{ + int result = 0; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_scan_fixed"); + + if (!root) + return_VALUE(-ENODEV); + + /* + * Enumerate all fixed-feature devices. + */ + if (acpi_fadt.pwr_button == 0) + result = acpi_bus_add(&device, acpi_root, + ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_POWER_BUTTON); + + if (acpi_fadt.sleep_button == 0) + result = acpi_bus_add(&device, acpi_root, + ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SLEEP_BUTTON); + + return_VALUE(result); +} + + +static int __init acpi_scan_init(void) +{ + int result; + + ACPI_FUNCTION_TRACE("acpi_scan_init"); + + if (acpi_disabled) + return_VALUE(0); + + /* + * Create the root device in the bus's device tree + */ + result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, + ACPI_BUS_TYPE_SYSTEM); + if (result) + goto Done; + + /* + * Enumerate devices in the ACPI namespace. + */ + result = acpi_bus_scan_fixed(acpi_root); + if (!result) + result = acpi_bus_scan(acpi_root); + + if (result) + acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL); + + Done: + return_VALUE(result); +} + +subsys_initcall(acpi_scan_init); diff -Nru a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/sleep.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,718 @@ +/* + * sleep.c - ACPI sleep support. + * + * Copyright (c) 2000-2002 Patrick Mochel + * + * Portions are + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "acpi_bus.h" +#include "acpi_drivers.h" + +#ifdef CONFIG_X86 +#include +#endif + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("sleep") + +#define ACPI_SYSTEM_FILE_SLEEP "sleep" +#define ACPI_SYSTEM_FILE_ALARM "alarm" + +static u8 sleep_states[ACPI_S_STATE_COUNT]; + +static void +acpi_power_off (void) +{ + acpi_enter_sleep_state_prep(ACPI_STATE_S5); + ACPI_DISABLE_IRQS(); + acpi_enter_sleep_state(ACPI_STATE_S5); +} + +/** + * acpi_system_restore_state - OS-specific restoration of state + * @state: sleep state we're exiting + * + * Note that if we're coming back from S4, the memory image should have already + * been loaded from the disk and is already in place. (Otherwise how else would we + * be here?). + */ +acpi_status +acpi_system_restore_state ( + u32 state) +{ + /* restore processor state + * We should only be here if we're coming back from STR or STD. + * And, in the case of the latter, the memory image should have already + * been loaded from disk. + */ + if (state > ACPI_STATE_S1) + acpi_restore_state_mem(); + + /* wait for power to come back */ + mdelay(10); + + /* turn all the devices back on */ + device_resume(RESUME_POWER_ON); + + /* enable interrupts once again */ + ACPI_ENABLE_IRQS(); + + /* restore device context */ + device_resume(RESUME_RESTORE_STATE); + + if (dmi_broken & BROKEN_INIT_AFTER_S1) { + printk("Broken toshiba laptop -> kicking interrupts\n"); + init_8259A(0); + } + + return AE_OK; +} + +/** + * acpi_system_save_state - save OS specific state and power down devices + * @state: sleep state we're entering. + * + * This handles saving all context to memory, and possibly disk. + * First, we call to the device driver layer to save device state. + * Once we have that, we save whatevery processor and kernel state we + * need to memory. + * If we're entering S4, we then write the memory image to disk. + * + * Only then is it safe for us to power down devices, since we may need + * the disks and upstream buses to write to. + */ +acpi_status +acpi_system_save_state( + u32 state) +{ + int error = 0; + + /* Send notification to devices that they will be suspended. + * If any device or driver cannot make the transition, either up + * or down, we'll get an error back. + */ + error = device_suspend(state, SUSPEND_NOTIFY); + if (error) + return AE_ERROR; + + if (state < ACPI_STATE_S5) { + + /* Tell devices to stop I/O and actually save their state. + * It is theoretically possible that something could fail, + * so handle that gracefully.. + */ + error = device_suspend(state, SUSPEND_SAVE_STATE); + if (error) { + /* tell devices to restore state if they have + * it saved and to start taking I/O requests. + */ + device_resume(RESUME_RESTORE_STATE); + return error; + } + + /* flush caches */ + ACPI_FLUSH_CPU_CACHE(); + + /* Do arch specific saving of state. */ + if (state > ACPI_STATE_S1) { + error = acpi_save_state_mem(); + + if (!error && (state == ACPI_STATE_S4)) + error = acpi_save_state_disk(); + + if (error) { + device_resume(RESUME_RESTORE_STATE); + return error; + } + } + } + + /* disable interrupts + * Note that acpi_suspend -- our caller -- will do this once we return. + * But, we want it done early, so we don't get any suprises during + * the device suspend sequence. + */ + ACPI_DISABLE_IRQS(); + + /* Unconditionally turn off devices. + * Obvious if we enter a sleep state. + * If entering S5 (soft off), this should put devices in a + * quiescent state. + */ + error = device_suspend(state, SUSPEND_POWER_DOWN); + + /* We're pretty screwed if we got an error from this. + * We try to recover by simply calling our own restore_state + * function; see above for definition. + * + * If it's S5 though, go through with it anyway.. + */ + if (error && state != ACPI_STATE_S5) + acpi_system_restore_state(state); + + return error ? AE_ERROR : AE_OK; +} + + +/**************************************************************************** + * + * FUNCTION: acpi_system_suspend + * + * PARAMETERS: %state: Sleep state to enter. + * + * RETURN: acpi_status, whether or not we successfully entered and + * exited sleep. + * + * DESCRIPTION: Perform OS-specific action to enter sleep state. + * This is the final step in going to sleep, per spec. If we + * know we're coming back (i.e. not entering S5), we save the + * processor flags. [ We'll have to save and restore them anyway, + * so we use the arch-agnostic save_flags and restore_flags + * here.] We then set the place to return to in arch-specific + * globals using arch_set_return_point. Finally, we call the + * ACPI function to write the proper values to I/O ports. + * + ****************************************************************************/ + +acpi_status +acpi_system_suspend( + u32 state) +{ + acpi_status status = AE_ERROR; + unsigned long flags = 0; + + local_irq_save(flags); + + switch (state) + { + case ACPI_STATE_S1: + barrier(); + status = acpi_enter_sleep_state(state); + break; + + case ACPI_STATE_S2: + case ACPI_STATE_S3: + do_suspend_lowlevel(0); + break; + } + local_irq_restore(flags); + + return status; +} + + +/** + * acpi_suspend - OS-agnostic system suspend/resume support (S? states) + * @state: state we're entering + * + */ +acpi_status +acpi_suspend ( + u32 state) +{ + acpi_status status; + + /* get out if state is invalid */ + if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5) + return AE_ERROR; + + freeze_processes(); /* device_suspend needs processes to be stopped */ + + /* do we have a wakeup address for S2 and S3? */ + if (state == ACPI_STATE_S2 || state == ACPI_STATE_S3) { + if (!acpi_wakeup_address) + return AE_ERROR; + acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) acpi_wakeup_address); + } + + acpi_enter_sleep_state_prep(state); + + status = acpi_system_save_state(state); + if (!ACPI_SUCCESS(status)) + return status; + + /* disable interrupts and flush caches */ + ACPI_DISABLE_IRQS(); + ACPI_FLUSH_CPU_CACHE(); + + /* perform OS-specific sleep actions */ + status = acpi_system_suspend(state); + + /* Even if we failed to go to sleep, all of the devices are in an suspended + * mode. So, we run these unconditionaly to make sure we have a usable system + * no matter what. + */ + acpi_system_restore_state(state); + acpi_leave_sleep_state(state); + + /* make sure interrupts are enabled */ + ACPI_ENABLE_IRQS(); + + /* reset firmware waking vector */ + acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) 0); + thaw_processes(); + + return status; +} + + +static int +acpi_system_read_sleep ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + char *p = page; + int size; + int i; + + ACPI_FUNCTION_TRACE("acpi_system_read_sleep"); + + if (off != 0) + goto end; + + for (i = 0; i <= ACPI_STATE_S5; i++) { + if (sleep_states[i]) + p += sprintf(p,"S%d ", i); + } + + p += sprintf(p, "\n"); + +end: + size = (p - page); + if (size <= off+count) *eof = 1; + *start = page + off; + size -= off; + if (size>count) size = count; + if (size<0) size = 0; + + return_VALUE(size); +} + + +static int +acpi_system_write_sleep ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + acpi_status status = AE_OK; + char state_string[12] = {'\0'}; + u32 state = 0; + + ACPI_FUNCTION_TRACE("acpi_system_write_sleep"); + + if (count > sizeof(state_string) - 1) + return_VALUE(-EINVAL); + + if (copy_from_user(state_string, buffer, count)) + return_VALUE(-EFAULT); + + state_string[count] = '\0'; + + state = simple_strtoul(state_string, NULL, 0); + + if (sleep_states[state]) + return_VALUE(-ENODEV); + +#ifdef CONFIG_SOFTWARE_SUSPEND + if (state == 4) { + software_suspend(); + return_VALUE(count); + } +#endif + status = acpi_suspend(state); + + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + return_VALUE(count); +} + + +static int +acpi_system_read_alarm ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *context) +{ + char *p = page; + int size = 0; + u32 sec, min, hr; + u32 day, mo, yr; + + ACPI_FUNCTION_TRACE("acpi_system_read_alarm"); + + if (off != 0) + goto end; + + spin_lock(&rtc_lock); + + sec = CMOS_READ(RTC_SECONDS_ALARM); + min = CMOS_READ(RTC_MINUTES_ALARM); + hr = CMOS_READ(RTC_HOURS_ALARM); + +#if 0 /* If we ever get an FACP with proper values... */ + if (acpi_gbl_FADT->day_alrm) + day = CMOS_READ(acpi_gbl_FADT->day_alrm); + else + day = CMOS_READ(RTC_DAY_OF_MONTH); + if (acpi_gbl_FADT->mon_alrm) + mo = CMOS_READ(acpi_gbl_FADT->mon_alrm); + else + mo = CMOS_READ(RTC_MONTH);; + if (acpi_gbl_FADT->century) + yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR); + else + yr = CMOS_READ(RTC_YEAR); +#else + day = CMOS_READ(RTC_DAY_OF_MONTH); + mo = CMOS_READ(RTC_MONTH); + yr = CMOS_READ(RTC_YEAR); +#endif + + spin_unlock(&rtc_lock); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hr); + BCD_TO_BIN(day); + BCD_TO_BIN(mo); + BCD_TO_BIN(yr); + +#if 0 + /* we're trusting the FADT (see above)*/ +#else + /* If we're not trusting the FADT, we should at least make it + * right for _this_ century... ehm, what is _this_ century? + * + * TBD: + * ASAP: find piece of code in the kernel, e.g. star tracker driver, + * which we can trust to determine the century correctly. Atom + * watch driver would be nice, too... + * + * if that has not happened, change for first release in 2050: + * if (yr<50) + * yr += 2100; + * else + * yr += 2000; // current line of code + * + * if that has not happened either, please do on 2099/12/31:23:59:59 + * s/2000/2100 + * + */ + yr += 2000; +#endif + + p += sprintf(p,"%4.4u-", yr); + p += (mo > 12) ? sprintf(p, "**-") : sprintf(p, "%2.2u-", mo); + p += (day > 31) ? sprintf(p, "** ") : sprintf(p, "%2.2u ", day); + p += (hr > 23) ? sprintf(p, "**:") : sprintf(p, "%2.2u:", hr); + p += (min > 59) ? sprintf(p, "**:") : sprintf(p, "%2.2u:", min); + p += (sec > 59) ? sprintf(p, "**\n") : sprintf(p, "%2.2u\n", sec); + + end: + size = p - page; + if (size < count) *eof = 1; + else if (size > count) size = count; + if (size < 0) size = 0; + *start = page; + + return_VALUE(size); +} + + +static int +get_date_field ( + char **p, + u32 *value) +{ + char *next = NULL; + char *string_end = NULL; + int result = -EINVAL; + + /* + * Try to find delimeter, only to insert null. The end of the + * string won't have one, but is still valid. + */ + next = strpbrk(*p, "- :"); + if (next) + *next++ = '\0'; + + *value = simple_strtoul(*p, &string_end, 10); + + /* Signal success if we got a good digit */ + if (string_end != *p) + result = 0; + + if (next) + *p = next; + + return result; +} + + +static int +acpi_system_write_alarm ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int result = 0; + char alarm_string[30] = {'\0'}; + char *p = alarm_string; + u32 sec, min, hr, day, mo, yr; + int adjust = 0; + unsigned char rtc_control = 0; + + ACPI_FUNCTION_TRACE("acpi_system_write_alarm"); + + if (count > sizeof(alarm_string) - 1) + return_VALUE(-EINVAL); + + if (copy_from_user(alarm_string, buffer, count)) + return_VALUE(-EFAULT); + + alarm_string[count] = '\0'; + + /* check for time adjustment */ + if (alarm_string[0] == '+') { + p++; + adjust = 1; + } + + if ((result = get_date_field(&p, &yr))) + goto end; + if ((result = get_date_field(&p, &mo))) + goto end; + if ((result = get_date_field(&p, &day))) + goto end; + if ((result = get_date_field(&p, &hr))) + goto end; + if ((result = get_date_field(&p, &min))) + goto end; + if ((result = get_date_field(&p, &sec))) + goto end; + + if (sec > 59) { + min += 1; + sec -= 60; + } + if (min > 59) { + hr += 1; + min -= 60; + } + if (hr > 23) { + day += 1; + hr -= 24; + } + if (day > 31) { + mo += 1; + day -= 31; + } + if (mo > 12) { + yr += 1; + mo -= 12; + } + + spin_lock_irq(&rtc_lock); + + rtc_control = CMOS_READ(RTC_CONTROL); + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(yr); + BIN_TO_BCD(mo); + BIN_TO_BCD(day); + BIN_TO_BCD(hr); + BIN_TO_BCD(min); + BIN_TO_BCD(sec); + } + + if (adjust) { + yr += CMOS_READ(RTC_YEAR); + mo += CMOS_READ(RTC_MONTH); + day += CMOS_READ(RTC_DAY_OF_MONTH); + hr += CMOS_READ(RTC_HOURS); + min += CMOS_READ(RTC_MINUTES); + sec += CMOS_READ(RTC_SECONDS); + } + + spin_unlock_irq(&rtc_lock); + + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(yr); + BCD_TO_BIN(mo); + BCD_TO_BIN(day); + BCD_TO_BIN(hr); + BCD_TO_BIN(min); + BCD_TO_BIN(sec); + } + + if (sec > 59) { + min++; + sec -= 60; + } + if (min > 59) { + hr++; + min -= 60; + } + if (hr > 23) { + day++; + hr -= 24; + } + if (day > 31) { + mo++; + day -= 31; + } + if (mo > 12) { + yr++; + mo -= 12; + } + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(yr); + BIN_TO_BCD(mo); + BIN_TO_BCD(day); + BIN_TO_BCD(hr); + BIN_TO_BCD(min); + BIN_TO_BCD(sec); + } + + spin_lock_irq(&rtc_lock); + + /* write the fields the rtc knows about */ + CMOS_WRITE(hr, RTC_HOURS_ALARM); + CMOS_WRITE(min, RTC_MINUTES_ALARM); + CMOS_WRITE(sec, RTC_SECONDS_ALARM); + + /* + * If the system supports an enhanced alarm it will have non-zero + * offsets into the CMOS RAM here -- which for some reason are pointing + * to the RTC area of memory. + */ +#if 0 + if (acpi_gbl_FADT->day_alrm) + CMOS_WRITE(day, acpi_gbl_FADT->day_alrm); + if (acpi_gbl_FADT->mon_alrm) + CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm); + if (acpi_gbl_FADT->century) + CMOS_WRITE(yr/100, acpi_gbl_FADT->century); +#endif + /* enable the rtc alarm interrupt */ + if (!(rtc_control & RTC_AIE)) { + rtc_control |= RTC_AIE; + CMOS_WRITE(rtc_control,RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + } + + spin_unlock_irq(&rtc_lock); + + acpi_set_register(ACPI_BITREG_RT_CLOCK_ENABLE, 1, ACPI_MTX_LOCK); + + file->f_pos += count; + + result = 0; +end: + return_VALUE(result ? result : count); +} + + +#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_PM) + +/* Simple wrapper calling power down function. */ +static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs, + struct tty_struct *tty) +{ + acpi_power_off(); +} + +struct sysrq_key_op sysrq_acpi_poweroff_op = { + .handler = &acpi_sysrq_power_off, + .help_msg = "Off", + .action_msg = "Power Off\n" +}; + +#endif /* CONFIG_MAGIC_SYSRQ */ + +static int __init acpi_sleep_init(void) +{ + struct proc_dir_entry *entry = NULL; + acpi_status status = AE_OK; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_system_add_fs"); + + if (acpi_disabled) + return_VALUE(0); + + printk(KERN_INFO PREFIX "(supports"); + for (i=0; iread_proc = acpi_system_read_sleep; + entry->write_proc = acpi_system_write_sleep; + } + + /* 'alarm' [R/W] */ + entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM, + S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_SYSTEM_FILE_ALARM)); + else { + entry->read_proc = acpi_system_read_alarm; + entry->write_proc = acpi_system_write_alarm; + } + + /* Install the soft-off (S5) handler. */ + if (sleep_states[ACPI_STATE_S5]) { + pm_power_off = acpi_power_off; + register_sysrq_key('o', &sysrq_acpi_poweroff_op); + + /* workaround: some systems don't claim S4 support, but they + do support S5 (power-down). That is all we need, so + indicate support. */ + sleep_states[ACPI_STATE_S4] = 1; + } + + return_VALUE(0); +} + +subsys_initcall(acpi_sleep_init); diff -Nru a/drivers/acpi/system.c b/drivers/acpi/system.c --- a/drivers/acpi/system.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/system.c Fri Sep 20 08:20:47 2002 @@ -23,314 +23,26 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include +#include #include -#include -#include "acpi_bus.h" -#include "acpi_drivers.h" -#ifdef CONFIG_X86 -#ifdef CONFIG_ACPI_SLEEP -#include -#endif -#endif +#include "acpi_drivers.h" #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME ("acpi_system") -#define PREFIX "ACPI: " +#define ACPI_SYSTEM_CLASS "system" +#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver" +#define ACPI_SYSTEM_DEVICE_NAME "System" +#define ACPI_SYSTEM_FILE_INFO "info" +#define ACPI_SYSTEM_FILE_EVENT "event" +#define ACPI_SYSTEM_FILE_DSDT "dsdt" +#define ACPI_SYSTEM_FILE_FADT "fadt" extern FADT_DESCRIPTOR acpi_fadt; -static int acpi_system_add (struct acpi_device *device); -static int acpi_system_remove (struct acpi_device *device, int type); - -static struct acpi_driver acpi_system_driver = { - .name = ACPI_SYSTEM_DRIVER_NAME, - .class = ACPI_SYSTEM_CLASS, - .ids = ACPI_SYSTEM_HID, - .ops = { - .add = acpi_system_add, - .remove = acpi_system_remove - }, -}; - -struct acpi_system -{ - acpi_handle handle; - u8 states[ACPI_S_STATE_COUNT]; -}; - -/* Global vars for handling event proc entry */ -static spinlock_t acpi_system_event_lock = SPIN_LOCK_UNLOCKED; -int event_is_open = 0; -extern struct list_head acpi_bus_event_list; -extern wait_queue_head_t acpi_bus_event_queue; - -/* -------------------------------------------------------------------------- - System Sleep - -------------------------------------------------------------------------- */ - -#ifdef CONFIG_PM - -static void -acpi_power_off (void) -{ - acpi_enter_sleep_state_prep(ACPI_STATE_S5); - ACPI_DISABLE_IRQS(); - acpi_enter_sleep_state(ACPI_STATE_S5); -} - -#endif /*CONFIG_PM*/ - - -#ifdef CONFIG_ACPI_SLEEP - -/** - * acpi_system_restore_state - OS-specific restoration of state - * @state: sleep state we're exiting - * - * Note that if we're coming back from S4, the memory image should have already - * been loaded from the disk and is already in place. (Otherwise how else would we - * be here?). - */ -acpi_status -acpi_system_restore_state ( - u32 state) -{ - /* restore processor state - * We should only be here if we're coming back from STR or STD. - * And, in the case of the latter, the memory image should have already - * been loaded from disk. - */ - if (state > ACPI_STATE_S1) - acpi_restore_state_mem(); - - /* wait for power to come back */ - mdelay(10); - - /* turn all the devices back on */ - device_resume(RESUME_POWER_ON); - - /* enable interrupts once again */ - ACPI_ENABLE_IRQS(); - - /* restore device context */ - device_resume(RESUME_RESTORE_STATE); - - if (dmi_broken & BROKEN_INIT_AFTER_S1) { - printk("Broken toshiba laptop -> kicking interrupts\n"); - init_8259A(0); - } - - return AE_OK; -} - -/** - * acpi_system_save_state - save OS specific state and power down devices - * @state: sleep state we're entering. - * - * This handles saving all context to memory, and possibly disk. - * First, we call to the device driver layer to save device state. - * Once we have that, we save whatevery processor and kernel state we - * need to memory. - * If we're entering S4, we then write the memory image to disk. - * - * Only then is it safe for us to power down devices, since we may need - * the disks and upstream buses to write to. - */ -acpi_status -acpi_system_save_state( - u32 state) -{ - int error = 0; - - /* Send notification to devices that they will be suspended. - * If any device or driver cannot make the transition, either up - * or down, we'll get an error back. - */ - error = device_suspend(state, SUSPEND_NOTIFY); - if (error) - return AE_ERROR; - - if (state < ACPI_STATE_S5) { - - /* Tell devices to stop I/O and actually save their state. - * It is theoretically possible that something could fail, - * so handle that gracefully.. - */ - error = device_suspend(state, SUSPEND_SAVE_STATE); - if (error) { - /* tell devices to restore state if they have - * it saved and to start taking I/O requests. - */ - device_resume(RESUME_RESTORE_STATE); - return error; - } - - /* flush caches */ - ACPI_FLUSH_CPU_CACHE(); - - /* Do arch specific saving of state. */ - if (state > ACPI_STATE_S1) { - error = acpi_save_state_mem(); - - if (!error && (state == ACPI_STATE_S4)) - error = acpi_save_state_disk(); - - if (error) { - device_resume(RESUME_RESTORE_STATE); - return error; - } - } - } - - /* disable interrupts - * Note that acpi_suspend -- our caller -- will do this once we return. - * But, we want it done early, so we don't get any suprises during - * the device suspend sequence. - */ - ACPI_DISABLE_IRQS(); - - /* Unconditionally turn off devices. - * Obvious if we enter a sleep state. - * If entering S5 (soft off), this should put devices in a - * quiescent state. - */ - error = device_suspend(state, SUSPEND_POWER_DOWN); - - /* We're pretty screwed if we got an error from this. - * We try to recover by simply calling our own restore_state - * function; see above for definition. - * - * If it's S5 though, go through with it anyway.. - */ - if (error && state != ACPI_STATE_S5) - acpi_system_restore_state(state); - - return error ? AE_ERROR : AE_OK; -} - - -/**************************************************************************** - * - * FUNCTION: acpi_system_suspend - * - * PARAMETERS: %state: Sleep state to enter. - * - * RETURN: acpi_status, whether or not we successfully entered and - * exited sleep. - * - * DESCRIPTION: Perform OS-specific action to enter sleep state. - * This is the final step in going to sleep, per spec. If we - * know we're coming back (i.e. not entering S5), we save the - * processor flags. [ We'll have to save and restore them anyway, - * so we use the arch-agnostic save_flags and restore_flags - * here.] We then set the place to return to in arch-specific - * globals using arch_set_return_point. Finally, we call the - * ACPI function to write the proper values to I/O ports. - * - ****************************************************************************/ - -acpi_status -acpi_system_suspend( - u32 state) -{ - acpi_status status = AE_ERROR; - unsigned long flags = 0; - - local_irq_save(flags); - - switch (state) - { - case ACPI_STATE_S1: - barrier(); - status = acpi_enter_sleep_state(state); - break; - - case ACPI_STATE_S2: - case ACPI_STATE_S3: - do_suspend_lowlevel(0); - break; - } - local_irq_restore(flags); - - return status; -} - - -/** - * acpi_suspend - OS-agnostic system suspend/resume support (S? states) - * @state: state we're entering - * - */ -acpi_status -acpi_suspend ( - u32 state) -{ - acpi_status status; - - /* get out if state is invalid */ - if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5) - return AE_ERROR; - - freeze_processes(); /* device_suspend needs processes to be stopped */ - - /* do we have a wakeup address for S2 and S3? */ - if (state == ACPI_STATE_S2 || state == ACPI_STATE_S3) { - if (!acpi_wakeup_address) - return AE_ERROR; - acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) acpi_wakeup_address); - } - - acpi_enter_sleep_state_prep(state); - - status = acpi_system_save_state(state); - if (!ACPI_SUCCESS(status)) - return status; - - /* disable interrupts and flush caches */ - ACPI_DISABLE_IRQS(); - ACPI_FLUSH_CPU_CACHE(); - - /* perform OS-specific sleep actions */ - status = acpi_system_suspend(state); - - /* Even if we failed to go to sleep, all of the devices are in an suspended - * mode. So, we run these unconditionaly to make sure we have a usable system - * no matter what. - */ - acpi_system_restore_state(state); - acpi_leave_sleep_state(state); - - /* make sure interrupts are enabled */ - ACPI_ENABLE_IRQS(); - - /* reset firmware waking vector */ - acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) 0); - thaw_processes(); - - return status; -} - -#endif /* CONFIG_ACPI_SLEEP */ - - /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ @@ -344,25 +56,16 @@ int *eof, void *data) { - struct acpi_system *system = (struct acpi_system *) data; char *p = page; int size = 0; - u32 i = 0; ACPI_FUNCTION_TRACE("acpi_system_read_info"); - if (!system || (off != 0)) + if (off != 0) goto end; p += sprintf(p, "version: %x\n", ACPI_CA_VERSION); - p += sprintf(p, "states: "); - for (i=0; istates[i]) - p += sprintf(p, "S%d ", i); - } - p += sprintf(p, "\n"); - end: size = (p - page); if (size <= off+count) *eof = 1; @@ -374,106 +77,6 @@ return_VALUE(size); } -static int acpi_system_open_event(struct inode *inode, struct file *file); -static ssize_t acpi_system_read_event (struct file*, char*, size_t, loff_t*); -static int acpi_system_close_event(struct inode *inode, struct file *file); -static unsigned int acpi_system_poll_event(struct file *file, poll_table *wait); - - -static struct file_operations acpi_system_event_ops = { - .open = acpi_system_open_event, - .read = acpi_system_read_event, - .release = acpi_system_close_event, - .poll = acpi_system_poll_event, -}; - -static int -acpi_system_open_event(struct inode *inode, struct file *file) -{ - spin_lock_irq (&acpi_system_event_lock); - - if(event_is_open) - goto out_busy; - - event_is_open = 1; - - spin_unlock_irq (&acpi_system_event_lock); - return 0; - -out_busy: - spin_unlock_irq (&acpi_system_event_lock); - return -EBUSY; -} - -static ssize_t -acpi_system_read_event ( - struct file *file, - char *buffer, - size_t count, - loff_t *ppos) -{ - int result = 0; - struct acpi_bus_event event; - static char str[ACPI_MAX_STRING]; - static int chars_remaining = 0; - static char *ptr; - - - ACPI_FUNCTION_TRACE("acpi_system_read_event"); - - if (!chars_remaining) { - memset(&event, 0, sizeof(struct acpi_bus_event)); - - if ((file->f_flags & O_NONBLOCK) - && (list_empty(&acpi_bus_event_list))) - return_VALUE(-EAGAIN); - - result = acpi_bus_receive_event(&event); - if (result) { - return_VALUE(-EIO); - } - - chars_remaining = sprintf(str, "%s %s %08x %08x\n", - event.device_class?event.device_class:"", - event.bus_id?event.bus_id:"", - event.type, event.data); - ptr = str; - } - - if (chars_remaining < count) { - count = chars_remaining; - } - - if (copy_to_user(buffer, ptr, count)) - return_VALUE(-EFAULT); - - *ppos += count; - chars_remaining -= count; - ptr += count; - - return_VALUE(count); -} - -static int -acpi_system_close_event(struct inode *inode, struct file *file) -{ - spin_lock_irq (&acpi_system_event_lock); - event_is_open = 0; - spin_unlock_irq (&acpi_system_event_lock); - return 0; -} - -static unsigned int -acpi_system_poll_event( - struct file *file, - poll_table *wait) -{ - poll_wait(file, &acpi_bus_event_queue, wait); - if (!list_empty(&acpi_bus_event_list)) - return POLLIN | POLLRDNORM; - return 0; -} - static ssize_t acpi_system_read_dsdt (struct file*, char*, size_t, loff_t*); static struct file_operations acpi_system_dsdt_ops = { @@ -560,732 +163,54 @@ } -#ifdef ACPI_DEBUG - -static int -acpi_system_read_debug ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *data) -{ - char *p = page; - int size = 0; - - if (off != 0) - goto end; - - switch ((unsigned long) data) { - case 0: - p += sprintf(p, "0x%08x\n", acpi_dbg_layer); - break; - case 1: - p += sprintf(p, "0x%08x\n", acpi_dbg_level); - break; - default: - p += sprintf(p, "Invalid debug option\n"); - break; - } - -end: - size = (p - page); - if (size <= off+count) *eof = 1; - *start = page + off; - size -= off; - if (size>count) size = count; - if (size<0) size = 0; - - return size; -} - - -static int -acpi_system_write_debug ( - struct file *file, - const char *buffer, - unsigned long count, - void *data) -{ - char debug_string[12] = {'\0'}; - - ACPI_FUNCTION_TRACE("acpi_system_write_debug"); - - if (count > sizeof(debug_string) - 1) - return_VALUE(-EINVAL); - - if (copy_from_user(debug_string, buffer, count)) - return_VALUE(-EFAULT); - - debug_string[count] = '\0'; - - switch ((unsigned long) data) { - case 0: - acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0); - break; - case 1: - acpi_dbg_level = simple_strtoul(debug_string, NULL, 0); - break; - default: - return_VALUE(-EINVAL); - } - - return_VALUE(count); -} - -#endif /* ACPI_DEBUG */ - - -#ifdef CONFIG_ACPI_SLEEP - -static int -acpi_system_read_sleep ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *data) -{ - struct acpi_system *system = (struct acpi_system *) data; - char *p = page; - int size; - int i; - - ACPI_FUNCTION_TRACE("acpi_system_read_sleep"); - - if (!system || (off != 0)) - goto end; - - for (i = 0; i <= ACPI_STATE_S5; i++) { - if (system->states[i]) - p += sprintf(p,"S%d ", i); - } - - p += sprintf(p, "\n"); - -end: - size = (p - page); - if (size <= off+count) *eof = 1; - *start = page + off; - size -= off; - if (size>count) size = count; - if (size<0) size = 0; - - return_VALUE(size); -} - - -static int -acpi_system_write_sleep ( - struct file *file, - const char *buffer, - unsigned long count, - void *data) -{ - acpi_status status = AE_OK; - struct acpi_system *system = (struct acpi_system *) data; - char state_string[12] = {'\0'}; - u32 state = 0; - - ACPI_FUNCTION_TRACE("acpi_system_write_sleep"); - - if (!system || (count > sizeof(state_string) - 1)) - return_VALUE(-EINVAL); - - if (copy_from_user(state_string, buffer, count)) - return_VALUE(-EFAULT); - - state_string[count] = '\0'; - - state = simple_strtoul(state_string, NULL, 0); - - if (!system->states[state]) - return_VALUE(-ENODEV); - - -#ifdef CONFIG_SOFTWARE_SUSPEND - if (state == 4) { - software_suspend(); - return_VALUE(count); - } -#endif - status = acpi_suspend(state); - - if (ACPI_FAILURE(status)) - return_VALUE(-ENODEV); - - return_VALUE(count); -} - - -static int -acpi_system_read_alarm ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - char *p = page; - int size = 0; - u32 sec, min, hr; - u32 day, mo, yr; - - ACPI_FUNCTION_TRACE("acpi_system_read_alarm"); - - if (off != 0) - goto end; - - spin_lock(&rtc_lock); - - sec = CMOS_READ(RTC_SECONDS_ALARM); - min = CMOS_READ(RTC_MINUTES_ALARM); - hr = CMOS_READ(RTC_HOURS_ALARM); - -#if 0 /* If we ever get an FACP with proper values... */ - if (acpi_gbl_FADT->day_alrm) - day = CMOS_READ(acpi_gbl_FADT->day_alrm); - else - day = CMOS_READ(RTC_DAY_OF_MONTH); - if (acpi_gbl_FADT->mon_alrm) - mo = CMOS_READ(acpi_gbl_FADT->mon_alrm); - else - mo = CMOS_READ(RTC_MONTH);; - if (acpi_gbl_FADT->century) - yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR); - else - yr = CMOS_READ(RTC_YEAR); -#else - day = CMOS_READ(RTC_DAY_OF_MONTH); - mo = CMOS_READ(RTC_MONTH); - yr = CMOS_READ(RTC_YEAR); -#endif - - spin_unlock(&rtc_lock); - - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hr); - BCD_TO_BIN(day); - BCD_TO_BIN(mo); - BCD_TO_BIN(yr); - -#if 0 - /* we're trusting the FADT (see above)*/ -#else - /* If we're not trusting the FADT, we should at least make it - * right for _this_ century... ehm, what is _this_ century? - * - * TBD: - * ASAP: find piece of code in the kernel, e.g. star tracker driver, - * which we can trust to determine the century correctly. Atom - * watch driver would be nice, too... - * - * if that has not happened, change for first release in 2050: - * if (yr<50) - * yr += 2100; - * else - * yr += 2000; // current line of code - * - * if that has not happened either, please do on 2099/12/31:23:59:59 - * s/2000/2100 - * - */ - yr += 2000; -#endif - - p += sprintf(p,"%4.4u-", yr); - p += (mo > 12) ? sprintf(p, "**-") : sprintf(p, "%2.2u-", mo); - p += (day > 31) ? sprintf(p, "** ") : sprintf(p, "%2.2u ", day); - p += (hr > 23) ? sprintf(p, "**:") : sprintf(p, "%2.2u:", hr); - p += (min > 59) ? sprintf(p, "**:") : sprintf(p, "%2.2u:", min); - p += (sec > 59) ? sprintf(p, "**\n") : sprintf(p, "%2.2u\n", sec); - - end: - size = p - page; - if (size < count) *eof = 1; - else if (size > count) size = count; - if (size < 0) size = 0; - *start = page; - - return_VALUE(size); -} - - -static int -get_date_field ( - char **p, - u32 *value) -{ - char *next = NULL; - char *string_end = NULL; - int result = -EINVAL; - - /* - * Try to find delimeter, only to insert null. The end of the - * string won't have one, but is still valid. - */ - next = strpbrk(*p, "- :"); - if (next) - *next++ = '\0'; - - *value = simple_strtoul(*p, &string_end, 10); - - /* Signal success if we got a good digit */ - if (string_end != *p) - result = 0; - - if (next) - *p = next; - - return result; -} - - -static int -acpi_system_write_alarm ( - struct file *file, - const char *buffer, - unsigned long count, - void *data) -{ - int result = 0; - char alarm_string[30] = {'\0'}; - char *p = alarm_string; - u32 sec, min, hr, day, mo, yr; - int adjust = 0; - unsigned char rtc_control = 0; - - ACPI_FUNCTION_TRACE("acpi_system_write_alarm"); - - if (count > sizeof(alarm_string) - 1) - return_VALUE(-EINVAL); - - if (copy_from_user(alarm_string, buffer, count)) - return_VALUE(-EFAULT); - - alarm_string[count] = '\0'; - - /* check for time adjustment */ - if (alarm_string[0] == '+') { - p++; - adjust = 1; - } - - if ((result = get_date_field(&p, &yr))) - goto end; - if ((result = get_date_field(&p, &mo))) - goto end; - if ((result = get_date_field(&p, &day))) - goto end; - if ((result = get_date_field(&p, &hr))) - goto end; - if ((result = get_date_field(&p, &min))) - goto end; - if ((result = get_date_field(&p, &sec))) - goto end; - - if (sec > 59) { - min += 1; - sec -= 60; - } - if (min > 59) { - hr += 1; - min -= 60; - } - if (hr > 23) { - day += 1; - hr -= 24; - } - if (day > 31) { - mo += 1; - day -= 31; - } - if (mo > 12) { - yr += 1; - mo -= 12; - } - - spin_lock_irq(&rtc_lock); - - rtc_control = CMOS_READ(RTC_CONTROL); - if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(yr); - BIN_TO_BCD(mo); - BIN_TO_BCD(day); - BIN_TO_BCD(hr); - BIN_TO_BCD(min); - BIN_TO_BCD(sec); - } - - if (adjust) { - yr += CMOS_READ(RTC_YEAR); - mo += CMOS_READ(RTC_MONTH); - day += CMOS_READ(RTC_DAY_OF_MONTH); - hr += CMOS_READ(RTC_HOURS); - min += CMOS_READ(RTC_MINUTES); - sec += CMOS_READ(RTC_SECONDS); - } - - spin_unlock_irq(&rtc_lock); - - if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BCD_TO_BIN(yr); - BCD_TO_BIN(mo); - BCD_TO_BIN(day); - BCD_TO_BIN(hr); - BCD_TO_BIN(min); - BCD_TO_BIN(sec); - } - - if (sec > 59) { - min++; - sec -= 60; - } - if (min > 59) { - hr++; - min -= 60; - } - if (hr > 23) { - day++; - hr -= 24; - } - if (day > 31) { - mo++; - day -= 31; - } - if (mo > 12) { - yr++; - mo -= 12; - } - if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(yr); - BIN_TO_BCD(mo); - BIN_TO_BCD(day); - BIN_TO_BCD(hr); - BIN_TO_BCD(min); - BIN_TO_BCD(sec); - } - - spin_lock_irq(&rtc_lock); - - /* write the fields the rtc knows about */ - CMOS_WRITE(hr, RTC_HOURS_ALARM); - CMOS_WRITE(min, RTC_MINUTES_ALARM); - CMOS_WRITE(sec, RTC_SECONDS_ALARM); - - /* - * If the system supports an enhanced alarm it will have non-zero - * offsets into the CMOS RAM here -- which for some reason are pointing - * to the RTC area of memory. - */ -#if 0 - if (acpi_gbl_FADT->day_alrm) - CMOS_WRITE(day, acpi_gbl_FADT->day_alrm); - if (acpi_gbl_FADT->mon_alrm) - CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm); - if (acpi_gbl_FADT->century) - CMOS_WRITE(yr/100, acpi_gbl_FADT->century); -#endif - /* enable the rtc alarm interrupt */ - if (!(rtc_control & RTC_AIE)) { - rtc_control |= RTC_AIE; - CMOS_WRITE(rtc_control,RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - } - - spin_unlock_irq(&rtc_lock); - - acpi_set_register(ACPI_BITREG_RT_CLOCK_ENABLE, 1, ACPI_MTX_LOCK); - - file->f_pos += count; - - result = 0; -end: - return_VALUE(result ? result : count); -} - -#endif /*CONFIG_ACPI_SLEEP*/ - - -static int -acpi_system_add_fs ( - struct acpi_device *device) +static int __init acpi_system_init (void) { - struct proc_dir_entry *entry = NULL; + struct proc_dir_entry *entry; + int error = 0; + char * name; - ACPI_FUNCTION_TRACE("acpi_system_add_fs"); + ACPI_FUNCTION_TRACE("acpi_system_init"); - if (!device) - return_VALUE(-EINVAL); + if (acpi_disabled) + return_VALUE(0); /* 'info' [R] */ - entry = create_proc_entry(ACPI_SYSTEM_FILE_INFO, - S_IRUGO, acpi_device_dir(device)); + name = ACPI_SYSTEM_FILE_INFO; + entry = create_proc_read_entry(name, + S_IRUGO, acpi_root_dir, acpi_system_read_info,NULL); if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_SYSTEM_FILE_INFO)); - else { - entry->read_proc = acpi_system_read_info; - entry->data = acpi_driver_data(device); - } + goto Error; /* 'dsdt' [R] */ - entry = create_proc_entry(ACPI_SYSTEM_FILE_DSDT, - S_IRUSR, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_SYSTEM_FILE_DSDT)); - else + name = ACPI_SYSTEM_FILE_DSDT; + entry = create_proc_entry(name, S_IRUSR, acpi_root_dir); + if (entry) entry->proc_fops = &acpi_system_dsdt_ops; + else + goto Error; /* 'fadt' [R] */ - entry = create_proc_entry(ACPI_SYSTEM_FILE_FADT, - S_IRUSR, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_SYSTEM_FILE_FADT)); - else + name = ACPI_SYSTEM_FILE_FADT; + entry = create_proc_entry(name, S_IRUSR, acpi_root_dir); + if (entry) entry->proc_fops = &acpi_system_fadt_ops; - - /* 'event' [R] */ - entry = create_proc_entry(ACPI_SYSTEM_FILE_EVENT, - S_IRUSR, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_SYSTEM_FILE_EVENT)); else - entry->proc_fops = &acpi_system_event_ops; + goto Error; -#ifdef CONFIG_ACPI_SLEEP + Done: + return_VALUE(error); - /* 'sleep' [R/W]*/ - entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP, - S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_SYSTEM_FILE_SLEEP)); - else { - entry->read_proc = acpi_system_read_sleep; - entry->write_proc = acpi_system_write_sleep; - entry->data = acpi_driver_data(device); - } + Error: + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' proc fs entry\n", name)); - /* 'alarm' [R/W] */ - entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM, - S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_SYSTEM_FILE_ALARM)); - else { - entry->read_proc = acpi_system_read_alarm; - entry->write_proc = acpi_system_write_alarm; - entry->data = acpi_driver_data(device); - } + remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir); + remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir); + remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir); -#endif /*CONFIG_ACPI_SLEEP*/ - -#ifdef ACPI_DEBUG - - /* 'debug_layer' [R/W] */ - entry = create_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, - S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_SYSTEM_FILE_DEBUG_LAYER)); - else { - entry->read_proc = acpi_system_read_debug; - entry->write_proc = acpi_system_write_debug; - entry->data = (void *) 0; - } - - /* 'debug_level' [R/W] */ - entry = create_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, - S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_SYSTEM_FILE_DEBUG_LEVEL)); - else { - entry->read_proc = acpi_system_read_debug; - entry->write_proc = acpi_system_write_debug; - entry->data = (void *) 1; - } - -#endif /*ACPI_DEBUG*/ - - return_VALUE(0); + error = -EFAULT; + goto Done; } -static int -acpi_system_remove_fs ( - struct acpi_device *device) -{ - ACPI_FUNCTION_TRACE("acpi_system_remove_fs"); - - if (!device) - return_VALUE(-EINVAL); - - remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_device_dir(device)); - remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_device_dir(device)); - remove_proc_entry(ACPI_SYSTEM_FILE_EVENT, acpi_device_dir(device)); -#ifdef CONFIG_ACPI_SLEEP - remove_proc_entry(ACPI_SYSTEM_FILE_SLEEP, acpi_device_dir(device)); - remove_proc_entry(ACPI_SYSTEM_FILE_ALARM, acpi_device_dir(device)); -#endif -#ifdef ACPI_DEBUG - remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, - acpi_device_dir(device)); - remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, - acpi_device_dir(device)); -#endif - - return_VALUE(0); -} - - -/* -------------------------------------------------------------------------- - Driver Interface - -------------------------------------------------------------------------- */ - -#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_PM) - -/* Simple wrapper calling power down function. */ -static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) -{ - acpi_power_off(); -} - -struct sysrq_key_op sysrq_acpi_poweroff_op = { - .handler = &acpi_sysrq_power_off, - .help_msg = "Off", - .action_msg = "Power Off\n" -}; - -#endif /* CONFIG_MAGIC_SYSRQ */ - -static int -acpi_system_add ( - struct acpi_device *device) -{ - int result = 0; - acpi_status status = AE_OK; - struct acpi_system *system = NULL; - u8 i = 0; - - ACPI_FUNCTION_TRACE("acpi_system_add"); - - if (!device) - return_VALUE(-EINVAL); - - system = kmalloc(sizeof(struct acpi_system), GFP_KERNEL); - if (!system) - return_VALUE(-ENOMEM); - memset(system, 0, sizeof(struct acpi_system)); - - system->handle = device->handle; - sprintf(acpi_device_name(device), "%s", ACPI_SYSTEM_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_SYSTEM_CLASS); - acpi_driver_data(device) = system; - - result = acpi_system_add_fs(device); - if (result) - goto end; - - printk(KERN_INFO PREFIX "%s [%s] (supports", - acpi_device_name(device), acpi_device_bid(device)); - for (i=0; istates[i] = 1; - printk(" S%d", i); - } - } - printk(")\n"); - -#ifdef CONFIG_PM - /* Install the soft-off (S5) handler. */ - if (system->states[ACPI_STATE_S5]) { - pm_power_off = acpi_power_off; - register_sysrq_key('o', &sysrq_acpi_poweroff_op); - - /* workaround: some systems don't claim S4 support, but they - do support S5 (power-down). That is all we need, so - indicate support. */ - system->states[ACPI_STATE_S4] = 1; - } -#endif - -end: - if (result) - kfree(system); - - return_VALUE(result); -} - - -static int -acpi_system_remove ( - struct acpi_device *device, - int type) -{ - struct acpi_system *system = NULL; - - ACPI_FUNCTION_TRACE("acpi_system_remove"); - - if (!device || !acpi_driver_data(device)) - return_VALUE(-EINVAL); - - system = (struct acpi_system *) acpi_driver_data(device); - -#ifdef CONFIG_PM - /* Remove the soft-off (S5) handler. */ - if (system->states[ACPI_STATE_S5]) { - unregister_sysrq_key('o', &sysrq_acpi_poweroff_op); - pm_power_off = NULL; - } -#endif - - acpi_system_remove_fs(device); - - kfree(system); - - return 0; -} - - -int __init -acpi_system_init (void) -{ - int result = 0; - - ACPI_FUNCTION_TRACE("acpi_system_init"); - - result = acpi_bus_register_driver(&acpi_system_driver); - if (result < 0) - return_VALUE(-ENODEV); - - return_VALUE(0); -} - - -void __exit -acpi_system_exit (void) -{ - ACPI_FUNCTION_TRACE("acpi_system_exit"); - acpi_bus_unregister_driver(&acpi_system_driver); - return_VOID; -} +subsys_initcall(acpi_system_init); diff -Nru a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c --- a/drivers/acpi/tables/tbget.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/tables/tbget.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: tbget - ACPI Table get* routines - * $Revision: 79 $ + * $Revision: 80 $ * *****************************************************************************/ @@ -129,8 +129,10 @@ status = acpi_os_map_memory (address->pointer.physical, sizeof (acpi_table_header), (void **) &header); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("Could not map memory at %p for length %X\n", - address->pointer.physical, sizeof (acpi_table_header))); + ACPI_REPORT_ERROR (("Could not map memory at %8.8X%8.8X for length %X\n", + ACPI_HIDWORD (address->pointer.physical), + ACPI_LODWORD (address->pointer.physical), + sizeof (acpi_table_header))); return_ACPI_STATUS (status); } @@ -343,8 +345,10 @@ status = acpi_os_map_memory (address->pointer.physical, (ACPI_SIZE) header->length, (void **) &full_table); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %p for length %X\n", - header->signature, address->pointer.physical, header->length)); + ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n", + header->signature, + ACPI_HIDWORD (address->pointer.physical), + ACPI_LODWORD (address->pointer.physical), header->length)); return (status); } diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c --- a/drivers/acpi/tables.c Fri Sep 20 08:20:44 2002 +++ b/drivers/acpi/tables.c Fri Sep 20 08:20:44 2002 @@ -46,7 +46,7 @@ [ACPI_DSDT] = "DSDT", [ACPI_ECDT] = "ECDT", [ACPI_ETDT] = "ETDT", - [ACPI_FACP] = "FACP", + [ACPI_FADT] = "FACP", [ACPI_FACS] = "FACS", [ACPI_OEMX] = "OEM", [ACPI_PSDT] = "PSDT", @@ -71,9 +71,6 @@ static struct acpi_table_sdt sdt; -acpi_madt_entry_handler madt_handlers[ACPI_MADT_ENTRY_COUNT]; - - void acpi_table_print ( struct acpi_table_header *header, @@ -92,7 +89,7 @@ name = "MADT"; } else if (!strncmp((char *) &header->signature, - acpi_table_signatures[ACPI_FACP], + acpi_table_signatures[ACPI_FADT], sizeof(header->signature))) { name = "FADT"; } @@ -222,6 +219,56 @@ return (sum & 0xFF); } +int __init +acpi_get_table_header_early ( + enum acpi_table_id id, + struct acpi_table_header **header) +{ + int i; + enum acpi_table_id temp_id; + + /* DSDT is different from the rest */ + if (id == ACPI_DSDT) + temp_id = ACPI_FADT; + else + temp_id = id; + + /* Locate the table. */ + + for (i = 0; i < sdt.count; i++) { + if (sdt.entry[i].id != temp_id) + continue; + *header = (void *) + __acpi_map_table(sdt.entry[i].pa, sdt.entry[i].size); + if (!*header) { + printk(KERN_WARNING PREFIX "Unable to map %s\n", + acpi_table_signatures[temp_id]); + return -ENODEV; + } + break; + } + + if (!*header) { + printk(KERN_WARNING PREFIX "%s not present\n", + acpi_table_signatures[id]); + return -ENODEV; + } + + /* Map the DSDT header via the pointer in the FADT */ + if (id == ACPI_DSDT) { + struct acpi_table_fadt *fadt = (struct acpi_table_fadt *) *header; + + *header = (void *) __acpi_map_table(fadt->dsdt_addr, + sizeof(struct acpi_table_header)); + if (!*header) { + printk(KERN_WARNING PREFIX "Unable to map DSDT\n"); + return -ENODEV; + } + } + + return 0; +} + int __init acpi_table_parse_madt_family ( @@ -447,6 +494,15 @@ } } + /* + * The DSDT is *not* in the RSDT (why not? no idea.) but we want + * to print its info, because this is what people usually blacklist + * against. Unfortunately, we don't know the phys_addr, so just + * print 0. Maybe no one will notice. + */ + if(!acpi_get_table_header_early(ACPI_DSDT, &header)) + acpi_table_print(header, 0); + return 0; } @@ -460,7 +516,6 @@ int result = 0; memset(&sdt, 0, sizeof(struct acpi_table_sdt)); - memset(&madt_handlers, 0, sizeof(madt_handlers)); /* Locate and map the Root System Description Table (RSDP) */ diff -Nru a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c --- a/drivers/acpi/thermal.c Fri Sep 20 08:20:44 2002 +++ b/drivers/acpi/thermal.c Fri Sep 20 08:20:44 2002 @@ -54,8 +54,23 @@ MODULE_PARM(tzp, "i"); MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n"); -#define PREFIX "ACPI: " - +#define ACPI_THERMAL_COMPONENT 0x04000000 +#define ACPI_THERMAL_CLASS "thermal_zone" +#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver" +#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" +#define ACPI_THERMAL_FILE_STATE "state" +#define ACPI_THERMAL_FILE_TEMPERATURE "temperature" +#define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points" +#define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode" +#define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency" +#define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80 +#define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81 +#define ACPI_THERMAL_NOTIFY_DEVICES 0x82 +#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0 +#define ACPI_THERMAL_NOTIFY_HOT 0xF1 +#define ACPI_THERMAL_MODE_ACTIVE 0x00 +#define ACPI_THERMAL_MODE_PASSIVE 0x01 +#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff" #define ACPI_THERMAL_MAX_ACTIVE 10 diff -Nru a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c --- a/drivers/acpi/utilities/utcopy.c Fri Sep 20 08:20:45 2002 +++ b/drivers/acpi/utilities/utcopy.c Fri Sep 20 08:20:45 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: utcopy - Internal to external object translation utilities - * $Revision: 103 $ + * $Revision: 104 $ * *****************************************************************************/ @@ -25,7 +25,6 @@ #include "acpi.h" -#include "acnamesp.h" #include "amlcode.h" diff -Nru a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c --- a/drivers/acpi/utilities/utdebug.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/utilities/utdebug.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: utdebug - Debug print routines - * $Revision: 104 $ + * $Revision: 105 $ * *****************************************************************************/ @@ -152,7 +152,7 @@ acpi_os_printf ("%8s-%04ld ", dbg_info->module_name, line_number); if (ACPI_LV_THREADS & acpi_dbg_level) { - acpi_os_printf ("[%04lX] ", thread_id, acpi_gbl_nesting_level, dbg_info->proc_name); + acpi_os_printf ("[%04lX] ", thread_id); } acpi_os_printf ("[%02ld] %-22.22s: ", acpi_gbl_nesting_level, dbg_info->proc_name); @@ -516,7 +516,7 @@ while (i < count) { /* Print current offset */ - acpi_os_printf ("%05X ", i); + acpi_os_printf ("%05X ", (u32) i); /* Print 16 hex chars */ diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c --- a/drivers/acpi/utilities/utglobal.c Fri Sep 20 08:20:42 2002 +++ b/drivers/acpi/utilities/utglobal.c Fri Sep 20 08:20:42 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: utglobal - Global variables for the ACPI subsystem - * $Revision: 170 $ + * $Revision: 171 $ * *****************************************************************************/ @@ -27,7 +27,6 @@ #include "acpi.h" #include "acnamesp.h" -#include "amlcode.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utglobal") diff -Nru a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c --- a/drivers/acpi/utilities/utinit.c Fri Sep 20 08:20:47 2002 +++ b/drivers/acpi/utilities/utinit.c Fri Sep 20 08:20:47 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: utinit - Common ACPI subsystem initialization - * $Revision: 113 $ + * $Revision: 114 $ * *****************************************************************************/ @@ -56,7 +56,7 @@ ACPI_REPORT_WARNING ( ("Invalid FADT value %s=%X at offset %X FADT=%p\n", - register_name, value, offset, acpi_gbl_FADT)); + register_name, value, (u32) offset, acpi_gbl_FADT)); } diff -Nru a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c --- a/drivers/acpi/utilities/utmisc.c Fri Sep 20 08:20:41 2002 +++ b/drivers/acpi/utilities/utmisc.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,7 @@ /******************************************************************************* * * Module Name: utmisc - common utility procedures - * $Revision: 80 $ + * $Revision: 81 $ * ******************************************************************************/ @@ -26,8 +26,6 @@ #include "acpi.h" #include "acnamesp.h" -#include "amlcode.h" -#include "acinterp.h" #define _COMPONENT ACPI_UTILITIES diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile --- a/drivers/base/Makefile Fri Sep 20 08:20:44 2002 +++ b/drivers/base/Makefile Fri Sep 20 08:20:44 2002 @@ -1,7 +1,7 @@ # Makefile for the Linux device tree obj-y := core.o sys.o interface.o power.o bus.o \ - driver.o class.o intf.o + driver.o class.o intf.o platform.o obj-y += fs/ diff -Nru a/drivers/base/core.c b/drivers/base/core.c --- a/drivers/base/core.c Fri Sep 20 08:20:41 2002 +++ b/drivers/base/core.c Fri Sep 20 08:20:41 2002 @@ -97,15 +97,10 @@ static void device_detach(struct device * dev) { - struct device_driver * drv; + struct device_driver * drv = dev->driver; - if (dev->driver) { + if (drv) { devclass_remove_device(dev); - spin_lock(&device_lock); - drv = dev->driver; - spin_unlock(&device_lock); - - /* detach from driver */ if (drv && drv->remove) drv->remove(dev); diff -Nru a/drivers/base/platform.c b/drivers/base/platform.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/base/platform.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,27 @@ +/* + * platform.c - platform 'psuedo' bus for legacy devices + * + * Please see Documentation/driver-model/platform.txt for more + * information. + */ + +#include +#include +#include + +static int platform_match(struct device * dev, struct device_driver * drv) +{ + return 0; +} + +struct bus_type platform_bus = { + .name = "platform", + .match = platform_match, +}; + +static int __init platform_bus_init(void) +{ + return bus_register(&platform_bus); +} + +postcore_initcall(platform_bus_init); diff -Nru a/drivers/base/power.c b/drivers/base/power.c --- a/drivers/base/power.c Fri Sep 20 08:20:41 2002 +++ b/drivers/base/power.c Fri Sep 20 08:20:41 2002 @@ -92,13 +92,13 @@ */ void device_shutdown(void) { - struct list_head * node; + struct list_head * node, * next; struct device * prev = NULL; printk(KERN_EMERG "Shutting down devices\n"); spin_lock(&device_lock); - list_for_each(node,&global_device_list) { + list_for_each_safe(node,next,&global_device_list) { struct device * dev = get_device_locked(to_dev(node)); if (dev) { spin_unlock(&device_lock); @@ -111,6 +111,8 @@ } } spin_unlock(&device_lock); + if (prev) + put_device(prev); } EXPORT_SYMBOL(device_suspend); diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c --- a/drivers/block/DAC960.c Fri Sep 20 08:20:47 2002 +++ b/drivers/block/DAC960.c Fri Sep 20 08:20:47 2002 @@ -2909,10 +2909,8 @@ static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader, boolean SuccessfulIO) { - if (SuccessfulIO) - set_bit(BIO_UPTODATE, &BufferHeader->bi_flags); + bio_endio(BufferHeader, BufferHeader->bi_size, SuccessfulIO ? 0 : -EIO); blk_finished_io(bio_sectors(BufferHeader)); - BufferHeader->bi_end_io(BufferHeader); } static inline int DAC960_PartitionByCommand(DAC960_Command_T *Command) diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c --- a/drivers/block/cciss.c Fri Sep 20 08:20:48 2002 +++ b/drivers/block/cciss.c Fri Sep 20 08:20:48 2002 @@ -1567,10 +1567,11 @@ { while (bio) { struct bio *xbh = bio->bi_next; + int nr_sectors = bio_sectors(bio); bio->bi_next = NULL; - blk_finished_io(bio_sectors(bio)); - bio_endio(bio, status); + blk_finished_io(len); + bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); bio = xbh; } diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c --- a/drivers/block/cpqarray.c Fri Sep 20 08:20:42 2002 +++ b/drivers/block/cpqarray.c Fri Sep 20 08:20:42 2002 @@ -911,11 +911,13 @@ { struct bio *xbh; while(bio) { + int nr_sectors = bio_sectors(bio); + xbh = bio->bi_next; bio->bi_next = NULL; - blk_finished_io(bio_sectors(bio)); - bio_endio(bio, ok); + blk_finished_io(nr_sectors); + bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO); bio = xbh; } diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c --- a/drivers/block/floppy.c Fri Sep 20 08:20:43 2002 +++ b/drivers/block/floppy.c Fri Sep 20 08:20:43 2002 @@ -3846,9 +3846,13 @@ * a disk in the drive, and whether that disk is writable. */ -static void floppy_rb0_complete(struct bio *bio) +static int floppy_rb0_complete(struct bio *bio, unsigned int bytes_done, int err) { + if (bio->bi_size) + return 1; + complete((struct completion*)bio->bi_private); + return 0; } static int __floppy_read_block_0(struct block_device *bdev) diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Fri Sep 20 08:20:41 2002 +++ b/drivers/block/ll_rw_blk.c Fri Sep 20 08:20:41 2002 @@ -12,38 +12,21 @@ /* * This handles all read/write requests to block devices */ -#include -#include -#include -#include -#include #include +#include +#include +#include #include +#include +#include #include -#include +#include +#include #include -#include -#include +#include /* for max_pfn/max_low_pfn */ #include -#include -#include -#include -#include - -#include -#include -#include -#include #include -#include - -/* - * MAC Floppy IWM hooks - */ -#ifdef CONFIG_MAC_FLOPPY_IWM -extern int mac_floppy_init(void); -#endif /* * For the allocated request tables @@ -53,7 +36,7 @@ /* * plug management */ -static struct list_head blk_plug_list; +static LIST_HEAD(blk_plug_list); static spinlock_t blk_plug_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; /* blk_dev_struct is: @@ -221,6 +204,11 @@ **/ void blk_queue_max_sectors(request_queue_t *q, unsigned short max_sectors) { + if ((max_sectors << 9) < PAGE_CACHE_SIZE) { + max_sectors = 1 << (PAGE_CACHE_SHIFT - 9); + printk("%s: set to minimum %d\n", __FUNCTION__, max_sectors); + } + q->max_sectors = max_sectors; } @@ -236,6 +224,11 @@ **/ void blk_queue_max_phys_segments(request_queue_t *q, unsigned short max_segments) { + if (!max_segments) { + max_segments = 1; + printk("%s: set to minimum %d\n", __FUNCTION__, max_segments); + } + q->max_phys_segments = max_segments; } @@ -252,6 +245,11 @@ **/ void blk_queue_max_hw_segments(request_queue_t *q, unsigned short max_segments) { + if (!max_segments) { + max_segments = 1; + printk("%s: set to minimum %d\n", __FUNCTION__, max_segments); + } + q->max_hw_segments = max_segments; } @@ -266,6 +264,11 @@ **/ void blk_queue_max_segment_size(request_queue_t *q, unsigned int max_size) { + if (max_size < PAGE_CACHE_SIZE) { + max_size = PAGE_CACHE_SIZE; + printk("%s: set to minimum %d\n", __FUNCTION__, max_size); + } + q->max_segment_size = max_size; } @@ -292,6 +295,11 @@ **/ void blk_queue_segment_boundary(request_queue_t *q, unsigned long mask) { + if (mask < PAGE_CACHE_SIZE - 1) { + mask = PAGE_CACHE_SIZE - 1; + printk("%s: set to minimum %lx\n", __FUNCTION__, mask); + } + q->seg_boundary_mask = mask; } @@ -1568,10 +1576,8 @@ /* * READA bit set */ - if (bio->bi_rw & (1 << BIO_RW_AHEAD)) { - set_bit(BIO_RW_BLOCK, &bio->bi_flags); + if (bio_flagged(bio, BIO_RW_AHEAD)) goto end_io; - } freereq = get_request_wait(q, rw); spin_lock_irq(q->queue_lock); @@ -1608,7 +1614,7 @@ return 0; end_io: - bio->bi_end_io(bio); + bio_endio(bio, nr_sectors << 9, -EWOULDBLOCK); return 0; } @@ -1697,7 +1703,7 @@ bdevname(bio->bi_bdev), (long long) bio->bi_sector); end_io: - bio->bi_end_io(bio); + bio_endio(bio, 0, -EIO); break; } @@ -1715,17 +1721,6 @@ } while (ret); } -/* - * our default bio end_io callback handler for a buffer_head mapping. - */ -static void end_bio_bh_io_sync(struct bio *bio) -{ - struct buffer_head *bh = bio->bi_private; - - bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags)); - bio_put(bio); -} - /** * submit_bio: submit a bio to the block device layer for I/O * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead) @@ -1759,161 +1754,6 @@ return 1; } -/** - * submit_bh: submit a buffer_head to the block device layer for I/O - * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead) - * @bh: The &struct buffer_head which describes the I/O - * - **/ -int submit_bh(int rw, struct buffer_head * bh) -{ - struct bio *bio; - - BUG_ON(!buffer_locked(bh)); - BUG_ON(!buffer_mapped(bh)); - BUG_ON(!bh->b_end_io); - - if ((rw == READ || rw == READA) && buffer_uptodate(bh)) - buffer_error(); - if (rw == WRITE && !buffer_uptodate(bh)) - buffer_error(); - if (rw == READ && buffer_dirty(bh)) - buffer_error(); - - set_buffer_req(bh); - - /* - * from here on down, it's all bio -- do the initial mapping, - * submit_bio -> generic_make_request may further map this bio around - */ - bio = bio_alloc(GFP_NOIO, 1); - - bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); - bio->bi_bdev = bh->b_bdev; - bio->bi_io_vec[0].bv_page = bh->b_page; - bio->bi_io_vec[0].bv_len = bh->b_size; - bio->bi_io_vec[0].bv_offset = bh_offset(bh); - - bio->bi_vcnt = 1; - bio->bi_idx = 0; - bio->bi_size = bh->b_size; - - bio->bi_end_io = end_bio_bh_io_sync; - bio->bi_private = bh; - - return submit_bio(rw, bio); -} - -/** - * ll_rw_block: low-level access to block devices - * @rw: whether to %READ or %WRITE or maybe %READA (readahead) - * @nr: number of &struct buffer_heads in the array - * @bhs: array of pointers to &struct buffer_head - * - * ll_rw_block() takes an array of pointers to &struct buffer_heads, - * and requests an I/O operation on them, either a %READ or a %WRITE. - * The third %READA option is described in the documentation for - * generic_make_request() which ll_rw_block() calls. - * - * This function provides extra functionality that is not in - * generic_make_request() that is relevant to buffers in the buffer - * cache or page cache. In particular it drops any buffer that it - * cannot get a lock on (with the BH_Lock state bit), any buffer that - * appears to be clean when doing a write request, and any buffer that - * appears to be up-to-date when doing read request. Further it marks - * as clean buffers that are processed for writing (the buffer cache - * wont assume that they are actually clean until the buffer gets - * unlocked). - * - * ll_rw_block sets b_end_io to simple completion handler that marks - * the buffer up-to-date (if approriate), unlocks the buffer and wakes - * any waiters. As client that needs a more interesting completion - * routine should call submit_bh() (or generic_make_request()) - * directly. - * - * Caveat: - * All of the buffers must be for the same device, and must also be - * a multiple of the current approved size for the device. - * - **/ - -void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) -{ - unsigned int major; - int correct_size; - int i; - - if (!nr) - return; - - major = major(to_kdev_t(bhs[0]->b_bdev->bd_dev)); - - /* Determine correct block size for this device. */ - correct_size = bdev_hardsect_size(bhs[0]->b_bdev); - - /* Verify requested block sizes. */ - for (i = 0; i < nr; i++) { - struct buffer_head *bh = bhs[i]; - if (bh->b_size & (correct_size - 1)) { - printk(KERN_NOTICE "ll_rw_block: device %s: " - "only %d-char blocks implemented (%u)\n", - bdevname(bhs[0]->b_bdev), - correct_size, bh->b_size); - goto sorry; - } - } - - if ((rw & WRITE) && bdev_read_only(bhs[0]->b_bdev)) { - printk(KERN_NOTICE "Can't write to read-only device %s\n", - bdevname(bhs[0]->b_bdev)); - goto sorry; - } - - for (i = 0; i < nr; i++) { - struct buffer_head *bh = bhs[i]; - - /* Only one thread can actually submit the I/O. */ - if (test_set_buffer_locked(bh)) - continue; - - /* We have the buffer lock */ - atomic_inc(&bh->b_count); - bh->b_end_io = end_buffer_io_sync; - - switch(rw) { - case WRITE: - if (!test_clear_buffer_dirty(bh)) - /* Hmmph! Nothing to write */ - goto end_io; - break; - - case READA: - case READ: - if (buffer_uptodate(bh)) - /* Hmmph! Already have it */ - goto end_io; - break; - default: - BUG(); - end_io: - bh->b_end_io(bh, buffer_uptodate(bh)); - continue; - } - - submit_bh(rw, bh); - } - return; - -sorry: - /* Make sure we don't get infinite dirty retries.. */ - for (i = 0; i < nr; i++) - clear_buffer_dirty(bhs[i]); -} - -#ifdef CONFIG_STRAM_SWAP -extern int stram_device_init (void); -#endif - inline void blk_recalc_rq_segments(struct request *rq) { struct bio *bio; @@ -1962,8 +1802,8 @@ * @nr_sectors: number of sectors to end I/O on * * Description: - * Ends I/O on the first buffer attached to @req, and sets it up - * for the next buffer_head (if any) in the cluster. + * Ends I/O on a number of sectors attached to @req, and sets it up + * for the next range of segments (if any) in the cluster. * * Return: * 0 - we are done with this request, call end_that_request_last() @@ -1983,6 +1823,7 @@ total_nsect = 0; while ((bio = req->bio)) { nsect = bio_iovec(bio)->bv_len >> 9; + total_nsect += nsect; BIO_BUG_ON(bio_iovec(bio)->bv_len > bio->bi_size); @@ -1992,38 +1833,31 @@ if (unlikely(nsect > nr_sectors)) { int partial = nr_sectors << 9; - bio->bi_size -= partial; bio_iovec(bio)->bv_offset += partial; bio_iovec(bio)->bv_len -= partial; - blk_recalc_rq_sectors(req, nr_sectors); + blk_recalc_rq_sectors(req, total_nsect); blk_recalc_rq_segments(req); + bio_endio(bio, partial, !uptodate ? -EIO : 0); return 1; } /* - * account transfer + * if bio->bi_end_io returns 0, this bio is done. move on */ - bio->bi_size -= bio_iovec(bio)->bv_len; - bio->bi_idx++; + req->bio = bio->bi_next; + if (bio_endio(bio, nsect << 9, !uptodate ? -EIO : 0)) { + bio->bi_idx++; + req->bio = bio; + } nr_sectors -= nsect; - total_nsect += nsect; - - if (!bio->bi_size) { - req->bio = bio->bi_next; - - bio_endio(bio, uptodate); - - total_nsect = 0; - } if ((bio = req->bio)) { - blk_recalc_rq_sectors(req, nsect); - /* * end more in this run, or just return 'not-done' */ if (unlikely(nr_sectors <= 0)) { + blk_recalc_rq_sectors(req, total_nsect); blk_recalc_rq_segments(req); return 1; } @@ -2041,27 +1875,16 @@ blk_put_request(req); } -#define MB(kb) ((kb) << 10) - int __init blk_dev_init(void) { - struct blk_dev_struct *dev; - int total_ram; + int total_ram = nr_free_pages() << (PAGE_SHIFT - 10); request_cachep = kmem_cache_create("blkdev_requests", - sizeof(struct request), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); - + sizeof(struct request), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); if (!request_cachep) panic("Can't create request pool slab cache\n"); - for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) - dev->queue = NULL; - - memset(ro_bits,0,sizeof(ro_bits)); - - total_ram = nr_free_pages() << (PAGE_SHIFT - 10); - /* * Free request slots per queue. * (Half for reads, half for writes) @@ -2077,16 +1900,11 @@ */ if ((batch_requests = queue_nr_requests / 4) > 32) batch_requests = 32; - printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests); + printk("block: %d slots per queue, batch=%d\n", + queue_nr_requests, batch_requests); blk_max_low_pfn = max_low_pfn; blk_max_pfn = max_pfn; - - INIT_LIST_HEAD(&blk_plug_list); - -#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD) - hd_init(); -#endif return 0; }; diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c --- a/drivers/block/loop.c Fri Sep 20 08:20:46 2002 +++ b/drivers/block/loop.c Fri Sep 20 08:20:46 2002 @@ -374,7 +374,7 @@ return ret; } -static void loop_end_io_transfer(struct bio *); +static int loop_end_io_transfer(struct bio *, unsigned int, int); static void loop_put_buffer(struct bio *bio) { /* @@ -382,6 +382,7 @@ */ if (bio && bio->bi_end_io == loop_end_io_transfer) { int i; + for (i = 0; i < bio->bi_vcnt; i++) __free_page(bio->bi_io_vec[i].bv_page); @@ -432,19 +433,23 @@ * bi_end_io context (we don't want to do decrypt of a page with irqs * disabled) */ -static void loop_end_io_transfer(struct bio *bio) +static int loop_end_io_transfer(struct bio *bio, unsigned int bytes_done, int err) { struct bio *rbh = bio->bi_private; struct loop_device *lo = &loop_dev[minor(to_kdev_t(rbh->bi_bdev->bd_dev))]; - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); - if (!uptodate || bio_rw(bio) == WRITE) { - bio_endio(rbh, uptodate); + if (bio->bi_size) + return 1; + + if (!err || bio_rw(bio) == WRITE) { + bio_endio(rbh, rbh->bi_size, err); if (atomic_dec_and_test(&lo->lo_pending)) up(&lo->lo_bh_mutex); loop_put_buffer(bio); } else loop_add_bio(lo, bio); + + return 0; } static struct bio *loop_get_buffer(struct loop_device *lo, struct bio *rbh) @@ -553,7 +558,7 @@ up(&lo->lo_bh_mutex); loop_put_buffer(new_bio); out: - bio_io_error(old_bio); + bio_io_error(old_bio, old_bio->bi_size); return 0; inactive: spin_unlock_irq(&lo->lo_lock); @@ -569,13 +574,13 @@ */ if (lo->lo_flags & LO_FLAGS_DO_BMAP) { ret = do_bio_filebacked(lo, bio); - bio_endio(bio, !ret); + bio_endio(bio, bio->bi_size, ret); } else { struct bio *rbh = bio->bi_private; ret = bio_transfer(lo, bio, rbh); - bio_endio(rbh, !ret); + bio_endio(rbh, rbh->bi_size, ret); loop_put_buffer(bio); } } diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c --- a/drivers/block/rd.c Fri Sep 20 08:20:47 2002 +++ b/drivers/block/rd.c Fri Sep 20 08:20:47 2002 @@ -277,11 +277,10 @@ if (rd_blkdev_bio_IO(sbh, minor)) goto fail; - set_bit(BIO_UPTODATE, &sbh->bi_flags); - sbh->bi_end_io(sbh); + bio_endio(sbh, sbh->bi_size, 0); return 0; fail: - bio_io_error(sbh); + bio_io_error(sbh, sbh->bi_size); return 0; } diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c --- a/drivers/block/umem.c Fri Sep 20 08:20:48 2002 +++ b/drivers/block/umem.c Fri Sep 20 08:20:48 2002 @@ -544,9 +544,16 @@ while(return_bio) { struct bio *bio = return_bio; + int bytes = bio->bi_size; + return_bio = bio->bi_next; bio->bi_next = NULL; - bio->bi_end_io(bio); + /* should use bio_endio(), however already cleared + * BIO_UPTODATE. so set bio->bi_size = 0 manually to indicate + * completely done + */ + bio->bi_size = 0; + bio->bi_end_io(bio, bytes, 0); } } @@ -560,8 +567,6 @@ struct cardinfo *card = q->queuedata; PRINTK("mm_make_request %ld %d\n", bh->b_rsector, bh->b_size); - /* set uptodate now, and clear it if there are any errors */ - set_bit(BIO_UPTODATE, &bio->bi_flags); bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/ spin_lock_bh(&card->lock); *card->biotail = bio; diff -Nru a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c --- a/drivers/bluetooth/hci_h4.c Fri Sep 20 08:20:46 2002 +++ b/drivers/bluetooth/hci_h4.c Fri Sep 20 08:20:46 2002 @@ -253,13 +253,13 @@ } static struct hci_uart_proto h4p = { - id: HCI_UART_H4, - open: h4_open, - close: h4_close, - send: h4_send, - recv: h4_recv, - preq: h4_preq, - flush: h4_flush, + .id = HCI_UART_H4, + .open = h4_open, + .close = h4_close, + .send = h4_send, + .recv = h4_recv, + .preq = h4_preq, + .flush = h4_flush, }; int h4_init(void) diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c --- a/drivers/bluetooth/hci_usb.c Fri Sep 20 08:20:48 2002 +++ b/drivers/bluetooth/hci_usb.c Fri Sep 20 08:20:48 2002 @@ -828,10 +828,10 @@ } static struct usb_driver hci_usb_driver = { - name: "hci_usb", - probe: hci_usb_probe, - disconnect: hci_usb_disconnect, - id_table: usb_bluetooth_ids, + .name = "hci_usb", + .probe = hci_usb_probe, + .disconnect = hci_usb_disconnect, + .id_table = usb_bluetooth_ids, }; int hci_usb_init(void) diff -Nru a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c --- a/drivers/bluetooth/hci_vhci.c Fri Sep 20 08:20:48 2002 +++ b/drivers/bluetooth/hci_vhci.c Fri Sep 20 08:20:48 2002 @@ -311,15 +311,15 @@ } static struct file_operations hci_vhci_fops = { - owner: THIS_MODULE, - llseek: hci_vhci_chr_lseek, - read: hci_vhci_chr_read, - write: hci_vhci_chr_write, - poll: hci_vhci_chr_poll, - ioctl: hci_vhci_chr_ioctl, - open: hci_vhci_chr_open, - release:hci_vhci_chr_close, - fasync: hci_vhci_chr_fasync + .owner = THIS_MODULE, + .llseek = hci_vhci_chr_lseek, + .read = hci_vhci_chr_read, + .write = hci_vhci_chr_write, + .poll = hci_vhci_chr_poll, + .ioctl = hci_vhci_chr_ioctl, + .open = hci_vhci_chr_open, + .release = hci_vhci_chr_close, + .fasync = hci_vhci_chr_fasync }; static struct miscdevice hci_vhci_miscdev= diff -Nru a/drivers/char/eurotechwdt.c b/drivers/char/eurotechwdt.c --- a/drivers/char/eurotechwdt.c Fri Sep 20 08:20:42 2002 +++ b/drivers/char/eurotechwdt.c Fri Sep 20 08:20:42 2002 @@ -46,7 +46,6 @@ #include #include #include -#include static int eurwdt_is_open; static spinlock_t eurwdt_lock; diff -Nru a/drivers/char/random.c b/drivers/char/random.c --- a/drivers/char/random.c Fri Sep 20 08:20:41 2002 +++ b/drivers/char/random.c Fri Sep 20 08:20:41 2002 @@ -2033,57 +2033,103 @@ /* This should not be decreased so low that ISNs wrap too fast. */ #define REKEY_INTERVAL 300 -#define HASH_BITS 24 +/* + * Bit layout of the tcp sequence numbers (before adding current time): + * bit 24-31: increased after every key exchange + * bit 0-23: hash(source,dest) + * + * The implementation is similar to the algorithm described + * in the Appendix of RFC 1185, except that + * - it uses a 1 MHz clock instead of a 250 kHz clock + * - it performs a rekey every 5 minutes, which is equivalent + * to a (source,dest) tulple dependent forward jump of the + * clock by 0..2^(HASH_BITS+1) + * + * Thus the average ISN wraparound time is 68 minutes instead of + * 4.55 hours. + * + * SMP cleanup and lock avoidance with poor man's RCU. + * Manfred Spraul + * + */ +#define COUNT_BITS 8 +#define COUNT_MASK ( (1<rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) { + keyptr = &ip_keydata[1^(ip_cnt&1)]; + keyptr->rekey_time = time; + get_random_bytes(keyptr->secret, sizeof(keyptr->secret)); + keyptr->count = (ip_cnt&COUNT_MASK)<rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) { + keyptr = __check_and_rekey(time); + } + + return keyptr; +} #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, __u16 sport, __u16 dport) { - static __u32 rekey_time; - static __u32 count; - static __u32 secret[12]; struct timeval tv; __u32 seq; + __u32 hash[12]; + struct keydata *keyptr; - /* The procedure is the same as for IPv4, but addresses are longer. */ + /* The procedure is the same as for IPv4, but addresses are longer. + * Thus we must use twothirdsMD4Transform. + */ do_gettimeofday(&tv); /* We need the usecs below... */ + keyptr = check_and_rekey(tv.tv_sec); - if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) { - rekey_time = tv.tv_sec; - /* First five words are overwritten below. */ - get_random_bytes(&secret[5], sizeof(secret)-5*4); - count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS; - } - - memcpy(secret, saddr, 16); - secret[4]=(sport << 16) + dport; - - seq = (twothirdsMD4Transform(daddr, secret) & - ((1<secret,sizeof(__u32)*7); + seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK; + seq += keyptr->count; seq += tv.tv_usec + tv.tv_sec*1000000; + return seq; } EXPORT_SYMBOL(secure_tcpv6_sequence_number); __u32 secure_ipv6_id(__u32 *daddr) { - static time_t rekey_time; - static __u32 secret[12]; - time_t t; + struct keydata *keyptr; - /* - * Pick a random secret every REKEY_INTERVAL seconds. - */ - t = CURRENT_TIME; - if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) { - rekey_time = t; - /* First word is overwritten below. */ - get_random_bytes(secret, sizeof(secret)); - } + keyptr = check_and_rekey(CURRENT_TIME); - return twothirdsMD4Transform(daddr, secret); + return halfMD4Transform(daddr, keyptr->secret); } EXPORT_SYMBOL(secure_ipv6_id); @@ -2093,40 +2139,30 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport) { - static __u32 rekey_time; - static __u32 count; - static __u32 secret[12]; struct timeval tv; __u32 seq; + __u32 hash[4]; + struct keydata *keyptr; /* * Pick a random secret every REKEY_INTERVAL seconds. */ do_gettimeofday(&tv); /* We need the usecs below... */ - - if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) { - rekey_time = tv.tv_sec; - /* First three words are overwritten below. */ - get_random_bytes(&secret[3], sizeof(secret)-12); - count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS; - } + keyptr = check_and_rekey(tv.tv_sec); /* * Pick a unique starting offset for each TCP connection endpoints * (saddr, daddr, sport, dport). - * Note that the words are placed into the first words to be - * mixed in with the halfMD4. This is because the starting - * vector is also a random secret (at secret+8), and further - * hashing fixed data into it isn't going to improve anything, - * so we should get started with the variable data. + * Note that the words are placed into the starting vector, which is + * then mixed with a partial MD4 over random data. */ - secret[0]=saddr; - secret[1]=daddr; - secret[2]=(sport << 16) + dport; - - seq = (halfMD4Transform(secret+8, secret) & - ((1<secret[11]; + seq = halfMD4Transform(hash, keyptr->secret) & HASH_MASK; + seq += keyptr->count; /* * As close as possible to RFC 793, which * suggests using a 250 kHz clock. @@ -2148,31 +2184,22 @@ */ __u32 secure_ip_id(__u32 daddr) { - static time_t rekey_time; - static __u32 secret[12]; - time_t t; + struct keydata *keyptr; + __u32 hash[4]; - /* - * Pick a random secret every REKEY_INTERVAL seconds. - */ - t = CURRENT_TIME; - if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) { - rekey_time = t; - /* First word is overwritten below. */ - get_random_bytes(secret+1, sizeof(secret)-4); - } + keyptr = check_and_rekey(CURRENT_TIME); /* * Pick a unique starting offset for each IP destination. - * Note that the words are placed into the first words to be - * mixed in with the halfMD4. This is because the starting - * vector is also a random secret (at secret+8), and further - * hashing fixed data into it isn't going to improve anything, - * so we should get started with the variable data. + * The dest ip address is placed in the starting vector, + * which is then hashed with random data. */ - secret[0]=daddr; + hash[0] = daddr; + hash[1] = keyptr->secret[9]; + hash[2] = keyptr->secret[10]; + hash[3] = keyptr->secret[11]; - return halfMD4Transform(secret+8, secret); + return halfMD4Transform(hash, keyptr->secret); } #ifdef CONFIG_SYN_COOKIES diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c --- a/drivers/char/raw.c Fri Sep 20 08:20:47 2002 +++ b/drivers/char/raw.c Fri Sep 20 08:20:47 2002 @@ -241,7 +241,7 @@ static ssize_t raw_write(struct file *filp, const char *buf, size_t size, loff_t *offp) { - struct iovec local_iov = { .iov_base = buf, .iov_len = size}; + struct iovec local_iov = { .iov_base = (char *)buf, .iov_len = size}; return rw_raw_dev(WRITE, filp, &local_iov, 1, offp); } diff -Nru a/drivers/char/rtc.c b/drivers/char/rtc.c --- a/drivers/char/rtc.c Fri Sep 20 08:20:44 2002 +++ b/drivers/char/rtc.c Fri Sep 20 08:20:44 2002 @@ -76,6 +76,7 @@ #include #ifdef __sparc__ +#include #include #ifdef __sparc_v9__ #include diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c --- a/drivers/char/tty_io.c Fri Sep 20 08:20:47 2002 +++ b/drivers/char/tty_io.c Fri Sep 20 08:20:47 2002 @@ -432,6 +432,7 @@ struct file * cons_filp = NULL; struct task_struct *p; struct list_head *l; + struct pid *pid; int closecount = 0, n; if (!tty) @@ -496,17 +497,17 @@ } read_lock(&tasklist_lock); - for_each_process(p) { - if ((tty->session > 0) && (p->session == tty->session) && - p->leader) { - send_sig(SIGHUP,p,1); - send_sig(SIGCONT,p,1); + if (tty->session > 0) + for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) { + if (p->tty == tty) + p->tty = NULL; + if (!p->leader) + continue; + send_sig(SIGHUP, p, 1); + send_sig(SIGCONT, p, 1); if (tty->pgrp > 0) p->tty_old_pgrp = tty->pgrp; } - if (p->tty == tty) - p->tty = NULL; - } read_unlock(&tasklist_lock); tty->flags = 0; @@ -571,6 +572,8 @@ { struct tty_struct *tty = current->tty; struct task_struct *p; + struct list_head *l; + struct pid *pid; int tty_pgrp = -1; lock_kernel(); @@ -598,9 +601,8 @@ tty->pgrp = -1; read_lock(&tasklist_lock); - for_each_process(p) - if (p->session == current->session) - p->tty = NULL; + for_each_task_pid(current->session, PIDTYPE_SID, p, l, pid) + p->tty = NULL; read_unlock(&tasklist_lock); unlock_kernel(); } @@ -1221,12 +1223,15 @@ */ if (tty_closing || o_tty_closing) { struct task_struct *p; + struct list_head *l; + struct pid *pid; read_lock(&tasklist_lock); - for_each_process(p) { - if (p->tty == tty || (o_tty && p->tty == o_tty)) + for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) + p->tty = NULL; + if (o_tty) + for_each_task_pid(o_tty->session, PIDTYPE_SID, p,l, pid) p->tty = NULL; - } read_unlock(&tasklist_lock); if (redirect == tty || (o_tty && redirect == o_tty)) @@ -1540,6 +1545,10 @@ static int tiocsctty(struct tty_struct *tty, int arg) { + struct list_head *l; + struct pid *pid; + task_t *p; + if (current->leader && (current->session == tty->session)) return 0; @@ -1558,12 +1567,10 @@ /* * Steal it away */ - struct task_struct *p; read_lock(&tasklist_lock); - for_each_process(p) - if (p->tty == tty) - p->tty = NULL; + for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) + p->tty = NULL; read_unlock(&tasklist_lock); } else return -EPERM; diff -Nru a/drivers/hotplug/cpqphp.h b/drivers/hotplug/cpqphp.h --- a/drivers/hotplug/cpqphp.h Fri Sep 20 08:20:44 2002 +++ b/drivers/hotplug/cpqphp.h Fri Sep 20 08:20:44 2002 @@ -305,8 +305,8 @@ u8 first_slot; u8 add_support; u8 push_flag; - u8 speed; /* 0 = 33MHz, 1 = 66MHz */ - u8 speed_capability; /* 0 = 33MHz, 1 = 66MHz */ + enum pci_bus_speed speed; + enum pci_bus_speed speed_capability; u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */ u8 slot_switch_type; /* 0 = no switch, 1 = switch present */ u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */ @@ -321,9 +321,6 @@ wait_queue_head_t queue; /* sleep & wake process */ }; -#define CTRL_SPEED_33MHz 0 -#define CTRL_SPEED_66MHz 1 - struct irq_mapping { u8 barber_pole; u8 valid_INT; @@ -635,7 +632,7 @@ u16 misc; misc = readw(ctrl->hpc_reg + MISC); - return (misc & 0x0800) ? 1 : 0; + return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; } diff -Nru a/drivers/hotplug/cpqphp_core.c b/drivers/hotplug/cpqphp_core.c --- a/drivers/hotplug/cpqphp_core.c Fri Sep 20 08:20:41 2002 +++ b/drivers/hotplug/cpqphp_core.c Fri Sep 20 08:20:41 2002 @@ -79,6 +79,8 @@ static int get_attention_status (struct hotplug_slot *slot, u8 *value); static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); +static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); +static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { .owner = THIS_MODULE, @@ -90,6 +92,8 @@ .get_attention_status = get_attention_status, .get_latch_status = get_latch_status, .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, }; @@ -378,7 +382,7 @@ new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; if (is_slot66mhz(new_slot)) new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; - if (ctrl->speed == 1) + if (ctrl->speed == PCI_SPEED_66MHz) new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION; ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); @@ -782,6 +786,44 @@ return 0; } +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = ctrl->speed_capability; + + return 0; +} + +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = ctrl->speed; + + return 0; +} + static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { u8 num_of_slots = 0; @@ -853,28 +895,28 @@ case PCI_SUB_HPC_ID: /* Original 6500/7000 implementation */ ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = CTRL_SPEED_33MHz; + ctrl->speed_capability = PCI_SPEED_33MHz; ctrl->push_button = 0; // No pushbutton ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported + ctrl->defeature_PHP = 1; // PHP is supported ctrl->pcix_support = 0; // PCI-X not supported - ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported break; case PCI_SUB_HPC_ID2: /* First Pushbutton implementation */ ctrl->push_flag = 1; ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = CTRL_SPEED_33MHz; + ctrl->speed_capability = PCI_SPEED_33MHz; ctrl->push_button = 1; // Pushbutton is present ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported + ctrl->defeature_PHP = 1; // PHP is supported ctrl->pcix_support = 0; // PCI-X not supported - ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported break; case PCI_SUB_HPC_ID_INTC: /* Third party (6500/7000) */ ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = CTRL_SPEED_33MHz; + ctrl->speed_capability = PCI_SPEED_33MHz; ctrl->push_button = 0; // No pushbutton ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported ctrl->defeature_PHP = 1; // PHP is supported @@ -885,7 +927,7 @@ /* First 66 Mhz implementation */ ctrl->push_flag = 1; ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = CTRL_SPEED_66MHz; + ctrl->speed_capability = PCI_SPEED_66MHz; ctrl->push_button = 1; // Pushbutton is present ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported ctrl->defeature_PHP = 1; // PHP is supported @@ -903,9 +945,9 @@ case PCI_VENDOR_ID_INTEL: /* Check for speed capability (0=33, 1=66) */ if (subsystem_deviceid & 0x0001) { - ctrl->speed_capability = CTRL_SPEED_66MHz; + ctrl->speed_capability = PCI_SPEED_66MHz; } else { - ctrl->speed_capability = CTRL_SPEED_33MHz; + ctrl->speed_capability = PCI_SPEED_33MHz; } /* Check for push button */ @@ -982,7 +1024,7 @@ info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); dbg ("Hotplug controller capabilities:\n"); - dbg (" speed_capability %s\n", ctrl->speed_capability == CTRL_SPEED_33MHz ? "33MHz" : "66Mhz"); + dbg (" speed_capability %s\n", ctrl->speed_capability == PCI_SPEED_33MHz ? "33MHz" : "66Mhz"); dbg (" slot_switch_type %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present"); dbg (" defeature_PHP %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported"); dbg (" alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported"); diff -Nru a/drivers/hotplug/cpqphp_ctrl.c b/drivers/hotplug/cpqphp_ctrl.c --- a/drivers/hotplug/cpqphp_ctrl.c Fri Sep 20 08:20:44 2002 +++ b/drivers/hotplug/cpqphp_ctrl.c Fri Sep 20 08:20:44 2002 @@ -1187,7 +1187,7 @@ //********************************* rc = CARD_FUNCTIONING; } else { - if (ctrl->speed == 1) { + if (ctrl->speed == PCI_SPEED_66MHz) { // Wait for exclusive access to hardware down(&ctrl->crit_sect); @@ -1385,7 +1385,7 @@ dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); - if (ctrl->speed == 1) { + if (ctrl->speed == PCI_SPEED_66MHz) { // Wait for exclusive access to hardware down(&ctrl->crit_sect); diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c --- a/drivers/hotplug/ibmphp_core.c Fri Sep 20 08:20:48 2002 +++ b/drivers/hotplug/ibmphp_core.c Fri Sep 20 08:20:48 2002 @@ -384,14 +384,15 @@ debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); return rc; } -/* -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value) + +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { int rc = -ENODEV; struct slot *pslot; u8 mode = 0; - debug ("get_max_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); + debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, + hotplug_slot, value); ibmphp_lock_operations (); @@ -413,25 +414,26 @@ *value = pslot->supported_speed + 0x01; break; default: -*/ /* Note (will need to change): there would be soon 256, 512 also */ -/* rc = -ENODEV; + /* Note (will need to change): there would be soon 256, 512 also */ + rc = -ENODEV; } } } else rc = -ENODEV; ibmphp_unlock_operations (); - debug ("get_max_bus_speed - Exit rc[%d] value[%x]\n", rc, *value); + debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); return rc; } -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value) +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { int rc = -ENODEV; struct slot *pslot; u8 mode = 0; - debug ("get_cur_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); + debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, + hotplug_slot, value); ibmphp_lock_operations (); @@ -458,8 +460,8 @@ *value += 0x01; break; default: -*/ /* Note of change: there would also be 256, 512 soon */ -/* rc = -ENODEV; + /* Note of change: there would also be 256, 512 soon */ + rc = -ENODEV; } } } @@ -467,10 +469,10 @@ rc = -ENODEV; ibmphp_unlock_operations (); - debug ("get_cur_bus_speed - Exit rc[%d] value[%x]\n", rc, *value); + debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); return rc; } - +/* static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag) { int rc = -ENODEV; @@ -1584,9 +1586,9 @@ .get_attention_status = get_attention_status, .get_latch_status = get_latch_status, .get_adapter_status = get_adapter_present, -/* .get_max_bus_speed_status = get_max_bus_speed, - .get_max_adapter_speed_status = get_max_adapter_speed, - .get_cur_bus_speed_status = get_cur_bus_speed, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +/* .get_max_adapter_speed = get_max_adapter_speed, .get_bus_name_status = get_bus_name, */ }; diff -Nru a/drivers/hotplug/pci_hotplug.h b/drivers/hotplug/pci_hotplug.h --- a/drivers/hotplug/pci_hotplug.h Fri Sep 20 08:20:44 2002 +++ b/drivers/hotplug/pci_hotplug.h Fri Sep 20 08:20:44 2002 @@ -29,6 +29,22 @@ #define _PCI_HOTPLUG_H +/* These values come from the PCI Hotplug Spec */ +enum pci_bus_speed { + PCI_SPEED_33MHz = 0x00, + PCI_SPEED_66MHz = 0x01, + PCI_SPEED_66MHz_PCIX = 0x02, + PCI_SPEED_100MHz_PCIX = 0x03, + PCI_SPEED_133MHz_PCIX = 0x04, + PCI_SPEED_66MHz_PCIX_266 = 0x09, + PCI_SPEED_100MHz_PCIX_266 = 0x0a, + PCI_SPEED_133MHz_PCIX_266 = 0x0b, + PCI_SPEED_66MHz_PCIX_533 = 0x11, + PCI_SPEED_100MHz_PCIX_533 = 0X12, + PCI_SPEED_133MHz_PCIX_533 = 0x13, + PCI_SPEED_UNKNOWN = 0xff, +}; + struct hotplug_slot; struct hotplug_slot_core; @@ -50,7 +66,13 @@ * @get_latch_status: Called to get the current latch status of a slot. * If this field is NULL, the value passed in the struct hotplug_slot_info * will be used when this value is requested by a user. - * @get_adapter_present: Called to get see if an adapter is present in the slot or not. + * @get_adapter_status: Called to get see if an adapter is present in the slot or not. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_max_bus_speed: Called to get the max bus speed for a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_cur_bus_speed: Called to get the current bus speed for a slot. * If this field is NULL, the value passed in the struct hotplug_slot_info * will be used when this value is requested by a user. * @@ -69,6 +91,8 @@ int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); + int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); + int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); }; /** @@ -85,6 +109,8 @@ u8 attention_status; u8 latch_status; u8 adapter_status; + enum pci_bus_speed max_bus_speed; + enum pci_bus_speed cur_bus_speed; }; /** diff -Nru a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c --- a/drivers/hotplug/pci_hotplug_core.c Fri Sep 20 08:20:44 2002 +++ b/drivers/hotplug/pci_hotplug_core.c Fri Sep 20 08:20:44 2002 @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include "pci_hotplug.h" @@ -74,6 +76,8 @@ struct dentry *latch_dentry; struct dentry *adapter_dentry; struct dentry *test_dentry; + struct dentry *max_bus_speed_dentry; + struct dentry *cur_bus_speed_dentry; }; static struct super_operations pcihpfs_ops; @@ -86,6 +90,35 @@ LIST_HEAD(pci_hotplug_slot_list); +/* these strings match up with the values in pci_bus_speed */ +static char *pci_bus_speed_strings[] = { + "33 MHz PCI", /* 0x00 */ + "66 MHz PCI", /* 0x01 */ + "66 MHz PCIX", /* 0x02 */ + "100 MHz PCIX", /* 0x03 */ + "133 MHz PCIX", /* 0x04 */ + NULL, /* 0x05 */ + NULL, /* 0x06 */ + NULL, /* 0x07 */ + NULL, /* 0x08 */ + "66 MHz PCIX 266", /* 0x09 */ + "100 MHz PCIX 266", /* 0x0a */ + "133 MHz PCIX 266", /* 0x0b */ + NULL, /* 0x0c */ + NULL, /* 0x0d */ + NULL, /* 0x0e */ + NULL, /* 0x0f */ + NULL, /* 0x10 */ + "66 MHz PCIX 533", /* 0x11 */ + "100 MHz PCIX 533", /* 0x12 */ + "133 MHz PCIX 533", /* 0x13 */ +}; + +#ifdef CONFIG_PROC_FS +extern struct proc_dir_entry *proc_bus_pci_dir; +static struct proc_dir_entry *slotdir = NULL; +static const char *slotdir_name = "slots"; +#endif static struct inode *pcihpfs_get_inode (struct super_block *sb, int mode, int dev) { @@ -274,6 +307,24 @@ .llseek = default_file_lseek, }; +/* file ops for the "max bus speed" files */ +static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static struct file_operations max_bus_speed_file_operations = { + read: max_bus_speed_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, +}; + +/* file ops for the "current bus speed" files */ +static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static struct file_operations cur_bus_speed_file_operations = { + read: cur_bus_speed_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, +}; + /* file ops for the "test" files */ static ssize_t test_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos); static struct file_operations test_file_operations = { @@ -501,26 +552,28 @@ up(&parent->d_inode->i_sem); } -#define GET_STATUS(name) \ -static int get_##name##_status (struct hotplug_slot *slot, u8 *value) \ +#define GET_STATUS(name,type) \ +static int get_##name (struct hotplug_slot *slot, type *value) \ { \ struct hotplug_slot_ops *ops = slot->ops; \ int retval = 0; \ if (ops->owner) \ __MOD_INC_USE_COUNT(ops->owner); \ - if (ops->get_##name##_status) \ - retval = ops->get_##name##_status (slot, value); \ + if (ops->get_##name) \ + retval = ops->get_##name (slot, value); \ else \ - *value = slot->info->name##_status; \ + *value = slot->info->name; \ if (ops->owner) \ __MOD_DEC_USE_COUNT(ops->owner); \ return retval; \ } -GET_STATUS(power) -GET_STATUS(attention) -GET_STATUS(latch) -GET_STATUS(adapter) +GET_STATUS(power_status, u8) +GET_STATUS(attention_status, u8) +GET_STATUS(latch_status, u8) +GET_STATUS(adapter_status, u8) +GET_STATUS(max_bus_speed, enum pci_bus_speed) +GET_STATUS(cur_bus_speed, enum pci_bus_speed) static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset) { @@ -575,7 +628,7 @@ if (*offset < 0) return -EINVAL; - if (count <= 0) + if (count == 0 || count > 16384) return 0; if (*offset != 0) return 0; @@ -686,7 +739,7 @@ if (*offset < 0) return -EINVAL; - if (count <= 0) + if (count == 0 || count > 16384) return 0; if (*offset != 0) return 0; @@ -769,7 +822,6 @@ return retval; } - static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset) { struct hotplug_slot *slot = file->private_data; @@ -813,6 +865,108 @@ return retval; } +static char *unknown_speed = "Unknown bus speed"; + +static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + char *speed_string; + int retval; + int len = 0; + enum pci_bus_speed value; + + dbg ("count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_max_bus_speed (slot, &value); + if (retval) + goto exit; + + if (value == PCI_SPEED_UNKNOWN) + speed_string = unknown_speed; + else + speed_string = pci_bus_speed_strings[value]; + + len = sprintf (page, "%s\n", speed_string); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + +static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + char *speed_string; + int retval; + int len = 0; + enum pci_bus_speed value; + + dbg ("count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_cur_bus_speed (slot, &value); + if (retval) + goto exit; + + if (value == PCI_SPEED_UNKNOWN) + speed_string = unknown_speed; + else + speed_string = pci_bus_speed_strings[value]; + + len = sprintf (page, "%s\n", speed_string); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + static ssize_t test_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset) { struct hotplug_slot *slot = file->private_data; @@ -823,7 +977,7 @@ if (*offset < 0) return -EINVAL; - if (count <= 0) + if (count == 0 || count > 16384) return 0; if (*offset != 0) return 0; @@ -876,30 +1030,57 @@ S_IFDIR | S_IXUGO | S_IRUGO, NULL, NULL, NULL); if (core->dir_dentry != NULL) { - core->power_dentry = fs_create_file ("power", - S_IFREG | S_IRUGO | S_IWUSR, - core->dir_dentry, slot, - &power_file_operations); - - core->attention_dentry = fs_create_file ("attention", - S_IFREG | S_IRUGO | S_IWUSR, - core->dir_dentry, slot, - &attention_file_operations); - - core->latch_dentry = fs_create_file ("latch", - S_IFREG | S_IRUGO, - core->dir_dentry, slot, - &latch_file_operations); - - core->adapter_dentry = fs_create_file ("adapter", - S_IFREG | S_IRUGO, - core->dir_dentry, slot, - &presence_file_operations); - - core->test_dentry = fs_create_file ("test", - S_IFREG | S_IRUGO | S_IWUSR, - core->dir_dentry, slot, - &test_file_operations); + if ((slot->ops->enable_slot) || + (slot->ops->disable_slot) || + (slot->ops->get_power_status)) + core->power_dentry = + fs_create_file ("power", + S_IFREG | S_IRUGO | S_IWUSR, + core->dir_dentry, slot, + &power_file_operations); + + if ((slot->ops->set_attention_status) || + (slot->ops->get_attention_status)) + core->attention_dentry = + fs_create_file ("attention", + S_IFREG | S_IRUGO | S_IWUSR, + core->dir_dentry, slot, + &attention_file_operations); + + if (slot->ops->get_latch_status) + core->latch_dentry = + fs_create_file ("latch", + S_IFREG | S_IRUGO, + core->dir_dentry, slot, + &latch_file_operations); + + if (slot->ops->get_adapter_status) + core->adapter_dentry = + fs_create_file ("adapter", + S_IFREG | S_IRUGO, + core->dir_dentry, slot, + &presence_file_operations); + + if (slot->ops->get_max_bus_speed) + core->max_bus_speed_dentry = + fs_create_file ("max_bus_speed", + S_IFREG | S_IRUGO, + core->dir_dentry, slot, + &max_bus_speed_file_operations); + + if (slot->ops->get_cur_bus_speed) + core->cur_bus_speed_dentry = + fs_create_file ("cur_bus_speed", + S_IFREG | S_IRUGO, + core->dir_dentry, slot, + &cur_bus_speed_file_operations); + + if (slot->ops->hardware_test) + core->test_dentry = + fs_create_file ("test", + S_IFREG | S_IRUGO | S_IWUSR, + core->dir_dentry, slot, + &test_file_operations); } return 0; } @@ -917,6 +1098,10 @@ fs_remove_file (core->latch_dentry); if (core->adapter_dentry) fs_remove_file (core->adapter_dentry); + if (core->max_bus_speed_dentry) + fs_remove_file (core->max_bus_speed_dentry); + if (core->cur_bus_speed_dentry) + fs_remove_file (core->cur_bus_speed_dentry); if (core->test_dentry) fs_remove_file (core->test_dentry); fs_remove_file (core->dir_dentry); @@ -969,6 +1154,7 @@ return -EINVAL; } + memset (core, 0, sizeof (struct hotplug_slot_core)); slot->core_priv = core; list_add (&slot->slot_list, &pci_hotplug_slot_list); @@ -1012,10 +1198,13 @@ return 0; } -static inline void update_inode_time (struct inode *inode) +static inline void update_dentry_inode_time (struct dentry *dentry) { - if (inode) - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + struct inode *inode = dentry->d_inode; + if (inode) { + inode->i_mtime = CURRENT_TIME; + dnotify_parent(dentry, DN_MODIFY); + } } /** @@ -1050,16 +1239,19 @@ core = temp->core_priv; if ((core->power_dentry) && (temp->info->power_status != info->power_status)) - update_inode_time (core->power_dentry->d_inode); + update_dentry_inode_time (core->power_dentry); if ((core->attention_dentry) && (temp->info->attention_status != info->attention_status)) - update_inode_time (core->attention_dentry->d_inode); + update_dentry_inode_time (core->attention_dentry); if ((core->latch_dentry) && (temp->info->latch_status != info->latch_status)) - update_inode_time (core->latch_dentry->d_inode); + update_dentry_inode_time (core->latch_dentry); if ((core->adapter_dentry) && (temp->info->adapter_status != info->adapter_status)) - update_inode_time (core->adapter_dentry->d_inode); + update_dentry_inode_time (core->adapter_dentry); + if ((core->cur_bus_speed_dentry) && + (temp->info->cur_bus_speed != info->cur_bus_speed)) + update_dentry_inode_time (core->cur_bus_speed_dentry); memcpy (temp->info, info, sizeof (struct hotplug_slot_info)); spin_unlock (&list_lock); @@ -1080,6 +1272,11 @@ goto exit; } +#ifdef CONFIG_PROC_FS + /* create mount point for pcihpfs */ + slotdir = proc_mkdir(slotdir_name, proc_bus_pci_dir); +#endif + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); exit: @@ -1089,6 +1286,11 @@ static void __exit pci_hotplug_exit (void) { unregister_filesystem(&pcihpfs_type); + +#ifdef CONFIG_PROC_FS + if (slotdir) + remove_proc_entry(slotdir_name, proc_bus_pci_dir); +#endif } module_init(pci_hotplug_init); diff -Nru a/drivers/i2c/i2c-philips-par.c b/drivers/i2c/i2c-philips-par.c --- a/drivers/i2c/i2c-philips-par.c Fri Sep 20 08:20:42 2002 +++ b/drivers/i2c/i2c-philips-par.c Fri Sep 20 08:20:42 2002 @@ -201,6 +201,7 @@ NULL); if (!adapter->pdev) { printk(KERN_ERR "i2c-philips-par: Unable to register with parport.\n"); + kfree(adapter); return; } @@ -211,6 +212,7 @@ if (parport_claim_or_block(adapter->pdev) < 0 ) { printk(KERN_ERR "i2c-philips-par: Could not claim parallel port.\n"); + kfree(adapter); return; } /* reset hardware to sane state */ diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile --- a/drivers/ide/Makefile Fri Sep 20 08:20:46 2002 +++ b/drivers/ide/Makefile Fri Sep 20 08:20:46 2002 @@ -9,18 +9,8 @@ # export-objs := ide-iops.o ide-taskfile.o ide-proc.o ide.o ide-probe.o ide-dma.o ide-lib.o setup-pci.o -all-subdirs := arm legacy pci ppc -mod-subdirs := arm legacy pci ppc - -obj-y := -obj-m := -ide-obj-y := - -subdir-$(CONFIG_BLK_DEV_IDEPCI) += pci -subdir-$(CONFIG_BLK_DEV_IDE) += legacy ppc arm pci - # First come modules that register themselves with the core -obj-y += pci/idedriver-pci.o +obj-$(CONFIG_BLK_DEV_IDEPCI) += pci/ # Core IDE code - must come before legacy @@ -35,13 +25,9 @@ obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o ifeq ($(CONFIG_BLK_DEV_IDE),y) -obj-$(CONFIG_PROC_FS) += ide-proc.o +obj-$(CONFIG_PROC_FS) += ide-proc.o endif -ifeq ($(CONFIG_BLK_DEV_IDE),y) - obj-y += legacy/idedriver-legacy.o - obj-y += ppc/idedriver-ppc.o - obj-y += arm/idedriver-arm.o -endif +obj-$(CONFIG_BLK_DEV_IDE) += legacy/ ppc/ arm/ include $(TOPDIR)/Rules.make diff -Nru a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile --- a/drivers/ide/arm/Makefile Fri Sep 20 08:20:41 2002 +++ b/drivers/ide/arm/Makefile Fri Sep 20 08:20:41 2002 @@ -1,9 +1,4 @@ -O_TARGET := idedriver-arm.o - -obj-y := -obj-m := - obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c --- a/drivers/ide/ide-dma.c Fri Sep 20 08:20:46 2002 +++ b/drivers/ide/ide-dma.c Fri Sep 20 08:20:46 2002 @@ -445,20 +445,6 @@ return 0; } -static void ide_toggle_bounce(ide_drive_t *drive, int on) -{ - u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */ - - if (on && drive->media == ide_disk) { - if (!PCI_DMA_BUS_IS_PHYS) - addr = BLK_BOUNCE_ANY; - else - addr = HWIF(drive)->pci_dev->dma_mask; - } - - blk_queue_bounce_limit(&drive->queue, addr); -} - int __ide_dma_host_off (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); diff -Nru a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c --- a/drivers/ide/ide-lib.c Fri Sep 20 08:20:48 2002 +++ b/drivers/ide/ide-lib.c Fri Sep 20 08:20:48 2002 @@ -386,3 +386,19 @@ } EXPORT_SYMBOL_GPL(ide_get_best_pio_mode); + +void ide_toggle_bounce(ide_drive_t *drive, int on) +{ + u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */ + + if (on && drive->media == ide_disk) { + if (!PCI_DMA_BUS_IS_PHYS) + addr = BLK_BOUNCE_ANY; + else + addr = HWIF(drive)->pci_dev->dma_mask; + } + + blk_queue_bounce_limit(&drive->queue, addr); +} + +EXPORT_SYMBOL(ide_toggle_bounce); diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c --- a/drivers/ide/ide-probe.c Fri Sep 20 08:20:47 2002 +++ b/drivers/ide/ide-probe.c Fri Sep 20 08:20:47 2002 @@ -778,6 +778,8 @@ /* This is a driver limit and could be eliminated. */ blk_queue_max_phys_segments(q, PRD_ENTRIES); + + ide_toggle_bounce(drive, 1); } /* diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c --- a/drivers/ide/ide-proc.c Fri Sep 20 08:20:46 2002 +++ b/drivers/ide/ide-proc.c Fri Sep 20 08:20:46 2002 @@ -548,7 +548,7 @@ len = sprintf(page, "(none)\n"); else len = sprintf(page,"%llu\n", - (u64) ((ide_driver_t *)drive->driver)->capacity(drive)); + (long long) ((ide_driver_t *)drive->driver)->capacity(drive)); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c --- a/drivers/ide/ide-taskfile.c Fri Sep 20 08:20:41 2002 +++ b/drivers/ide/ide-taskfile.c Fri Sep 20 08:20:41 2002 @@ -271,7 +271,7 @@ hwif->OUTB(0x80, IDE_CONTROL_REG); high = task_read_24(drive); sectors = ((u64)high << 24) | low; - printk(", LBAsect=%lld", sectors); + printk(", LBAsect=%lld", (long long) sectors); } else { u8 cur = hwif->INB(IDE_SELECT_REG); u8 low = hwif->INB(IDE_LCYL_REG); diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c --- a/drivers/ide/ide.c Fri Sep 20 08:20:44 2002 +++ b/drivers/ide/ide.c Fri Sep 20 08:20:44 2002 @@ -567,7 +567,7 @@ sectors = ((u64)high << 24) | low; printk(", LBAsect=%llu, high=%d, low=%d", - (u64) sectors, + (long long) sectors, high, low); } else { u8 cur = hwif->INB(IDE_SELECT_REG); diff -Nru a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile --- a/drivers/ide/legacy/Makefile Fri Sep 20 08:20:43 2002 +++ b/drivers/ide/legacy/Makefile Fri Sep 20 08:20:43 2002 @@ -1,9 +1,4 @@ -O_TARGET := idedriver-legacy.o - -obj-y := -obj-m := - obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o diff -Nru a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c --- a/drivers/ide/legacy/hd.c Fri Sep 20 08:20:41 2002 +++ b/drivers/ide/legacy/hd.c Fri Sep 20 08:20:41 2002 @@ -846,7 +846,7 @@ } } -int __init hd_init(void) +static int __init hd_init(void) { if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) { printk("hd: unable to get major %d for hard disk\n",MAJOR_NR); diff -Nru a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile --- a/drivers/ide/pci/Makefile Fri Sep 20 08:20:43 2002 +++ b/drivers/ide/pci/Makefile Fri Sep 20 08:20:43 2002 @@ -1,9 +1,4 @@ -O_TARGET := idedriver-pci.o - -obj-y := -obj-m := - obj-$(CONFIG_BLK_DEV_ADMA100) += adma100.o obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o diff -Nru a/drivers/ide/ppc/Makefile b/drivers/ide/ppc/Makefile --- a/drivers/ide/ppc/Makefile Fri Sep 20 08:20:47 2002 +++ b/drivers/ide/ppc/Makefile Fri Sep 20 08:20:47 2002 @@ -1,9 +1,4 @@ -O_TARGET := idedriver-ppc.o - -obj-y := -obj-m := - obj-$(CONFIG_BLK_DEV_MPC8xx_IDE) += mpc8xx.o obj-$(CONFIG_BLK_DEV_IDE_PMAC) += pmac.o obj-$(CONFIG_BLK_DEV_IDE_SWARM) += swarm.o diff -Nru a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile --- a/drivers/ieee1394/Makefile Fri Sep 20 08:20:48 2002 +++ b/drivers/ieee1394/Makefile Fri Sep 20 08:20:48 2002 @@ -2,11 +2,8 @@ # Makefile for the Linux IEEE 1394 implementation # -O_TARGET := ieee1394drv.o - export-objs := ieee1394_core.o ohci1394.o cmp.o -list-multi := ieee1394.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ highlevel.o csr.o nodemgr.o @@ -22,6 +19,3 @@ obj-$(CONFIG_IEEE1394_CMP) += cmp.o include $(TOPDIR)/Rules.make - -ieee1394.o: $(ieee1394-objs) - $(LD) $(LDFLAGS) -r -o $@ $(ieee1394-objs) diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c --- a/drivers/ieee1394/dv1394.c Fri Sep 20 08:20:47 2002 +++ b/drivers/ieee1394/dv1394.c Fri Sep 20 08:20:47 2002 @@ -170,15 +170,6 @@ static struct hpsb_highlevel *hl_handle; /* = NULL; */ -static LIST_HEAD(dv1394_devfs); -struct dv1394_devfs_entry { - struct list_head list; - devfs_handle_t devfs; - char name[32]; - struct dv1394_devfs_entry *parent; -}; -static spinlock_t dv1394_devfs_lock = SPIN_LOCK_UNLOCKED; - /* translate from a struct file* to the corresponding struct video_card* */ static inline struct video_card* file_to_video_card(struct file *file) @@ -2564,6 +2555,17 @@ /*** DEVFS HELPERS *********************************************************/ +#ifdef CONFIG_DEVFS_FS + +static LIST_HEAD(dv1394_devfs); +struct dv1394_devfs_entry { + struct list_head list; + devfs_handle_t devfs; + char name[32]; + struct dv1394_devfs_entry *parent; +}; +static spinlock_t dv1394_devfs_lock = SPIN_LOCK_UNLOCKED; + struct dv1394_devfs_entry * dv1394_devfs_find( char *name) { @@ -2693,6 +2695,7 @@ kfree(p); } } +#endif /* CONFIG_DEVFS */ /*** IEEE1394 HPSB CALLBACKS ***********************************************/ @@ -2851,7 +2854,6 @@ { struct ti_ohci *ohci; char buf[16]; - struct dv1394_devfs_entry *devfs_entry; /* We only work with the OHCI-1394 driver */ if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) @@ -2873,6 +2875,8 @@ #endif #ifdef CONFIG_DEVFS_FS +{ + struct dv1394_devfs_entry *devfs_entry; devfs_entry = dv1394_devfs_find("dv"); if (devfs_entry != NULL) { snprintf(buf, sizeof(buf), "host%d", ohci->id); @@ -2880,6 +2884,7 @@ dv1394_devfs_add_dir("NTSC", devfs_entry, NULL); dv1394_devfs_add_dir("PAL", devfs_entry, NULL); } +} #endif dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE); diff -Nru a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c --- a/drivers/isdn/hisax/st5481_init.c Fri Sep 20 08:20:48 2002 +++ b/drivers/isdn/hisax/st5481_init.c Fri Sep 20 08:20:48 2002 @@ -59,7 +59,7 @@ * This function will be called when the adapter is plugged * into the USB bus. */ -static int probe_st5481(struct usb_interface *intf +static int probe_st5481(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); @@ -115,7 +115,7 @@ st5481_start(adapter); dev_set_drvdata(&intf->dev, adapter); - return adapter; + return 0; err_b: st5481_release_b(&adapter->bcs[0]); diff -Nru a/drivers/md/linear.c b/drivers/md/linear.c --- a/drivers/md/linear.c Fri Sep 20 08:20:45 2002 +++ b/drivers/md/linear.c Fri Sep 20 08:20:45 2002 @@ -144,7 +144,7 @@ if (!hash->dev1) { printk ("linear_make_request : hash->dev1==NULL for block %ld\n", block); - bio_io_error(bio); + bio_io_error(bio, bio->bi_size); return 0; } tmp_dev = hash->dev1; @@ -154,7 +154,7 @@ if (block >= (tmp_dev->size + tmp_dev->offset) || block < tmp_dev->offset) { printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, bdevname(tmp_dev->rdev->bdev), tmp_dev->size, tmp_dev->offset); - bio_io_error(bio); + bio_io_error(bio, bio->bi_size); return 0; } bio->bi_bdev = tmp_dev->rdev->bdev; diff -Nru a/drivers/md/md.c b/drivers/md/md.c --- a/drivers/md/md.c Fri Sep 20 08:20:44 2002 +++ b/drivers/md/md.c Fri Sep 20 08:20:44 2002 @@ -144,7 +144,7 @@ static int md_fail_request (request_queue_t *q, struct bio *bio) { - bio_io_error(bio); + bio_io_error(bio, bio->bi_size); return 0; } @@ -361,9 +361,13 @@ } -static void bi_complete(struct bio *bio) +static int bi_complete(struct bio *bio, unsigned int bytes_done, int error) { + if (bio->bi_size) + return 1; + complete((struct completion*)bio->bi_private); + return 0; } static int sync_page_io(struct block_device *bdev, sector_t sector, int size, diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c --- a/drivers/md/multipath.c Fri Sep 20 08:20:46 2002 +++ b/drivers/md/multipath.c Fri Sep 20 08:20:46 2002 @@ -109,17 +109,20 @@ struct bio *bio = mp_bh->master_bio; multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); - bio_endio(bio, uptodate); + bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO); mempool_free(mp_bh, conf->pool); } -void multipath_end_request(struct bio *bio) +int multipath_end_request(struct bio *bio, unsigned int bytes_done, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private); multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); mdk_rdev_t *rdev = conf->multipaths[mp_bh->path].rdev; + if (bio->bi_size) + return 1; + if (uptodate) multipath_end_bh_io(mp_bh, uptodate); else { @@ -132,7 +135,7 @@ multipath_reschedule_retry(mp_bh); } atomic_dec(&rdev->nr_pending); - return; + return 0; } /* diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c --- a/drivers/md/raid0.c Fri Sep 20 08:20:46 2002 +++ b/drivers/md/raid0.c Fri Sep 20 08:20:46 2002 @@ -323,7 +323,7 @@ bad_zone1: printk ("raid0_make_request bug: hash->zone1==NULL for block %ld\n", block); outerr: - bio_io_error(bio); + bio_io_error(bio, bio->bi_size); return 0; } diff -Nru a/drivers/md/raid1.c b/drivers/md/raid1.c --- a/drivers/md/raid1.c Fri Sep 20 08:20:41 2002 +++ b/drivers/md/raid1.c Fri Sep 20 08:20:41 2002 @@ -236,7 +236,7 @@ { struct bio *bio = r1_bio->master_bio; - bio_endio(bio, uptodate); + bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO); free_r1bio(r1_bio); } @@ -251,12 +251,15 @@ r1_bio->sector + (r1_bio->master_bio->bi_size >> 9); } -static void end_request(struct bio *bio) +static int end_request(struct bio *bio, unsigned int bytes_done, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); int mirror; conf_t *conf = mddev_to_conf(r1_bio->mddev); + + if (bio->bi_size) + return 1; if (r1_bio->cmd == READ || r1_bio->cmd == READA) mirror = r1_bio->read_disk; @@ -313,6 +316,7 @@ raid_end_bio_io(r1_bio, uptodate); } atomic_dec(&conf->mirrors[mirror].rdev->nr_pending); + return 0; } /* @@ -748,12 +752,15 @@ #define REDIRECT_SECTOR KERN_ERR \ "raid1: %s: redirecting sector %lu to another mirror\n" -static void end_sync_read(struct bio *bio) +static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); conf_t *conf = mddev_to_conf(r1_bio->mddev); + if (bio->bi_size) + return 1; + if (r1_bio->read_bio != bio) BUG(); update_head_pos(r1_bio->read_disk, r1_bio); @@ -769,9 +776,10 @@ set_bit(R1BIO_Uptodate, &r1_bio->state); atomic_dec(&conf->mirrors[r1_bio->read_disk].rdev->nr_pending); reschedule_retry(r1_bio); + return 0; } -static void end_sync_write(struct bio *bio) +static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); @@ -780,6 +788,9 @@ int i; int mirror=0; + if (bio->bi_size) + return 1; + for (i = 0; i < conf->raid_disks; i++) if (r1_bio->write_bios[i] == bio) { mirror = i; @@ -795,6 +806,7 @@ put_buf(r1_bio); } atomic_dec(&conf->mirrors[mirror].rdev->nr_pending); + return 0; } static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c --- a/drivers/md/raid5.c Fri Sep 20 08:20:43 2002 +++ b/drivers/md/raid5.c Fri Sep 20 08:20:43 2002 @@ -321,13 +321,17 @@ conf->slab_cache = NULL; } -static void raid5_end_read_request (struct bio * bi) +static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done, + int error) { struct stripe_head *sh = bi->bi_private; raid5_conf_t *conf = sh->raid_conf; int disks = conf->raid_disks, i; int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); + if (bi->bi_size) + return 1; + for (i=0 ; idev[i].req) break; @@ -335,7 +339,7 @@ PRINTK("end_read_request %lu/%d, count: %d, uptodate %d.\n", sh->sector, i, atomic_read(&sh->count), uptodate); if (i == disks) { BUG(); - return; + return 0; } if (uptodate) { @@ -384,9 +388,11 @@ clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh); + return 0; } -static void raid5_end_write_request (struct bio *bi) +static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, + int error) { struct stripe_head *sh = bi->bi_private; raid5_conf_t *conf = sh->raid_conf; @@ -394,6 +400,9 @@ unsigned long flags; int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); + if (bi->bi_size) + return 1; + for (i=0 ; idev[i].req) break; @@ -401,7 +410,7 @@ PRINTK("end_write_request %lu/%d, count %d, uptodate: %d.\n", sh->sector, i, atomic_read(&sh->count), uptodate); if (i == disks) { BUG(); - return; + return 0; } spin_lock_irqsave(&conf->device_lock, flags); @@ -414,6 +423,7 @@ set_bit(STRIPE_HANDLE, &sh->state); __release_stripe(conf, sh); spin_unlock_irqrestore(&conf->device_lock, flags); + return 0; } @@ -1135,9 +1145,12 @@ spin_unlock(&sh->lock); while ((bi=return_bi)) { + int bytes = bi->bi_size; + return_bi = bi->bi_next; bi->bi_next = NULL; - bi->bi_end_io(bi); + bi->bi_size = 0; + bi->bi_end_io(bi, bytes, 0); } for (i=disks; i-- ;) if (sh->dev[i].flags & ((1<bi_sector + (bi->bi_size>>9); bi->bi_next = NULL; - set_bit(BIO_UPTODATE, &bi->bi_flags); /* will be cleared if error detected */ bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { @@ -1257,8 +1269,12 @@ } } spin_lock_irq(&conf->device_lock); - if (--bi->bi_phys_segments == 0) - bi->bi_end_io(bi); + if (--bi->bi_phys_segments == 0) { + int bytes = bi->bi_size; + + bi->bi_size = 0; + bi->bi_end_io(bi, bytes, 0); + } spin_unlock_irq(&conf->device_lock); return 0; } diff -Nru a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile --- a/drivers/message/fusion/Makefile Fri Sep 20 08:20:47 2002 +++ b/drivers/message/fusion/Makefile Fri Sep 20 08:20:47 2002 @@ -1,14 +1,7 @@ # # Makefile for the LSI Logic Fusion MPT (Message Passing Technology) drivers. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now inherited from the -# parent makefile. -# -# Note 3! If you want to turn on various debug defines for an extended period of +# Note! If you want to turn on various debug defines for an extended period of # time but don't want them lingering around in the Makefile when you pass it on # to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer @@ -53,27 +46,11 @@ #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC -O_TARGET := fusion.o - export-objs := mptbase.o mptscsih.o mptlan.o mptctl.o isense.o -# ? what's list-multi for? -#list-multi := fusion.o mptscsih.o - obj-$(CONFIG_FUSION) += mptbase.o mptscsih.o obj-$(CONFIG_FUSION_ISENSE) += isense.o obj-$(CONFIG_FUSION_CTL) += mptctl.o obj-$(CONFIG_FUSION_LAN) += mptlan.o -O_OBJS := $(filter-out $(export-objs), $(obj-y)) -OX_OBJS := $(filter $(export-objs), $(obj-y)) -M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) - include $(TOPDIR)/Rules.make - - -# EXP... -## Fusion MPT extra's... -##mptscsih.o: $(mptscsih-objs) -## $(LD) -r -o $@ $(mptscsih-objs) diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c --- a/drivers/net/3c509.c Fri Sep 20 08:20:41 2002 +++ b/drivers/net/3c509.c Fri Sep 20 08:20:41 2002 @@ -692,7 +692,7 @@ outw(0x00, ioaddr + TX_FIFO); /* ... and the packet rounded to a doubleword. */ #ifdef __powerpc__ - outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); + outsl_ns(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); #else outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); #endif @@ -903,7 +903,7 @@ /* 'skb->data' points to the start of sk_buff data area. */ #ifdef __powerpc__ - insl_unswapped(ioaddr+RX_FIFO, skb_put(skb,pkt_len), + insl_ns(ioaddr+RX_FIFO, skb_put(skb,pkt_len), (pkt_len + 3) >> 2); #else insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len), diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c --- a/drivers/net/3c59x.c Fri Sep 20 08:20:41 2002 +++ b/drivers/net/3c59x.c Fri Sep 20 08:20:41 2002 @@ -1483,12 +1483,13 @@ mii_reg1 = mdio_read(dev, vp->phys[0], 1); mii_reg5 = mdio_read(dev, vp->phys[0], 5); if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) { - ; /* No MII device or no link partner report */ + netif_carrier_off(dev); /* No MII device or no link partner report */ } else { mii_reg5 &= vp->advertising; if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ vp->full_duplex = 1; + netif_carrier_on(dev); } vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); if (vortex_debug > 1) @@ -1692,13 +1693,16 @@ switch (dev->if_port) { case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx: if (media_status & Media_LnkBeat) { + netif_carrier_on(dev); ok = 1; if (vortex_debug > 1) printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); - } else if (vortex_debug > 1) + } else if (vortex_debug > 1) { + netif_carrier_off(dev); printk(KERN_DEBUG "%s: Media %s has no link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); + } break; case XCVR_MII: case XCVR_NWAY: { @@ -1707,7 +1711,7 @@ if (vortex_debug > 2) printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", dev->name, mii_status); - if (mii_status & 0x0004) { + if (mii_status & BMSR_LSTATUS) { int mii_reg5 = mdio_read(dev, vp->phys[0], 5); if (! vp->force_fd && mii_reg5 != 0xffff) { int duplex; @@ -1731,6 +1735,9 @@ /* AKPM: bug: should reset Tx and Rx after setting Duplex. Page 180 */ } } + netif_carrier_on(dev); + } else { + netif_carrier_off(dev); } } break; diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c --- a/drivers/net/8139cp.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/8139cp.c Fri Sep 20 08:20:46 2002 @@ -639,13 +639,13 @@ cp_rx_skb(cp, skb, desc); rx_next: + cp->rx_ring[rx_tail].opts2 = 0; + cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping); if (rx_tail == (CP_RX_RING_SIZE - 1)) desc->opts1 = cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz); else desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz); - cp->rx_ring[rx_tail].opts2 = 0; - cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping); rx_tail = NEXT_RX(rx_tail); } @@ -669,6 +669,8 @@ printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n", dev->name, status, cpr8(Cmd), cpr16(CpCmd)); + cpw16_f(IntrStatus, status); + spin_lock(&cp->lock); if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) @@ -676,8 +678,6 @@ if (status & (TxOK | TxErr | TxEmpty | SWInt)) cp_tx(cp); - cpw16_f(IntrStatus, status); - if (status & PciErr) { u16 pci_status; @@ -781,7 +781,6 @@ len = skb->len; mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE); - eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; CP_VLAN_TX_TAG(txd, vlan_tag); txd->addr = cpu_to_le64(mapping); wmb(); @@ -811,7 +810,7 @@ entry = NEXT_TX(entry); } else { struct cp_desc *txd; - u32 first_len; + u32 first_len, first_eor; dma_addr_t first_mapping; int frag, first_entry = entry; #ifdef CP_TX_CHECKSUM @@ -821,6 +820,7 @@ /* We must give this initial chunk to the device last. * Otherwise we could race with the device. */ + first_eor = eor; first_len = skb->len - skb->data_len; first_mapping = pci_map_single(cp->pdev, skb->data, first_len, PCI_DMA_TODEVICE); @@ -879,17 +879,19 @@ #ifdef CP_TX_CHECKSUM if (skb->ip_summed == CHECKSUM_HW) { if (ip->protocol == IPPROTO_TCP) - txd->opts1 = cpu_to_le32(first_len | FirstFrag | - DescOwn | IPCS | TCPCS); + txd->opts1 = cpu_to_le32(first_eor | first_len | + FirstFrag | DescOwn | + IPCS | TCPCS); else if (ip->protocol == IPPROTO_UDP) - txd->opts1 = cpu_to_le32(first_len | FirstFrag | - DescOwn | IPCS | UDPCS); + txd->opts1 = cpu_to_le32(first_eor | first_len | + FirstFrag | DescOwn | + IPCS | UDPCS); else BUG(); } else #endif - txd->opts1 = cpu_to_le32(first_len | FirstFrag | - DescOwn); + txd->opts1 = cpu_to_le32(first_eor | first_len | + FirstFrag | DescOwn); wmb(); } cp->tx_head = entry; @@ -1088,14 +1090,14 @@ cp->rx_skb[i].skb = skb; cp->rx_skb[i].frag = 0; + cp->rx_ring[i].opts2 = 0; + cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping); if (i == (CP_RX_RING_SIZE - 1)) cp->rx_ring[i].opts1 = cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz); else cp->rx_ring[i].opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz); - cp->rx_ring[i].opts2 = 0; - cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping); } return 0; @@ -1208,7 +1210,11 @@ printk(KERN_DEBUG "%s: disabling interface\n", dev->name); netif_stop_queue(dev); + + spin_lock_irq(&cp->lock); cp_stop_hw(cp); + spin_unlock_irq(&cp->lock); + free_irq(dev->irq, dev); cp_free_rings(cp); return 0; diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c Fri Sep 20 08:20:41 2002 +++ b/drivers/net/8139too.c Fri Sep 20 08:20:41 2002 @@ -1746,10 +1746,6 @@ tp->stats.tx_carrier_errors++; if (txstatus & TxOutOfWindow) tp->stats.tx_window_errors++; -#ifdef ETHER_STATS - if ((txstatus & 0x0f000000) == 0x0f000000) - tp->stats.collisions16++; -#endif } else { if (txstatus & TxUnderrun) { /* Add 64 to the Tx FIFO threshold. */ diff -Nru a/drivers/net/Config.help b/drivers/net/Config.help --- a/drivers/net/Config.help Fri Sep 20 08:20:41 2002 +++ b/drivers/net/Config.help Fri Sep 20 08:20:41 2002 @@ -1226,17 +1226,6 @@ More specific information and updates are available from . -CONFIG_NATSEMI_CABLE_MAGIC - Some systems see lots of errors with NatSemi ethernet controllers - on certain cables. If you are seeing lots of errors, try turning - this option on. Some boards have incorrect values for supporting - resistors that can cause this change to break. If you turn this - option on and your network suddenly stops working, turn this - option off. - - Say N unless you are certain you need this option. - Vendors should not enable this option by default. - CONFIG_SK_G16 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -1535,6 +1524,13 @@ This driver is for the Sundance "Alta" chip. More specific information and updates are available from . + +CONFIG_SUNDANCE_MMIO + Enable memory-mapped I/O for interaction with Sundance NIC registers. + Do NOT enable this by default, PIO (enabled when MMIO is disabled) + is known to solve bugs on certain chips. + + If unsure, say N. CONFIG_ZNET The Zenith Z-Note notebook computer has a built-in network diff -Nru a/drivers/net/Config.in b/drivers/net/Config.in --- a/drivers/net/Config.in Fri Sep 20 08:20:41 2002 +++ b/drivers/net/Config.in Fri Sep 20 08:20:41 2002 @@ -165,9 +165,6 @@ dep_tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI dep_tristate ' National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI - if [ "$CONFIG_NATSEMI" = "y" -o "$CONFIG_NATSEMI" = "m" ]; then - bool ' NatSemi workaround for high errors' CONFIG_NATSEMI_CABLE_MAGIC - fi dep_tristate ' PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI dep_tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL @@ -180,6 +177,7 @@ dep_tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI dep_tristate ' SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI dep_tristate ' Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI + dep_mbool ' Use MMIO instead of PIO' CONFIG_SUNDANCE_MMIO $CONFIG_SUNDANCE if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then tristate ' TI ThunderLAN support' CONFIG_TLAN fi diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile Fri Sep 20 08:20:44 2002 +++ b/drivers/net/Makefile Fri Sep 20 08:20:44 2002 @@ -70,7 +70,7 @@ obj-$(CONFIG_AIRONET4500_CS) += aironet4500_proc.o obj-$(CONFIG_WINBOND_840) += mii.o -obj-$(CONFIG_SUNDANCE) += sundance.o +obj-$(CONFIG_SUNDANCE) += sundance.o mii.o obj-$(CONFIG_HAMACHI) += hamachi.o obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o obj-$(CONFIG_SEEQ8005) += seeq8005.o diff -Nru a/drivers/net/acenic.c b/drivers/net/acenic.c --- a/drivers/net/acenic.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/acenic.c Fri Sep 20 08:20:46 2002 @@ -47,6 +47,7 @@ * flushing the Jumbo ring. * Hans Grobler : Memory leak fixes in the * driver init path. + * Grant Grundler : PCI write posting fixes. */ #include @@ -120,6 +121,9 @@ #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX #define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a #endif +#ifndef PCI_DEVICE_ID_FARALLON_PN9100T +#define PCI_DEVICE_ID_FARALLON_PN9100T 0xfa +#endif #ifndef PCI_VENDOR_ID_SGI #define PCI_VENDOR_ID_SGI 0x10a9 #endif @@ -140,10 +144,13 @@ { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620T, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, /* - * Farallon used the DEC vendor ID on their cards incorrectly. + * Farallon used the DEC vendor ID on their cards incorrectly, + * then later Alteon's ID. */ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, + { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_FARALLON_PN9100T, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { } @@ -173,15 +180,27 @@ #endif #ifndef SET_MODULE_OWNER -#define SET_MODULE_OWNER(dev) {do{} while(0);} +#define SET_MODULE_OWNER(dev) do{} while(0) #define ACE_MOD_INC_USE_COUNT MOD_INC_USE_COUNT #define ACE_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT #else -#define ACE_MOD_INC_USE_COUNT {do{} while(0);} -#define ACE_MOD_DEC_USE_COUNT {do{} while(0);} +#define ACE_MOD_INC_USE_COUNT do{} while(0) +#define ACE_MOD_DEC_USE_COUNT do{} while(0) #endif +#if LINUX_VERSION_CODE >= 0x2051c +#define ace_sync_irq(irq) synchronize_irq(irq) +#else +#define ace_sync_irq(irq) synchronize_irq() +#endif + +#if LINUX_VERSION_CODE < 0x2051e +#define local_irq_save(flags) do{__save_flags(flags) ; \ + __cli();} while(0) +#define local_irq_restore(flags) __restore_flags(flags) +#endif + #if (LINUX_VERSION_CODE < 0x02030d) #define pci_resource_start(dev, bar) dev->base_address[bar] #elif (LINUX_VERSION_CODE < 0x02032c) @@ -192,6 +211,7 @@ #define net_device device #endif + #if (LINUX_VERSION_CODE < 0x02032a) typedef u32 dma_addr_t; @@ -215,8 +235,6 @@ (((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO) #define pci_dma_supported(dev, mask) \ (((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0) -#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) -#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) #elif (LINUX_VERSION_CODE < 0x02040d) @@ -240,8 +258,15 @@ } #define pci_unmap_page(cookie, dma_addr, size, dir) \ pci_unmap_single(cookie, dma_addr, size, dir) +#endif + +#if (LINUX_VERSION_CODE < 0x020412) #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) +#define pci_unmap_addr(PTR, ADDR_NAME) 0 +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do{} while(0) +#define pci_unmap_len(PTR, LEN_NAME) 0 +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do{} while(0) #endif @@ -259,7 +284,7 @@ #define dev_kfree_skb_irq(a) dev_kfree_skb(a) #define netif_wake_queue(dev) clear_bit(0, &dev->tbusy) #define netif_stop_queue(dev) set_bit(0, &dev->tbusy) -#define late_stop_netif_stop_queue(dev) {do{} while(0);} +#define late_stop_netif_stop_queue(dev) do{} while(0) #define early_stop_netif_stop_queue(dev) test_and_set_bit(0,&dev->tbusy) #define early_stop_netif_wake_queue(dev) netif_wake_queue(dev) @@ -273,7 +298,7 @@ #define ace_mark_net_bh() mark_bh(NET_BH) #define netif_queue_stopped(dev) dev->tbusy #define netif_running(dev) dev->start -#define ace_if_down(dev) {do{dev->start = 0;} while(0);} +#define ace_if_down(dev) do{dev->start = 0;} while(0) #define tasklet_struct tq_struct static inline void tasklet_schedule(struct tasklet_struct *tasklet) @@ -291,13 +316,13 @@ tasklet->routine = (void (*)(void *))func; tasklet->data = (void *)data; } -#define tasklet_kill(tasklet) {do{} while(0);} +#define tasklet_kill(tasklet) do{} while(0) #else #define late_stop_netif_stop_queue(dev) netif_stop_queue(dev) #define early_stop_netif_stop_queue(dev) 0 -#define early_stop_netif_wake_queue(dev) {do{} while(0);} -#define ace_mark_net_bh() {do{} while(0);} -#define ace_if_down(dev) {do{} while(0);} +#define early_stop_netif_wake_queue(dev) do{} while(0) +#define ace_mark_net_bh() do{} while(0) +#define ace_if_down(dev) do{} while(0) #endif #if (LINUX_VERSION_CODE >= 0x02031b) @@ -313,7 +338,7 @@ #ifndef ARCH_HAS_PREFETCHW #ifndef prefetchw -#define prefetchw(x) {do{} while(0);} +#define prefetchw(x) do{} while(0) #endif #endif @@ -568,7 +593,7 @@ static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; static char version[] __initdata = - "acenic.c: v0.89 03/15/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n" + "acenic.c: v0.92 08/05/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; static struct net_device *root_dev; @@ -611,6 +636,8 @@ */ !((pdev->vendor == PCI_VENDOR_ID_DEC) && (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) && + !((pdev->vendor == PCI_VENDOR_ID_ALTEON) && + (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T)) && !((pdev->vendor == PCI_VENDOR_ID_SGI) && (pdev->device == PCI_DEVICE_ID_SGI_ACENIC))) continue; @@ -664,6 +691,11 @@ printk(version); } + if (pci_enable_device(pdev)) { + kfree(dev); + continue; + } + /* * Enable master mode before we start playing with the * pci_command word since pci_set_master() will modify @@ -708,9 +740,17 @@ switch(pdev->vendor) { case PCI_VENDOR_ID_ALTEON: - strncpy(ap->name, "AceNIC Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: Alteon AceNIC ", dev->name); + if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) { + strncpy(ap->name, "Farallon PN9100-T " + "Gigabit Ethernet", sizeof (ap->name)); + printk(KERN_INFO "%s: Farallon PN9100-T ", + dev->name); + } else { + strncpy(ap->name, "AceNIC Gigabit Ethernet", + sizeof (ap->name)); + printk(KERN_INFO "%s: Alteon AceNIC ", + dev->name); + } break; case PCI_VENDOR_ID_3COM: strncpy(ap->name, "3Com 3C985 Gigabit Ethernet", @@ -846,6 +886,7 @@ * This clears any pending interrupts */ writel(1, ®s->Mb0Lo); + readl(®s->CpuCtrl); /* flush */ /* * Make sure no other CPUs are processing interrupts @@ -856,7 +897,7 @@ * Then release the RX buffers - jumbo buffers were * already released in ace_close(). */ - synchronize_irq(); + ace_sync_irq(root_dev->irq); for (i = 0; i < RX_STD_RING_ENTRIES; i++) { struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; @@ -1138,34 +1179,30 @@ * to any crashes involving the NIC */ writel(HW_RESET | (HW_RESET << 24), ®s->HostCtrl); - wmb(); + readl(®s->HostCtrl); /* PCI write posting */ + udelay(5); /* - * Don't access any other registes before this point! + * Don't access any other registers before this point! */ #ifdef __BIG_ENDIAN /* * This will most likely need BYTE_SWAP once we switch * to using __raw_writel() */ -#ifdef __parisc__ - writel((WORD_SWAP | BYTE_SWAP | CLR_INT | - ((WORD_SWAP | BYTE_SWAP | CLR_INT) << 24)), - ®s->HostCtrl); -#else writel((WORD_SWAP | CLR_INT | ((WORD_SWAP | CLR_INT) << 24)), ®s->HostCtrl); -#endif #else writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)), ®s->HostCtrl); #endif - mb(); + readl(®s->HostCtrl); /* PCI write posting */ /* * Stop the NIC CPU and clear pending interrupts */ writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); + readl(®s->CpuCtrl); /* PCI write posting */ writel(0, ®s->Mb0Lo); tig_ver = readl(®s->HostCtrl) >> 28; @@ -1186,6 +1223,7 @@ tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor, tigon2FwReleaseFix); writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); + readl(®s->CpuBCtrl); /* PCI write posting */ /* * The SRAM bank size does _not_ indicate the amount * of memory on the card, it controls the _bank_ size! @@ -1217,7 +1255,7 @@ writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL | ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, ®s->ModeStat); #endif - mb(); + readl(®s->ModeStat); /* PCI write posting */ mac1 = 0; for(i = 0; i < 4; i++) { @@ -1355,7 +1393,7 @@ tmp &= ~DMA_READ_WRITE_MASK; tmp |= DMA_READ_MAX_128; /* - * All the docs sy MUST NOT. Well, I did. + * All the docs say MUST NOT. Well, I did. * Nothing terrible happens, if we load wrong size. * Bit w&i still works better! */ @@ -1365,6 +1403,13 @@ #if 0 /* + * The Host PCI bus controller driver has to set FBB. + * If all devices on that PCI bus support FBB, then the controller + * can enable FBB support in the Host PCI Bus controller (or on + * the PCI-PCI bridge if that applies). + * -ggg + */ + /* * I have received reports from people having problems when this * bit is enabled. */ @@ -1445,9 +1490,9 @@ set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring_dma); info->evt_ctrl.flags = 0; - set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma); *(ap->evt_prd) = 0; wmb(); + set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma); writel(0, ®s->EvtCsm); set_aceaddr(&info->cmd_ctrl.rngptr, 0x100); @@ -1579,7 +1624,13 @@ writel(0, ®s->MaskInt); writel(1, ®s->IfIdx); +#if 0 + /* + * McKinley boxes do not like us fiddling with AssistState + * this early + */ writel(1, ®s->AssistState); +#endif writel(DEF_STAT, ®s->TuneStatTicks); writel(DEF_TRACE, ®s->TuneTrace); @@ -1689,10 +1740,19 @@ */ memset(&ap->stats, 0, sizeof(ap->stats)); + /* + * Enable DMA engine now. + * If we do this sooner, Mckinley box pukes. + * I assume it's because Tigon II DMA engine wants to check + * *something* even before the CPU is started. + */ + writel(1, ®s->AssistState); /* enable DMA */ + /* * Start the NIC CPU */ writel(readl(®s->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), ®s->CpuCtrl); + readl(®s->CpuCtrl); /* * Wait for the firmware to spin up - max 3 seconds. @@ -1705,6 +1765,7 @@ ace_dump_trace(ap); writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); + readl(®s->CpuCtrl); /* aman@sgi.com - account for badly behaving firmware/NIC: * - have observed that the NIC may continue to generate @@ -1719,6 +1780,7 @@ writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); writel(0, ®s->Mb0Lo); + readl(®s->Mb0Lo); ecode = -EBUSY; goto init_error; @@ -2393,6 +2455,7 @@ * threads and it is wrong even for that case. */ writel(0, ®s->Mb0Lo); + readl(®s->Mb0Lo); /* * There is no conflict between transmit handling in @@ -2496,12 +2559,13 @@ struct ace_private *ap = dev->priv; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); + ace_mask_irq(dev); ap->vlgrp = grp; - restore_flags(flags); + ace_unmask_irq(dev); + local_irq_restore(flags); } @@ -2510,13 +2574,14 @@ struct ace_private *ap = dev->priv; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); + ace_mask_irq(dev); if (ap->vlgrp) ap->vlgrp->vlan_devices[vid] = NULL; - restore_flags(flags); + ace_unmask_irq(dev); + local_irq_restore(flags); } #endif /* ACENIC_DO_VLAN */ @@ -2620,8 +2685,9 @@ * Make sure one CPU is not processing packets while * buffers are being released by another. */ - save_flags(flags); - cli(); + + local_irq_save(flags); + ace_mask_irq(dev); for (i = 0; i < ACE_TX_RING_ENTRIES(ap); i++) { struct sk_buff *skb; @@ -2658,7 +2724,8 @@ ace_issue_cmd(regs, &cmd); } - restore_flags(flags); + ace_unmask_irq(dev); + local_irq_restore(flags); ACE_MOD_DEC_USE_COUNT; return 0; @@ -2877,7 +2944,7 @@ } } else { while (test_and_set_bit(0, &ap->jumbo_refill_busy)); - synchronize_irq(); + ace_sync_irq(dev->irq); ace_set_rxtx_parms(dev, 0); if (ap->jumbo) { struct cmd cmd; @@ -3259,22 +3326,27 @@ { u32 local; + readl(®s->LocalCtrl); udelay(ACE_SHORT_DELAY); local = readl(®s->LocalCtrl); local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); local &= ~EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); local &= ~EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); } @@ -3289,6 +3361,7 @@ local &= ~EEPROM_DATA_OUT; local |= EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); for (i = 0; i < 8; i++, magic <<= 1) { @@ -3298,15 +3371,18 @@ else local &= ~EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT); writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); } } @@ -3320,10 +3396,12 @@ local = readl(®s->LocalCtrl); local &= ~EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_LONG_DELAY); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); /* sample data in middle of high clk */ @@ -3331,6 +3409,7 @@ udelay(ACE_SHORT_DELAY); mb(); writel(readl(®s->LocalCtrl) & ~EEPROM_CLK_OUT, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); return state; @@ -3345,18 +3424,22 @@ local = readl(®s->LocalCtrl); local |= EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); local &= ~EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); local |= EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_LONG_DELAY); local &= ~EEPROM_CLK_OUT; @@ -3433,10 +3516,12 @@ local = readl(®s->LocalCtrl); local &= ~EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); udelay(ACE_LONG_DELAY); mb(); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); /* sample data mid high clk */ @@ -3447,11 +3532,13 @@ local = readl(®s->LocalCtrl); local &= ~EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); udelay(ACE_SHORT_DELAY); mb(); if (i == 7) { local |= EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); } @@ -3459,11 +3546,14 @@ local |= EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); writel(readl(®s->LocalCtrl) | EEPROM_CLK_OUT, ®s->LocalCtrl); + readl(®s->LocalCtrl); udelay(ACE_LONG_DELAY); writel(readl(®s->LocalCtrl) & ~EEPROM_CLK_OUT, ®s->LocalCtrl); + readl(®s->LocalCtrl); mb(); udelay(ACE_SHORT_DELAY); eeprom_stop(regs); diff -Nru a/drivers/net/acenic.h b/drivers/net/acenic.h --- a/drivers/net/acenic.h Fri Sep 20 08:20:46 2002 +++ b/drivers/net/acenic.h Fri Sep 20 08:20:46 2002 @@ -748,6 +748,32 @@ } +static inline void ace_mask_irq(struct net_device *dev) +{ + struct ace_private *ap = dev->priv; + struct ace_regs *regs = ap->regs; + + if (ACE_IS_TIGON_I(ap)) + writel(1, ®s->MaskInt); + else + writel(readl(®s->HostCtrl) | MASK_INTS, ®s->HostCtrl); + + ace_sync_irq(dev->irq); +} + + +static inline void ace_unmask_irq(struct net_device *dev) +{ + struct ace_private *ap = dev->priv; + struct ace_regs *regs = ap->regs; + + if (ACE_IS_TIGON_I(ap)) + writel(0, ®s->MaskInt); + else + writel(readl(®s->HostCtrl) &= ~MASK_INTS, ®s->HostCtrl); +} + + /* * Prototypes */ diff -Nru a/drivers/net/dl2k.c b/drivers/net/dl2k.c --- a/drivers/net/dl2k.c Fri Sep 20 08:20:44 2002 +++ b/drivers/net/dl2k.c Fri Sep 20 08:20:44 2002 @@ -809,13 +809,8 @@ /* Let TxStartThresh stay default value */ } /* Maximum Collisions */ -#ifdef ETHER_STATS - if (tx_status & 0x08) - np->stats.collisions16++; -#else if (tx_status & 0x08) np->stats.collisions++; -#endif /* Restart the Tx */ writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl); } diff -Nru a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c --- a/drivers/net/e100/e100_main.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/e100/e100_main.c Fri Sep 20 08:20:46 2002 @@ -114,8 +114,10 @@ static int e100_ethtool_gregs(struct net_device *, struct ifreq *); static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *); static int e100_ethtool_wol(struct net_device *, struct ifreq *); +#ifdef CONFIG_PM static unsigned char e100_setup_filter(struct e100_private *bdp); static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp); +#endif static u16 e100_get_ip_lbytes(struct net_device *dev); extern void e100_config_wol(struct e100_private *bdp); extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags); @@ -3740,8 +3742,8 @@ set_current_state(TASK_INTERRUPTIBLE); - if ((!ecmd.data) || (ecmd.data > MAX_SCHEDULE_TIMEOUT / HZ)) - ecmd.data = MAX_SCHEDULE_TIMEOUT / HZ; + if ((!ecmd.data) || (ecmd.data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))) + ecmd.data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); schedule_timeout(ecmd.data * HZ); @@ -3799,6 +3801,7 @@ } +#ifdef CONFIG_PM static unsigned char e100_setup_filter(struct e100_private *bdp) { @@ -3853,6 +3856,7 @@ printk(KERN_ERR "e100: config WOL failed\n"); } } +#endif static u16 e100_get_ip_lbytes(struct net_device *dev) diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c --- a/drivers/net/eepro100.c Fri Sep 20 08:20:47 2002 +++ b/drivers/net/eepro100.c Fri Sep 20 08:20:47 2002 @@ -459,8 +459,8 @@ Unfortunately, all the positions have been shifted since there. A new re-alignment is required. 2000/03/06 SAW */ struct speedo_private { - struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */ - struct RxFD *rx_ringp[RX_RING_SIZE];/* Rx descriptor, used as ring. */ + struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */ + struct RxFD *rx_ringp[RX_RING_SIZE]; /* Rx descriptor, used as ring. */ /* The addresses of a Tx/Rx-in-place packets/buffers. */ struct sk_buff *tx_skbuff[TX_RING_SIZE]; struct sk_buff *rx_skbuff[RX_RING_SIZE]; @@ -470,9 +470,9 @@ dma_addr_t rx_ring_dma[RX_RING_SIZE]; struct descriptor *last_cmd; /* Last command sent. */ unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */ - spinlock_t lock; /* Group with Tx control cache line. */ - u32 tx_threshold; /* The value for txdesc.count. */ - struct RxFD *last_rxf; /* Last filled RX buffer. */ + spinlock_t lock; /* Group with Tx control cache line. */ + u32 tx_threshold; /* The value for txdesc.count. */ + struct RxFD *last_rxf; /* Last filled RX buffer. */ dma_addr_t last_rxf_dma; unsigned int cur_rx, dirty_rx; /* The next free ring entry */ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ @@ -481,21 +481,21 @@ dma_addr_t lstats_dma; int chip_id; struct pci_dev *pdev; - struct timer_list timer; /* Media selection timer. */ - struct speedo_mc_block *mc_setup_head;/* Multicast setup frame list head. */ - struct speedo_mc_block *mc_setup_tail;/* Multicast setup frame list tail. */ - long in_interrupt; /* Word-aligned dev->interrupt */ + struct timer_list timer; /* Media selection timer. */ + struct speedo_mc_block *mc_setup_head; /* Multicast setup frame list head. */ + struct speedo_mc_block *mc_setup_tail; /* Multicast setup frame list tail. */ + long in_interrupt; /* Word-aligned dev->interrupt */ unsigned char acpi_pwr; - signed char rx_mode; /* Current PROMISC/ALLMULTI setting. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int flow_ctrl:1; /* Use 802.3x flow control. */ - unsigned int rx_bug:1; /* Work around receiver hang errata. */ + signed char rx_mode; /* Current PROMISC/ALLMULTI setting. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int flow_ctrl:1; /* Use 802.3x flow control. */ + unsigned int rx_bug:1; /* Work around receiver hang errata. */ unsigned char default_port:8; /* Last dev->if_port value. */ unsigned char rx_ring_state; /* RX ring status flags. */ - unsigned short phy[2]; /* PHY media interfaces available. */ - unsigned short advertising; /* Current PHY advertised caps. */ - unsigned short partner; /* Link partner caps. */ + unsigned short phy[2]; /* PHY media interfaces available. */ + unsigned short partner; /* Link partner caps. */ + struct mii_if_info mii_if; /* MII API hooks, info */ #ifdef CONFIG_PM u32 pm_state[16]; #endif @@ -532,8 +532,8 @@ static void eepro100_remove_one (struct pci_dev *pdev); static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len); -static int mdio_read(long ioaddr, int phy_id, int location); -static int mdio_write(long ioaddr, int phy_id, int location, int value); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int speedo_open(struct net_device *dev); static void speedo_resume(struct net_device *dev); static void speedo_timer(unsigned long data); @@ -658,6 +658,8 @@ return -1; } + SET_MODULE_OWNER(dev); + if (dev->mem_start > 0) option = dev->mem_start; else if (card_idx >= 0 && options[card_idx] >= 0) @@ -728,6 +730,9 @@ #endif printk("IRQ %d.\n", pdev->irq); + /* we must initialize base_addr early, for mdio_{read,write} */ + dev->base_addr = ioaddr; + #if 1 || defined(kernel_bloat) /* OK, this is pure kernel bloat. I don't like it when other drivers waste non-pageable kernel space to emit similar messages, but I need @@ -753,18 +758,18 @@ phys[(eeprom[7]>>8)&7]); if (((eeprom[6]>>8) & 0x3f) == DP83840 || ((eeprom[6]>>8) & 0x3f) == DP83840A) { - int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422; + int mdi_reg23 = mdio_read(dev, eeprom[6] & 0x1f, 23) | 0x0422; if (congenb) mdi_reg23 |= 0x0100; printk(KERN_INFO" DP83840 specific setup, setting register 23 to %4.4x.\n", mdi_reg23); - mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23); + mdio_write(dev, eeprom[6] & 0x1f, 23, mdi_reg23); } if ((option >= 0) && (option & 0x70)) { printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", (option & 0x20 ? 100 : 10), (option & 0x10 ? "full" : "half")); - mdio_write(ioaddr, eeprom[6] & 0x1f, 0, + mdio_write(dev, eeprom[6] & 0x1f, MII_BMCR, ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ } @@ -806,7 +811,6 @@ pci_set_drvdata (pdev, dev); - dev->base_addr = ioaddr; dev->irq = pdev->irq; sp = dev->priv; @@ -818,15 +822,21 @@ sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE); init_timer(&sp->timer); /* used in ioctl() */ - sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; + sp->mii_if.full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; if (card_idx >= 0) { if (full_duplex[card_idx] >= 0) - sp->full_duplex = full_duplex[card_idx]; + sp->mii_if.full_duplex = full_duplex[card_idx]; } sp->default_port = option >= 0 ? (option & 0x0f) : 0; sp->phy[0] = eeprom[6]; sp->phy[1] = eeprom[7]; + + sp->mii_if.phy_id = eeprom[6]; + sp->mii_if.dev = dev; + sp->mii_if.mdio_read = mdio_read; + sp->mii_if.mdio_write = mdio_write; + sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1; if (((pdev->device > 0x1030 && (pdev->device < 0x103F))) || (pdev->device == 0x2449) || (pdev->device == 0x2459) @@ -848,7 +858,30 @@ return 0; } - + +static void do_slow_command(struct net_device *dev, int cmd) +{ + long cmd_ioaddr = dev->base_addr + SCBCmd; + int wait = 0; + do + if (inb(cmd_ioaddr) == 0) break; + while(++wait <= 200); + if (wait > 100) + printk(KERN_ERR "Command %4.4x never accepted (%d polls)!\n", + inb(cmd_ioaddr), wait); + + outb(cmd, cmd_ioaddr); + + for (wait = 0; wait <= 100; wait++) + if (inb(cmd_ioaddr) == 0) return; + for (; wait <= 20000; wait++) + if (inb(cmd_ioaddr) == 0) return; + else udelay(1); + printk(KERN_ERR "Command %4.4x was not accepted after %d polls!" + " Current status %8.8x.\n", + cmd, wait, inl(dev->base_addr + SCBStatus)); +} + /* Serial EEPROM section. A "bit" grungy, but we work our way through bit-by-bit :->. */ /* EEPROM_Ctrl bits. */ @@ -890,8 +923,9 @@ return retval; } -static int mdio_read(long ioaddr, int phy_id, int location) +static int mdio_read(struct net_device *dev, int phy_id, int location) { + long ioaddr = dev->base_addr; int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI); do { @@ -904,8 +938,9 @@ return val & 0xffff; } -static int mdio_write(long ioaddr, int phy_id, int location, int value) +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { + long ioaddr = dev->base_addr; int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ outl(0x04000000 | (location<<16) | (phy_id<<21) | value, ioaddr + SCBCtrlMDI); @@ -916,10 +951,8 @@ break; } } while (! (val & 0x10000000)); - return val & 0xffff; } - static int speedo_open(struct net_device *dev) { @@ -930,8 +963,6 @@ if (speedo_debug > 1) printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq); - MOD_INC_USE_COUNT; - pci_set_power_state(sp->pdev, 0); /* Set up the Tx queue early.. */ @@ -945,7 +976,6 @@ /* .. we can safely take handler calls during init. */ retval = request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev); if (retval) { - MOD_DEC_USE_COUNT; return retval; } @@ -962,9 +992,9 @@ 0x2100 100-FD */ #ifdef honor_default_port - mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]); + mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]); #else - mdio_write(ioaddr, phy_addr, 0, 0x3300); + mdio_write(dev, phy_addr, MII_BMCR, 0x3300); #endif } #endif @@ -985,9 +1015,9 @@ sp->rx_mode = -1; /* Invalid -> always reset the mode. */ set_rx_mode(dev); if ((sp->phy[0] & 0x8000) == 0) - sp->advertising = mdio_read(ioaddr, sp->phy[0] & 0x1f, 4); + sp->mii_if.advertising = mdio_read(dev, sp->phy[0] & 0x1f, MII_ADVERTISE); - if (mdio_read(ioaddr, sp->phy[0] & 0x1f, MII_BMSR) & BMSR_LSTATUS) + if (mdio_read(dev, sp->phy[0] & 0x1f, MII_BMSR) & BMSR_LSTATUS) netif_carrier_on(dev); else netif_carrier_off(dev); @@ -1009,7 +1039,7 @@ /* No need to wait for the command unit to accept here. */ if ((sp->phy[0] & 0x8000) == 0) - mdio_read(ioaddr, sp->phy[0] & 0x1f, 0); + mdio_read(dev, sp->phy[0] & 0x1f, MII_BMCR); return 0; } @@ -1017,7 +1047,7 @@ /* Start the chip hardware after a full reset. */ static void speedo_resume(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = dev->priv; long ioaddr = dev->base_addr; /* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */ @@ -1025,34 +1055,40 @@ /* Set the segment registers to '0'. */ wait_for_cmd_done(ioaddr + SCBCmd); - outl(0, ioaddr + SCBPointer); - /* impose a delay to avoid a bug */ - inl(ioaddr + SCBPointer); - udelay(10); - outb(RxAddrLoad, ioaddr + SCBCmd); - wait_for_cmd_done(ioaddr + SCBCmd); - outb(CUCmdBase, ioaddr + SCBCmd); + if (inb(ioaddr + SCBCmd)) { + outl(PortPartialReset, ioaddr + SCBPort); + udelay(10); + } + + outl(0, ioaddr + SCBPointer); + inl(ioaddr + SCBPointer); /* Flush to PCI. */ + udelay(10); /* Bogus, but it avoids the bug. */ + + /* Note: these next two operations can take a while. */ + do_slow_command(dev, RxAddrLoad); + do_slow_command(dev, CUCmdBase); /* Load the statistics block and rx ring addresses. */ - wait_for_cmd_done(ioaddr + SCBCmd); outl(sp->lstats_dma, ioaddr + SCBPointer); + inl(ioaddr + SCBPointer); /* Flush to PCI */ + outb(CUStatsAddr, ioaddr + SCBCmd); sp->lstats->done_marker = 0; + wait_for_cmd_done(ioaddr + SCBCmd); if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) { if (speedo_debug > 2) printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n", dev->name); } else { - wait_for_cmd_done(ioaddr + SCBCmd); outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], ioaddr + SCBPointer); - outb(RxStart, ioaddr + SCBCmd); + inl(ioaddr + SCBPointer); /* Flush to PCI */ } - wait_for_cmd_done(ioaddr + SCBCmd); - outb(CUDumpStats, ioaddr + SCBCmd); - udelay(30); + /* Note: RxStart should complete instantly. */ + do_slow_command(dev, RxStart); + do_slow_command(dev, CUDumpStats); /* Fill the first command with our physical address. */ { @@ -1065,11 +1101,12 @@ ias_cmd->link = cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE)); memcpy(ias_cmd->params, dev->dev_addr, 6); + if (sp->last_cmd) + clear_suspend(sp->last_cmd); sp->last_cmd = ias_cmd; } /* Start the chip's Tx process and unmask interrupts. */ - wait_for_cmd_done(ioaddr + SCBCmd); outl(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE), ioaddr + SCBPointer); /* We are not ACK-ing FCP and ER in the interrupt handler yet so they should @@ -1132,13 +1169,13 @@ /* We have MII and lost link beat. */ if ((sp->phy[0] & 0x8000) == 0) { - int partner = mdio_read(ioaddr, phy_num, 5); + int partner = mdio_read(dev, phy_num, MII_LPA); if (partner != sp->partner) { - int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0; + int flow_ctrl = sp->mii_if.advertising & partner & 0x0400 ? 1 : 0; if (speedo_debug > 2) { printk(KERN_DEBUG "%s: Link status change.\n", dev->name); printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n", - dev->name, sp->partner, partner, sp->advertising); + dev->name, sp->partner, partner, sp->mii_if.advertising); } sp->partner = partner; if (flow_ctrl != sp->flow_ctrl) { @@ -1146,9 +1183,9 @@ sp->rx_mode = -1; /* Trigger a reload. */ } /* Clear sticky bit. */ - mdio_read(ioaddr, phy_num, 1); + mdio_read(dev, phy_num, MII_BMSR); /* If link beat has returned... */ - if (mdio_read(ioaddr, phy_num, MII_BMSR) & BMSR_LSTATUS) + if (mdio_read(dev, phy_num, MII_BMSR) & BMSR_LSTATUS) netif_carrier_on(dev); else netif_carrier_off(dev); @@ -1214,7 +1251,7 @@ /* FIXME: what does it mean? --SAW */ if (i == 6) i = 21; printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n", - dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i)); + dev->name, phy_num, i, mdio_read(dev, phy_num, i)); } } #endif @@ -1306,22 +1343,22 @@ static void reset_mii(struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - long ioaddr = dev->base_addr; + /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ if ((sp->phy[0] & 0x8000) == 0) { int phy_addr = sp->phy[0] & 0x1f; - int advertising = mdio_read(ioaddr, phy_addr, 4); - int mii_bmcr = mdio_read(ioaddr, phy_addr, 0); - mdio_write(ioaddr, phy_addr, 0, 0x0400); - mdio_write(ioaddr, phy_addr, 1, 0x0000); - mdio_write(ioaddr, phy_addr, 4, 0x0000); - mdio_write(ioaddr, phy_addr, 0, 0x8000); + int advertising = mdio_read(dev, phy_addr, MII_ADVERTISE); + int mii_bmcr = mdio_read(dev, phy_addr, MII_BMCR); + mdio_write(dev, phy_addr, MII_BMCR, 0x0400); + mdio_write(dev, phy_addr, MII_BMSR, 0x0000); + mdio_write(dev, phy_addr, MII_ADVERTISE, 0x0000); + mdio_write(dev, phy_addr, MII_BMCR, 0x8000); #ifdef honor_default_port - mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]); + mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]); #else - mdio_read(ioaddr, phy_addr, 0); - mdio_write(ioaddr, phy_addr, 0, mii_bmcr); - mdio_write(ioaddr, phy_addr, 4, advertising); + mdio_read(dev, phy_addr, MII_BMCR); + mdio_write(dev, phy_addr, MII_BMCR, mii_bmcr); + mdio_write(dev, phy_addr, MII_ADVERTISE, advertising); #endif } } @@ -1886,8 +1923,6 @@ pci_set_power_state(sp->pdev, 2); - MOD_DEC_USE_COUNT; - return 0; } @@ -1941,6 +1976,7 @@ return -EFAULT; switch (ethcmd) { + /* get driver-specific version/etc. info */ case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; strncpy(info.driver, "eepro100", sizeof(info.driver)-1); @@ -1952,19 +1988,48 @@ return 0; } + /* get settings */ + case ETHTOOL_GSET: { + struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + spin_lock_irq(&sp->lock); + mii_ethtool_gset(&sp->mii_if, &ecmd); + spin_unlock_irq(&sp->lock); + if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } + /* set settings */ + case ETHTOOL_SSET: { + int r; + struct ethtool_cmd ecmd; + if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) + return -EFAULT; + spin_lock_irq(&sp->lock); + r = mii_ethtool_sset(&sp->mii_if, &ecmd); + spin_unlock_irq(&sp->lock); + return r; + } + /* restart autonegotiation */ + case ETHTOOL_NWAY_RST: { + return mii_nway_restart(&sp->mii_if); + } + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + edata.data = mii_link_ok(&sp->mii_if); + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + } return -EOPNOTSUPP; } - - - - static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - long ioaddr = dev->base_addr; struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phy = sp->phy[0] & 0x1f; int saved_acpi; @@ -1981,7 +2046,7 @@ timer routine. 2000/05/09 SAW */ saved_acpi = pci_set_power_state(sp->pdev, 0); t = del_timer_sync(&sp->timer); - data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f); + data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); if (t) add_timer(&sp->timer); /* may be set to the past --SAW */ pci_set_power_state(sp->pdev, saved_acpi); @@ -1992,7 +2057,7 @@ return -EPERM; saved_acpi = pci_set_power_state(sp->pdev, 0); t = del_timer_sync(&sp->timer); - mdio_write(ioaddr, data->phy_id, data->reg_num, data->val_in); + mdio_write(dev, data->phy_id, data->reg_num, data->val_in); if (t) add_timer(&sp->timer); /* may be set to the past --SAW */ pci_set_power_state(sp->pdev, saved_acpi); @@ -2064,7 +2129,7 @@ Disable Flow control since we are not ACK-ing any FC interrupts for now. --Dragan */ config_cmd_data[19] = 0x84; - config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0; + config_cmd_data[19] |= sp->mii_if.full_duplex ? 0x40 : 0; config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05; if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */ config_cmd_data[15] |= 0x80; diff -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c --- a/drivers/net/epic100.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/epic100.c Fri Sep 20 08:20:46 2002 @@ -1072,13 +1072,7 @@ if (txstatus & 0x0008) ep->stats.tx_carrier_errors++; if (txstatus & 0x0040) ep->stats.tx_window_errors++; if (txstatus & 0x0010) ep->stats.tx_fifo_errors++; -#ifdef ETHER_STATS - if (txstatus & 0x1000) ep->stats.collisions16++; -#endif } else { -#ifdef ETHER_STATS - if ((txstatus & 0x0002) != 0) ep->stats.tx_deferred++; -#endif ep->stats.collisions += (txstatus >> 8) & 15; ep->stats.tx_packets++; ep->stats.tx_bytes += ep->tx_skbuff[entry]->len; diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c --- a/drivers/net/fealnx.c Fri Sep 20 08:20:47 2002 +++ b/drivers/net/fealnx.c Fri Sep 20 08:20:47 2002 @@ -1493,16 +1493,7 @@ if ((tx_status & HF) && np->mii.full_duplex == 0) np->stats.tx_heartbeat_errors++; -#ifdef ETHER_STATS - if (tx_status & EC) - np->stats.collisions16++; -#endif } else { -#ifdef ETHER_STATS - if (tx_status & DFR) - np->stats.tx_deferred++; -#endif - np->stats.tx_bytes += ((tx_control & PKTSMask) >> PKTSShift); @@ -1544,9 +1535,6 @@ np->stats.tx_errors += (data & 0xff000000) >> 24; np->stats.tx_aborted_errors += (data & 0xff000000) >> 24; np->stats.tx_window_errors += (data & 0x00ff0000) >> 16; -#ifdef ETHER_STATS - np->stats.collisions16 += (data & 0xff000000) >> 24; -#endif np->stats.collisions += (data & 0x0000ffff); } diff -Nru a/drivers/net/hp100.c b/drivers/net/hp100.c --- a/drivers/net/hp100.c Fri Sep 20 08:20:44 2002 +++ b/drivers/net/hp100.c Fri Sep 20 08:20:44 2002 @@ -236,6 +236,9 @@ /* 10/100 ISA card with Cascade chip */ {0x5019F022, "HP J2573", HP100_BUS_ISA}, + /* 10/100 EISA card with AT&T chip */ + {0x9019f022, "HP J2577", HP100_BUS_EISA }, + /* 10/100 PCI card - old J2585A */ {0x1030103c, "HP J2585A", HP100_BUS_PCI}, @@ -1879,7 +1882,7 @@ #endif /* Now we allocate the skb and transfer the data into it. */ - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { /* Not enough memory->drop packet */ #ifdef HP100_DEBUG printk("hp100: %s: rx: couldn't allocate a sk_buff of size %d\n", @@ -1890,10 +1893,12 @@ u_char *ptr; + skb_reserve(skb,2); skb->dev = dev; /* ptr to start of the sk_buff data area */ - ptr = (u_char *) skb_put(skb, pkt_len); + skb_put(skb, pkt_len); + ptr = skb->data; /* Now transfer the data from the card into that area */ if (lp->mode == 2) { diff -Nru a/drivers/net/irda/act200l.c b/drivers/net/irda/act200l.c --- a/drivers/net/irda/act200l.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/irda/act200l.c Fri Sep 20 08:20:46 2002 @@ -158,7 +158,7 @@ } break; case IRDA_TASK_CHILD_WAIT: - WARNING(__FUNCTION__ "(), resetting dongle timed out!\n"); + WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__); ret = -1; break; case IRDA_TASK_CHILD_DONE: @@ -203,7 +203,7 @@ self->speed_task = NULL; break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->speed_task = NULL; ret = -1; @@ -269,7 +269,7 @@ self->reset_task = NULL; break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->reset_task = NULL; ret = -1; diff -Nru a/drivers/net/irda/actisys.c b/drivers/net/irda/actisys.c --- a/drivers/net/irda/actisys.c Fri Sep 20 08:20:49 2002 +++ b/drivers/net/irda/actisys.c Fri Sep 20 08:20:49 2002 @@ -259,7 +259,7 @@ self->speed = 9600; /* That's the default */ break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->reset_task = NULL; ret = -1; diff -Nru a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c --- a/drivers/net/irda/ali-ircc.c Fri Sep 20 08:20:44 2002 +++ b/drivers/net/irda/ali-ircc.c Fri Sep 20 08:20:44 2002 @@ -141,12 +141,12 @@ int reg, revision; int i = 0; - IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); /* Probe for all the ALi chipsets we know about */ for (chip= chips; chip->name; chip++, i++) { - IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", chip->name); + IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, chip->name); /* Try all config registers for this chip */ for (cfg=0; cfg<2; cfg++) @@ -176,13 +176,11 @@ if (reg == chip->cid_value) { - IRDA_DEBUG(2, __FUNCTION__ - "(), Chip found at 0x%03x\n", cfg_base); + IRDA_DEBUG(2, "%s(), Chip found at 0x%03x\n", __FUNCTION__, cfg_base); outb(0x1F, cfg_base); revision = inb(cfg_base+1); - IRDA_DEBUG(2, __FUNCTION__ - "(), Found %s chip, revision=%d\n", + IRDA_DEBUG(2, "%s(), Found %s chip, revision=%d\n", __FUNCTION__, chip->name, revision); /* @@ -205,15 +203,14 @@ } else { - IRDA_DEBUG(2, __FUNCTION__ - "(), No %s chip at 0x%03x\n", chip->name, cfg_base); + IRDA_DEBUG(2, "%s(), No %s chip at 0x%03x\n", __FUNCTION__, chip->name, cfg_base); } /* Exit configuration */ outb(0xbb, cfg_base); } } - IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n"); + IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); return ret; } @@ -227,7 +224,7 @@ { int i; - IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); pm_unregister_all(ali_ircc_pmproc); @@ -236,7 +233,7 @@ ali_ircc_close(dev_self[i]); } - IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n"); + IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); } /* @@ -251,9 +248,10 @@ struct ali_ircc_cb *self; struct pm_dev *pmdev; int dongle_id; + int ret; int err; - IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); /* Set FIR FIFO and DMA Threshold */ if ((ali_ircc_setup(info)) == -1) @@ -263,7 +261,7 @@ self = kmalloc(sizeof(struct ali_ircc_cb), GFP_KERNEL); if (self == NULL) { - ERROR(__FUNCTION__ "(), can't allocate memory for control block!\n"); + ERROR("%s(), can't allocate memory for control block!\n", __FUNCTION__); return -ENOMEM; } memset(self, 0, sizeof(struct ali_ircc_cb)); @@ -285,7 +283,7 @@ /* Reserve the ioports that we need */ ret = check_region(self->io.fir_base, self->io.fir_ext); if (ret < 0) { - WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", + WARNING("%s(), can't get iobase of 0x%03x\n", __FUNCTION__, self->io.fir_base); dev_self[i] = NULL; kfree(self); @@ -339,7 +337,7 @@ self->tx_fifo.tail = self->tx_buff.head; if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); return -ENOMEM; } @@ -358,14 +356,14 @@ err = register_netdevice(dev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); return -1; } MESSAGE("IrDA: Registered device %s\n", dev->name); /* Check dongle id */ dongle_id = ali_ircc_read_dongle_id(i, info); - MESSAGE(__FUNCTION__ "(), %s, Found dongle: %s\n", driver_name, dongle_types[dongle_id]); + MESSAGE("%s(), %s, Found dongle: %s\n", __FUNCTION__, driver_name, dongle_types[dongle_id]); self->io.dongle_id = dongle_id; @@ -373,7 +371,7 @@ if (pmdev) pmdev->data = self; - IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n"); + IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); return 0; } @@ -389,7 +387,7 @@ { int iobase; - IRDA_DEBUG(4, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__); ASSERT(self != NULL, return -1;); @@ -403,7 +401,7 @@ } /* Release the PORT that this driver is using */ - IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", self->io.fir_base); + IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", __FUNCTION__, self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) @@ -415,7 +413,7 @@ dev_self[self->index] = NULL; kfree(self); - IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n"); + IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); return 0; } @@ -458,7 +456,7 @@ int cfg_base = info->cfg_base; int hi, low, reg; - IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); /* Enter Configuration */ outb(chip->entr1, cfg_base); @@ -477,13 +475,13 @@ info->sir_base = info->fir_base; - IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", info->fir_base); + IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __FUNCTION__, info->fir_base); /* Read IRQ control register */ outb(0x70, cfg_base); reg = inb(cfg_base+1); info->irq = reg & 0x0f; - IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq); + IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq); /* Read DMA channel */ outb(0x74, cfg_base); @@ -491,26 +489,26 @@ info->dma = reg & 0x07; if(info->dma == 0x04) - WARNING(__FUNCTION__ "(), No DMA channel assigned !\n"); + WARNING("%s(), No DMA channel assigned !\n", __FUNCTION__); else - IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma); + IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma); /* Read Enabled Status */ outb(0x30, cfg_base); reg = inb(cfg_base+1); info->enabled = (reg & 0x80) && (reg & 0x01); - IRDA_DEBUG(2, __FUNCTION__ "(), probing enabled=%d\n", info->enabled); + IRDA_DEBUG(2, "%s(), probing enabled=%d\n", __FUNCTION__, info->enabled); /* Read Power Status */ outb(0x22, cfg_base); reg = inb(cfg_base+1); info->suspended = (reg & 0x20); - IRDA_DEBUG(2, __FUNCTION__ "(), probing suspended=%d\n", info->suspended); + IRDA_DEBUG(2, "%s(), probing suspended=%d\n", __FUNCTION__, info->suspended); /* Exit configuration */ outb(0xbb, cfg_base); - IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n"); + IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); return 0; } @@ -528,8 +526,13 @@ int version; int iobase = info->fir_base; - IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + /* Locking comments : + * Most operations here need to be protected. We are called before + * the device instance is created in ali_ircc_open(), therefore + * nobody can bother us - Jean II */ + /* Switch to FIR space */ SIR2FIR(iobase); @@ -584,7 +587,7 @@ // outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM // Turn on the interrupts in ali_ircc_net_open - IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); return 0; } @@ -601,7 +604,7 @@ int dongle_id, reg; int cfg_base = info->cfg_base; - IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); /* Enter Configuration */ outb(chips[i].entr1, cfg_base); @@ -615,13 +618,13 @@ outb(0xf0, cfg_base); reg = inb(cfg_base+1); dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01); - IRDA_DEBUG(2, __FUNCTION__ "(), probing dongle_id=%d, dongle_types=%s\n", + IRDA_DEBUG(2, "%s(), probing dongle_id=%d, dongle_types=%s\n", __FUNCTION__, dongle_id, dongle_types[dongle_id]); /* Exit configuration */ outb(0xbb, cfg_base); - IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); return dongle_id; } @@ -637,7 +640,7 @@ struct net_device *dev = (struct net_device *) dev_id; struct ali_ircc_cb *self; - IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); if (!dev) { WARNING("%s: irq %d for unknown device.\n", driver_name, irq); @@ -656,7 +659,7 @@ spin_unlock(&self->lock); - IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); } /* * Function ali_ircc_fir_interrupt(irq, struct ali_ircc_cb *self, regs) @@ -669,7 +672,7 @@ __u8 eir, OldMessageCount; int iobase, tmp; - IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__); iobase = self->io.fir_base; @@ -682,10 +685,10 @@ //self->ier = inb(iobase+FIR_IER); 2000/12/1 04:32PM eir = self->InterruptID & self->ier; /* Mask out the interesting ones */ - IRDA_DEBUG(1, __FUNCTION__ "(), self->InterruptID = %x\n",self->InterruptID); - IRDA_DEBUG(1, __FUNCTION__ "(), self->LineStatus = %x\n",self->LineStatus); - IRDA_DEBUG(1, __FUNCTION__ "(), self->ier = %x\n",self->ier); - IRDA_DEBUG(1, __FUNCTION__ "(), eir = %x\n",eir); + IRDA_DEBUG(1, "%s(), self->InterruptID = %x\n", __FUNCTION__,self->InterruptID); + IRDA_DEBUG(1, "%s(), self->LineStatus = %x\n", __FUNCTION__,self->LineStatus); + IRDA_DEBUG(1, "%s(), self->ier = %x\n", __FUNCTION__,self->ier); + IRDA_DEBUG(1, "%s(), eir = %x\n", __FUNCTION__,eir); /* Disable interrupts */ SetCOMInterrupts(self, FALSE); @@ -696,7 +699,7 @@ { if (self->io.direction == IO_XMIT) /* TX */ { - IRDA_DEBUG(1, __FUNCTION__ "(), ******* IIR_EOM (Tx) *******\n"); + IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Tx) *******\n", __FUNCTION__); if(ali_ircc_dma_xmit_complete(self)) { @@ -715,23 +718,23 @@ } else /* RX */ { - IRDA_DEBUG(1, __FUNCTION__ "(), ******* IIR_EOM (Rx) *******\n"); + IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Rx) *******\n", __FUNCTION__); if(OldMessageCount > ((self->LineStatus+1) & 0x07)) { self->rcvFramesOverflow = TRUE; - IRDA_DEBUG(1, __FUNCTION__ "(), ******* self->rcvFramesOverflow = TRUE ******** \n"); + IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******** \n", __FUNCTION__); } if (ali_ircc_dma_receive_complete(self)) { - IRDA_DEBUG(1, __FUNCTION__ "(), ******* receive complete ******** \n"); + IRDA_DEBUG(1, "%s(), ******* receive complete ******** \n", __FUNCTION__); self->ier = IER_EOM; } else { - IRDA_DEBUG(1, __FUNCTION__ "(), ******* Not receive complete ******** \n"); + IRDA_DEBUG(1, "%s(), ******* Not receive complete ******** \n", __FUNCTION__); self->ier = IER_EOM | IER_TIMER; } @@ -744,7 +747,7 @@ if(OldMessageCount > ((self->LineStatus+1) & 0x07)) { self->rcvFramesOverflow = TRUE; - IRDA_DEBUG(1, __FUNCTION__ "(), ******* self->rcvFramesOverflow = TRUE ******* \n"); + IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******* \n", __FUNCTION__); } /* Disable Timer */ switch_bank(iobase, BANK1); @@ -776,7 +779,7 @@ /* Restore Interrupt */ SetCOMInterrupts(self, TRUE); - IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ---------------\n"); + IRDA_DEBUG(1, "%s(), ----------------- End ---------------\n", __FUNCTION__); } /* @@ -790,7 +793,7 @@ int iobase; int iir, lsr; - IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); iobase = self->io.sir_base; @@ -799,14 +802,13 @@ /* Clear interrupt */ lsr = inb(iobase+UART_LSR); - IRDA_DEBUG(4, __FUNCTION__ - "(), iir=%02x, lsr=%02x, iobase=%#x\n", + IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", __FUNCTION__, iir, lsr, iobase); switch (iir) { case UART_IIR_RLSI: - IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n"); + IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__); break; case UART_IIR_RDI: /* Receive interrupt */ @@ -820,14 +822,14 @@ } break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir); + IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir); break; } } - IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); } @@ -842,7 +844,7 @@ int boguscount = 0; int iobase; - IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); ASSERT(self != NULL, return;); iobase = self->io.sir_base; @@ -857,7 +859,7 @@ /* Make sure we don't stay here to long */ if (boguscount++ > 32) { - IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n"); + IRDA_DEBUG(2,"%s(), breaking!\n", __FUNCTION__); break; } } while (inb(iobase+UART_LSR) & UART_LSR_DR); @@ -937,6 +939,9 @@ IRDA_DEBUG(2, __FUNCTION__ "(), setting speed = %d \n", baud); + /* This function *must* be called with irq off and spin-lock. + * - Jean II */ + iobase = self->io.fir_base; SetCOMInterrupts(self, FALSE); // 2000/11/24 11:43AM @@ -1084,7 +1089,6 @@ struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv; int iobase,dongle_id; - unsigned long flags; int tmp = 0; IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); @@ -1092,8 +1096,7 @@ iobase = self->io.fir_base; /* or iobase = self->io.sir_base; */ dongle_id = self->io.dongle_id; - save_flags(flags); - cli(); + /* We are already locked, no need to do it again */ IRDA_DEBUG(1, __FUNCTION__ "(), Set Speed for %s , Speed = %d\n", dongle_types[dongle_id], speed); @@ -1259,8 +1262,6 @@ switch_bank(iobase, BANK0); - restore_flags(flags); - IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); } @@ -1440,20 +1441,26 @@ netif_stop_queue(dev); + /* Make sure tests *& speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + + /* Note : you should make sure that speed changes are not going + * to corrupt any outgoing frame. Look at nsc-ircc for the gory + * details - Jean II */ + /* Check if we need to change the speed */ speed = irda_get_next_speed(skb); if ((speed != self->io.speed) && (speed != -1)) { /* Check for empty frame */ if (!skb->len) { ali_ircc_change_speed(self, speed); + spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; } else self->new_speed = speed; } - spin_lock_irqsave(&self->lock, flags); - /* Register and copy this frame to DMA memory */ self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; @@ -1651,7 +1658,7 @@ if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT) { - ERROR(__FUNCTION__ "(), ********* LSR_FRAME_ABORT *********\n"); + ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __FUNCTION__); self->stats.tx_errors++; self->stats.tx_fifo_errors++; } @@ -1898,8 +1905,8 @@ skb = dev_alloc_skb(len+1); if (skb == NULL) { - WARNING(__FUNCTION__ "(), memory squeeze, " - "dropping frame.\n"); + WARNING("%s(), memory squeeze, " + "dropping frame.\n", __FUNCTION__); self->stats.rx_dropped++; return FALSE; @@ -1957,20 +1964,26 @@ netif_stop_queue(dev); + /* Make sure tests *& speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + + /* Note : you should make sure that speed changes are not going + * to corrupt any outgoing frame. Look at nsc-ircc for the gory + * details - Jean II */ + /* Check if we need to change the speed */ speed = irda_get_next_speed(skb); if ((speed != self->io.speed) && (speed != -1)) { /* Check for empty frame */ if (!skb->len) { ali_ircc_change_speed(self, speed); + spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; } else self->new_speed = speed; } - spin_lock_irqsave(&self->lock, flags); - /* Init tx buffer */ self->tx_buff.data = self->tx_buff.head; @@ -2016,10 +2029,6 @@ IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); - /* Disable interrupts & save flags */ - save_flags(flags); - cli(); - switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ IRDA_DEBUG(1, __FUNCTION__ "(), SIOCSBANDWIDTH\n"); @@ -2031,7 +2040,9 @@ if (!in_interrupt() && !capable(CAP_NET_ADMIN)) return -EPERM; + spin_lock_irqsave(&self->lock, flags); ali_ircc_change_speed(self, irq->ifr_baudrate); + spin_unlock_irqrestore(&self->lock, flags); break; case SIOCSMEDIABUSY: /* Set media busy */ IRDA_DEBUG(1, __FUNCTION__ "(), SIOCSMEDIABUSY\n"); @@ -2041,14 +2052,13 @@ break; case SIOCGRECEIVING: /* Check if we are receiving right now */ IRDA_DEBUG(2, __FUNCTION__ "(), SIOCGRECEIVING\n"); + /* This is protected */ irq->ifr_receiving = ali_ircc_is_receiving(self); break; default: ret = -EOPNOTSUPP; } - restore_flags(flags); - IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); return ret; @@ -2219,19 +2229,16 @@ static void SIR2FIR(int iobase) { //unsigned char tmp; - unsigned long flags; IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); - save_flags(flags); - cli(); + /* Already protected (change_speed() or setup()), no need to lock. + * Jean II */ outb(0x28, iobase+UART_MCR); outb(0x68, iobase+UART_MCR); outb(0x88, iobase+UART_MCR); - restore_flags(flags); - outb(0x60, iobase+FIR_MCR); /* Master Reset */ outb(0x20, iobase+FIR_MCR); /* Master Interrupt Enable */ @@ -2245,12 +2252,11 @@ static void FIR2SIR(int iobase) { unsigned char val; - unsigned long flags; IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); - save_flags(flags); - cli(); + /* Already protected (change_speed() or setup()), no need to lock. + * Jean II */ outb(0x20, iobase+FIR_MCR); /* IRQ to low */ outb(0x00, iobase+UART_IER); @@ -2262,8 +2268,6 @@ val = inb(iobase+UART_RX); val = inb(iobase+UART_LSR); val = inb(iobase+UART_MSR); - - restore_flags(flags); IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); } diff -Nru a/drivers/net/irda/girbil.c b/drivers/net/irda/girbil.c --- a/drivers/net/irda/girbil.c Fri Sep 20 08:20:41 2002 +++ b/drivers/net/irda/girbil.c Fri Sep 20 08:20:41 2002 @@ -129,7 +129,7 @@ } break; case IRDA_TASK_CHILD_WAIT: - WARNING(__FUNCTION__ "(), resetting dongle timed out!\n"); + WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__); ret = -1; break; case IRDA_TASK_CHILD_DONE: @@ -168,7 +168,7 @@ self->speed_task = NULL; break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->speed_task = NULL; ret = -1; @@ -221,7 +221,7 @@ self->reset_task = NULL; break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->reset_task = NULL; ret = -1; diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c --- a/drivers/net/irda/irda-usb.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/irda/irda-usb.c Fri Sep 20 08:20:46 2002 @@ -1171,7 +1171,7 @@ irda_usb_init_qos(self); /* Initialise list of skb beeing curently transmitted */ - self->tx_list = hashbin_new(HB_GLOBAL); + self->tx_list = hashbin_new(HB_NOLOCK); /* unused */ /* Allocate the buffer for speed changes */ /* Don't change this buffer size and allocation without doing diff -Nru a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c --- a/drivers/net/irda/irport.c Fri Sep 20 08:20:42 2002 +++ b/drivers/net/irda/irport.c Fri Sep 20 08:20:42 2002 @@ -124,7 +124,7 @@ { int i; - IRDA_DEBUG( 4, __FUNCTION__ "()\n"); + IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); for (i=0; i < 4; i++) { if (dev_self[i]) @@ -140,15 +140,15 @@ void *ret; int err; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); /* * Allocate new instance of the driver */ self = kmalloc(sizeof(struct irport_cb), GFP_KERNEL); if (!self) { - ERROR(__FUNCTION__ "(), can't allocate memory for " - "control block!\n"); + ERROR("%s(), can't allocate memory for " + "control block!\n", __FUNCTION__); return NULL; } memset(self, 0, sizeof(struct irport_cb)); @@ -168,8 +168,8 @@ /* Lock the port that we need */ ret = request_region(self->io.sir_base, self->io.sir_ext, driver_name); if (!ret) { - IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.sir_base); + IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n", + __FUNCTION__, self->io.sir_base); return NULL; } @@ -212,7 +212,7 @@ self->mode = IRDA_IRLAP; if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); return NULL; } self->netdev = dev; @@ -240,7 +240,7 @@ err = register_netdevice(dev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); return NULL; } MESSAGE("IrDA: Registered device %s\n", dev->name); @@ -265,8 +265,8 @@ } /* Release the IO-port that this driver is using */ - IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", - self->io.sir_base); + IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", + __FUNCTION__, self->io.sir_base); release_region(self->io.sir_base, self->io.sir_ext); if (self->tx_buff.head) @@ -284,14 +284,13 @@ void irport_start(struct irport_cb *self) { - unsigned long flags; int iobase; iobase = self->io.sir_base; irport_stop(self); - spin_lock_irqsave(&self->lock, flags); + /* We can't lock, we may be called from a FIR driver - Jean II */ /* Initialize UART */ outb(UART_LCR_WLEN8, iobase+UART_LCR); /* Reset DLAB */ @@ -299,26 +298,21 @@ /* Turn on interrups */ outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER); - - spin_unlock_irqrestore(&self->lock, flags); } void irport_stop(struct irport_cb *self) { - unsigned long flags; int iobase; iobase = self->io.sir_base; - spin_lock_irqsave(&self->lock, flags); + /* We can't lock, we may be called from a FIR driver - Jean II */ /* Reset UART */ outb(0, iobase+UART_MCR); /* Turn off interrupts */ outb(0, iobase+UART_IER); - - spin_unlock_irqrestore(&self->lock, flags); } /* @@ -329,7 +323,7 @@ */ int irport_probe(int iobase) { - IRDA_DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase); + IRDA_DEBUG(4, "%s(), iobase=%#x\n", __FUNCTION__, iobase); return 0; } @@ -339,27 +333,28 @@ * * Set speed of IrDA port to specified baudrate * + * This function should be called with irq off and spin-lock. */ void irport_change_speed(void *priv, __u32 speed) { struct irport_cb *self = (struct irport_cb *) priv; - unsigned long flags; int iobase; int fcr; /* FIFO control reg */ int lcr; /* Line control reg */ int divisor; - IRDA_DEBUG(0, __FUNCTION__ "(), Setting speed to: %d\n", speed); - ASSERT(self != NULL, return;); + IRDA_DEBUG(1, "%s(), Setting speed to: %d - iobase=%#x\n", + __FUNCTION__, speed, self->io.sir_base); + + /* We can't lock, we may be called from a FIR driver - Jean II */ + iobase = self->io.sir_base; /* Update accounting for new speed */ self->io.speed = speed; - spin_lock_irqsave(&self->lock, flags); - /* Turn off interrupts */ outb(0, iobase+UART_IER); @@ -387,9 +382,9 @@ outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ /* Turn on interrups */ - outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER); - - spin_unlock_irqrestore(&self->lock, flags); + /* This will generate a fata interrupt storm. + * People calling us will do that properly - Jean II */ + //outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER); } /* @@ -397,19 +392,33 @@ * * State machine for changing speed of the device. We do it this way since * we cannot use schedule_timeout() when we are in interrupt context + * */ int __irport_change_speed(struct irda_task *task) { struct irport_cb *self; __u32 speed = (__u32) task->param; + unsigned long flags = 0; + int wasunlocked = 0; int ret = 0; - IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies); + IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); self = (struct irport_cb *) task->instance; ASSERT(self != NULL, return -1;); + /* Locking notes : this function may be called from irq context with + * spinlock, via irport_write_wakeup(), or from non-interrupt without + * spinlock (from the task timer). Yuck ! + * This is ugly, and unsafe is the spinlock is not already aquired. + * This will be fixed when irda-task get rewritten. + * Jean II */ + if (!spin_is_locked(&self->lock)) { + spin_lock_irqsave(&self->lock, flags); + wasunlocked = 1; + } + switch (task->state) { case IRDA_TASK_INIT: case IRDA_TASK_WAIT: @@ -446,8 +455,7 @@ irda_task_next_state(task, IRDA_TASK_CHILD_DONE); break; case IRDA_TASK_CHILD_WAIT: - WARNING(__FUNCTION__ - "(), changing speed of dongle timed out!\n"); + WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__); ret = -1; break; case IRDA_TASK_CHILD_DONE: @@ -457,11 +465,16 @@ irda_task_next_state(task, IRDA_TASK_DONE); break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); ret = -1; break; } + /* Put stuff in the sate we found them - Jean II */ + if(wasunlocked) { + spin_unlock_irqrestore(&self->lock, flags); + } + return ret; } @@ -480,7 +493,7 @@ ASSERT(self != NULL, return;); - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); iobase = self->io.sir_base; @@ -491,6 +504,9 @@ self->tx_buff.data, self->tx_buff.len); self->tx_buff.data += actual; self->tx_buff.len -= actual; + + /* Turn on transmit finished interrupt. */ + outb(UART_IER_THRI, iobase+UART_IER); } else { /* * Now serial buffer is almost free & we can start @@ -498,11 +514,12 @@ * if we need to change the speed of the hardware */ if (self->new_speed) { - IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n"); + IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__); irda_task_execute(self, __irport_change_speed, irport_change_speed_complete, NULL, (void *) self->new_speed); self->new_speed = 0; + IRDA_DEBUG(5, "%s(), Speed changed!\n", __FUNCTION__ ); } else { /* Tell network layer that we want more frames */ netif_wake_queue(self->netdev); @@ -538,7 +555,7 @@ /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - IRDA_DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n"); + IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n", __FUNCTION__); return 0; } @@ -563,7 +580,7 @@ { struct irport_cb *self; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); self = (struct irport_cb *) task->instance; @@ -589,13 +606,19 @@ { struct irport_cb *self; int iobase; + unsigned long flags; self = (struct irport_cb *) dev->priv; iobase = self->io.sir_base; WARNING("%s: transmit timed out\n", dev->name); + spin_lock_irqsave(&self->lock, flags); irport_start(self); self->change_speed(self->priv, self->io.speed); + /* This will re-enable irqs */ + outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER); + spin_unlock_irqrestore(&self->lock, flags); + dev->trans_start = jiffies; netif_wake_queue(dev); } @@ -614,7 +637,7 @@ int iobase; s32 speed; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); ASSERT(dev != NULL, return 0;); @@ -625,22 +648,25 @@ netif_stop_queue(dev); + /* Make sure tests *& speed change are atomic */ + spin_lock_irqsave(&self->lock, flags); + /* Check if we need to change the speed */ speed = irda_get_next_speed(skb); if ((speed != self->io.speed) && (speed != -1)) { /* Check for empty frame */ if (!skb->len) { + /* Better go there already locked - Jean II */ irda_task_execute(self, __irport_change_speed, irport_change_speed_complete, NULL, (void *) speed); + spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; } else self->new_speed = speed; } - spin_lock_irqsave(&self->lock, flags); - /* Init tx buffer */ self->tx_buff.data = self->tx_buff.head; @@ -685,7 +711,7 @@ /* Make sure we don't stay here to long */ if (boguscount++ > 32) { - IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n"); + IRDA_DEBUG(2,"%s(), breaking!\n", __FUNCTION__); break; } } while (inb(iobase+UART_LSR) & UART_LSR_DR); @@ -705,7 +731,7 @@ int iir, lsr; if (!dev) { - WARNING(__FUNCTION__ "() irq %d for unknown device.\n", irq); + WARNING("%s() irq %d for unknown device.\n", __FUNCTION__, irq); return; } self = (struct irport_cb *) dev->priv; @@ -719,13 +745,12 @@ /* Clear interrupt */ lsr = inb(iobase+UART_LSR); - IRDA_DEBUG(4, __FUNCTION__ - "(), iir=%02x, lsr=%02x, iobase=%#x\n", - iir, lsr, iobase); + IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", + __FUNCTION__, iir, lsr, iobase); switch (iir) { case UART_IIR_RLSI: - IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n"); + IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__); break; case UART_IIR_RDI: /* Receive interrupt */ @@ -737,7 +762,7 @@ irport_write_wakeup(self); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir); + IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir); break; } @@ -771,8 +796,9 @@ struct irport_cb *self; int iobase; char hwname[16]; + unsigned long flags; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); ASSERT(dev != NULL, return -1;); self = (struct irport_cb *) dev->priv; @@ -781,12 +807,14 @@ if (request_irq(self->io.irq, self->interrupt, 0, dev->name, (void *) dev)) { - IRDA_DEBUG(0, __FUNCTION__ "(), unable to allocate irq=%d\n", - self->io.irq); + IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n", + __FUNCTION__, self->io.irq); return -EAGAIN; } + spin_lock_irqsave(&self->lock, flags); irport_start(self); + spin_unlock_irqrestore(&self->lock, flags); /* Give self a hardware name */ @@ -818,8 +846,9 @@ { struct irport_cb *self; int iobase; + unsigned long flags; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(dev != NULL, return -1;); self = (struct irport_cb *) dev->priv; @@ -836,7 +865,9 @@ irlap_close(self->irlap); self->irlap = NULL; + spin_lock_irqsave(&self->lock, flags); irport_stop(self); + spin_unlock_irqrestore(&self->lock, flags); free_irq(self->io.irq, dev); @@ -860,7 +891,7 @@ /* Wait until Tx FIFO is empty */ while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - IRDA_DEBUG(2, __FUNCTION__ "(), waiting!\n"); + IRDA_DEBUG(2, "%s(), waiting!\n", __FUNCTION__); current->state = TASK_INTERRUPTIBLE; schedule_timeout(MSECS_TO_JIFFIES(60)); } @@ -915,7 +946,7 @@ /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - IRDA_DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n"); + IRDA_DEBUG( 0, "%s(), failed, fifo not empty!\n", __FUNCTION__); return -1; } @@ -949,11 +980,7 @@ ASSERT(self != NULL, return -1;); - IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); - - /* Disable interrupts & save flags */ - save_flags(flags); - cli(); + IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ @@ -979,14 +1006,16 @@ dongle->write = irport_raw_write; dongle->set_dtr_rts = irport_set_dtr_rts; - self->dongle = dongle; - /* Now initialize the dongle! */ dongle->issue->open(dongle, &self->qos); /* Reset dongle */ irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, NULL); + + /* Make dongle available to driver only now to avoid + * race conditions - Jean II */ + self->dongle = dongle; break; case SIOCSMEDIABUSY: /* Set media busy */ if (!capable(CAP_NET_ADMIN)) { @@ -1005,13 +1034,14 @@ break; } + /* No real need to lock... */ + spin_lock_irqsave(&self->lock, flags); irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); + spin_unlock_irqrestore(&self->lock, flags); break; default: ret = -EOPNOTSUPP; } - - restore_flags(flags); return ret; } diff -Nru a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c --- a/drivers/net/irda/irtty.c Fri Sep 20 08:20:43 2002 +++ b/drivers/net/irda/irtty.c Fri Sep 20 08:20:43 2002 @@ -74,8 +74,10 @@ int __init irtty_init(void) { int status; - - irtty = hashbin_new( HB_LOCAL); + + /* Probably no need to lock here because all operations done in + * open()/close() which are already safe - Jean II */ + irtty = hashbin_new( HB_NOLOCK); if ( irtty == NULL) { printk( KERN_WARNING "IrDA: Can't allocate irtty hashbin!\n"); return -ENOMEM; @@ -118,9 +120,8 @@ /* Unregister tty line-discipline */ if ((ret = tty_register_ldisc(N_IRDA, NULL))) { - ERROR(__FUNCTION__ - "(), can't unregister line discipline (err = %d)\n", - ret); + ERROR("%s(), can't unregister line discipline (err = %d)\n", + __FUNCTION__, ret); } /* @@ -163,6 +164,7 @@ return -ENOMEM; } memset(self, 0, sizeof(struct irtty_cb)); + spin_lock_init(&self->lock); self->tty = tty; tty->disc_data = self; @@ -226,7 +228,7 @@ self->rx_buff.data = self->rx_buff.head; if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); return -ENOMEM; } @@ -245,7 +247,7 @@ err = register_netdevice(dev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); return -1; } @@ -266,11 +268,12 @@ static void irtty_close(struct tty_struct *tty) { struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; + unsigned long flags; /* First make sure we're connected. */ ASSERT(self != NULL, return;); ASSERT(self->magic == IRTTY_MAGIC, return;); - + /* Stop tty */ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); tty->disc_data = 0; @@ -287,6 +290,11 @@ rtnl_unlock(); } + self = hashbin_remove(irtty, (int) self, NULL); + + /* Protect access to self->task and self->?x_buff - Jean II */ + spin_lock_irqsave(&self->lock, flags); + /* Remove speed changing task if any */ if (self->task) irda_task_delete(self->task); @@ -294,13 +302,12 @@ self->tty = NULL; self->magic = 0; - self = hashbin_remove(irtty, (int) self, NULL); - if (self->tx_buff.head) kfree(self->tx_buff.head); if (self->rx_buff.head) kfree(self->rx_buff.head); + spin_unlock_irqrestore(&self->lock, flags); kfree(self); @@ -326,6 +333,7 @@ else cflag |= CREAD; + /* This is unsafe, but currently under discussion - Jean II */ self->tty->termios->c_cflag = cflag; self->tty->driver.set_termios(self->tty, &old_termios); } @@ -378,6 +386,7 @@ break; } + /* This is unsafe, but currently under discussion - Jean II */ self->tty->termios->c_cflag = cflag; self->tty->driver.set_termios(self->tty, &old_termios); @@ -393,6 +402,7 @@ static int irtty_change_speed(struct irda_task *task) { struct irtty_cb *self; + unsigned long flags; __u32 speed = (__u32) task->param; int ret = 0; @@ -401,12 +411,17 @@ self = (struct irtty_cb *) task->instance; ASSERT(self != NULL, return -1;); + /* Protect access to self->task - Jean II */ + spin_lock_irqsave(&self->lock, flags); + /* Check if busy */ if (self->task && self->task != task) { IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n"); + spin_unlock_irqrestore(&self->lock, flags); return MSECS_TO_JIFFIES(10); } else self->task = task; + spin_unlock_irqrestore(&self->lock, flags); switch (task->state) { case IRDA_TASK_INIT: @@ -451,8 +466,7 @@ irda_task_next_state(task, IRDA_TASK_CHILD_DONE); break; case IRDA_TASK_CHILD_WAIT: - WARNING(__FUNCTION__ - "(), changing speed of dongle timed out!\n"); + WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__); ret = -1; break; case IRDA_TASK_CHILD_DONE: @@ -463,7 +477,7 @@ self->task = NULL; break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->task = NULL; ret = -1; @@ -501,6 +515,7 @@ switch (cmd) { case TCGETS: case TCGETA: + /* Unsure about locking here, to check - Jean II */ return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg); break; @@ -516,15 +531,16 @@ dongle->write = irtty_raw_write; dongle->set_dtr_rts = irtty_set_dtr_rts; - /* Bind dongle */ - self->dongle = dongle; - /* Now initialize the dongle! */ dongle->issue->open(dongle, &self->qos); /* Reset dongle */ irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, NULL); + + /* Make dongle available to driver only now to avoid + * race conditions - Jean II */ + self->dongle = dongle; break; case IRTTY_IOCGET: ASSERT(self->netdev != NULL, return -1;); @@ -559,6 +575,9 @@ return; } + // Are we in interrupt context ? What locking is done ? - Jean II + //spin_lock_irqsave(&self->lock, flags); + /* Read the characters out of the buffer */ while (count--) { /* @@ -589,6 +608,7 @@ break; } } + //spin_unlock_irqrestore(&self->lock, flags); } /* @@ -626,11 +646,13 @@ struct irtty_cb *self; int actual = 0; __s32 speed; + unsigned long flags; self = (struct irtty_cb *) dev->priv; ASSERT(self != NULL, return 0;); - /* Lock transmit buffer */ + /* Lock transmit buffer + * this serialise operations, no need to spinlock - Jean II */ netif_stop_queue(dev); /* Check if we need to change the speed */ @@ -647,6 +669,9 @@ self->new_speed = speed; } + /* Protect access to self->tx_buff - Jean II */ + spin_lock_irqsave(&self->lock, flags); + /* Init tx buffer*/ self->tx_buff.data = self->tx_buff.head; @@ -667,6 +692,8 @@ self->tx_buff.data += actual; self->tx_buff.len -= actual; + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); return 0; @@ -695,6 +722,7 @@ { struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; int actual = 0; + unsigned long flags; /* * First make sure we're connected. @@ -702,6 +730,11 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == IRTTY_MAGIC, return;); + /* Protected via netif_stop_queue(dev); - Jean II */ + + /* Protect access to self->tx_buff - Jean II */ + spin_lock_irqsave(&self->lock, flags); + /* Finished with frame? */ if (self->tx_buff.len > 0) { /* Write data left in transmit buffer */ @@ -710,6 +743,7 @@ self->tx_buff.data += actual; self->tx_buff.len -= actual; + spin_unlock_irqrestore(&self->lock, flags); } else { /* * Now serial buffer is almost free & we can start @@ -721,6 +755,9 @@ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + /* Don't change speed with irq off */ + spin_unlock_irqrestore(&self->lock, flags); + if (self->new_speed) { IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n"); irda_task_execute(self, irtty_change_speed, @@ -755,12 +792,17 @@ { struct irtty_cb *self; struct tty_struct *tty; + //unsigned long flags; mm_segment_t fs; int arg = 0; self = (struct irtty_cb *) dev->priv; tty = self->tty; + /* Was protected in ioctl handler, but the serial driver doesn't + * like it. This may need to change. - Jean II */ + //spin_lock_irqsave(&self->lock, flags); + #ifdef TIOCM_OUT2 /* Not defined for ARM */ arg = TIOCM_OUT2; #endif @@ -780,11 +822,14 @@ fs = get_fs(); set_fs(get_ds()); + /* This is probably unsafe, but currently under discussion - Jean II */ if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { IRDA_DEBUG(2, __FUNCTION__ "(), error doing ioctl!\n"); } set_fs(fs); + //spin_unlock_irqrestore(&self->lock, flags); + return 0; } @@ -799,13 +844,17 @@ int irtty_set_mode(struct net_device *dev, int mode) { struct irtty_cb *self; + unsigned long flags; self = (struct irtty_cb *) dev->priv; ASSERT(self != NULL, return -1;); IRDA_DEBUG(2, __FUNCTION__ "(), mode=%s\n", infrared_mode[mode]); - + + /* Protect access to self->rx_buff - Jean II */ + spin_lock_irqsave(&self->lock, flags); + /* save status for driver */ self->mode = mode; @@ -814,6 +863,8 @@ self->rx_buff.len = 0; self->rx_buff.state = OUTSIDE_FRAME; + spin_unlock_irqrestore(&self->lock, flags); + return 0; } @@ -955,7 +1006,6 @@ struct if_irda_req *irq = (struct if_irda_req *) rq; struct irtty_cb *self; dongle_t *dongle; - unsigned long flags; int ret = 0; ASSERT(dev != NULL, return -1;); @@ -971,8 +1021,7 @@ * irda_device_dongle_init() can't be locked. * irda_task_execute() doesn't need to be locked (but * irtty_change_speed() should protect itself). - * As this driver doesn't have spinlock protection, keep - * old fashion locking :-( + * Other calls protect themselves. * Jean II */ @@ -1025,20 +1074,14 @@ if (!capable(CAP_NET_ADMIN)) ret = -EPERM; else { - save_flags(flags); - cli(); irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); - restore_flags(flags); } break; case SIOCSMODE: if (!capable(CAP_NET_ADMIN)) ret = -EPERM; else { - save_flags(flags); - cli(); irtty_set_mode(dev, irq->ifr_mode); - restore_flags(flags); } break; default: diff -Nru a/drivers/net/irda/mcp2120.c b/drivers/net/irda/mcp2120.c --- a/drivers/net/irda/mcp2120.c Fri Sep 20 08:20:48 2002 +++ b/drivers/net/irda/mcp2120.c Fri Sep 20 08:20:48 2002 @@ -109,7 +109,7 @@ } break; case IRDA_TASK_CHILD_WAIT: - WARNING(__FUNCTION__ "(), resetting dongle timed out!\n"); + WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__); ret = -1; break; case IRDA_TASK_CHILD_DONE: @@ -157,7 +157,7 @@ //printk("mcp2120_change_speed irda_task_wait\n"); break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->speed_task = NULL; ret = -1; @@ -212,7 +212,7 @@ self->reset_task = NULL; break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->reset_task = NULL; ret = -1; diff -Nru a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c --- a/drivers/net/irda/nsc-ircc.c Fri Sep 20 08:20:41 2002 +++ b/drivers/net/irda/nsc-ircc.c Fri Sep 20 08:20:41 2002 @@ -161,7 +161,7 @@ /* Probe for all the NSC chipsets we know about */ for (chip=chips; chip->name ; chip++) { - IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", + IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, chip->name); /* Try all config registers for this chip */ @@ -179,8 +179,7 @@ /* Read index register */ reg = inb(cfg_base); if (reg == 0xff) { - IRDA_DEBUG(2, __FUNCTION__ - "() no chip at 0x%03x\n", cfg_base); + IRDA_DEBUG(2, "%s() no chip at 0x%03x\n", __FUNCTION__, cfg_base); continue; } @@ -188,9 +187,8 @@ outb(chip->cid_index, cfg_base); id = inb(cfg_base+1); if ((id & chip->cid_mask) == chip->cid_value) { - IRDA_DEBUG(2, __FUNCTION__ - "() Found %s chip, revision=%d\n", - chip->name, id & ~chip->cid_mask); + IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n", + __FUNCTION__, chip->name, id & ~chip->cid_mask); /* * If the user supplies the base address, then * we init the chip, if not we probe the values @@ -205,8 +203,7 @@ ret = 0; i++; } else { - IRDA_DEBUG(2, __FUNCTION__ - "(), Wrong chip id=0x%02x\n", id); + IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id); } } @@ -247,7 +244,7 @@ void *ret; int err; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, info->cfg_base); @@ -260,8 +257,8 @@ /* Allocate new instance of the driver */ self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL); if (self == NULL) { - ERROR(__FUNCTION__ "(), can't allocate memory for " - "control block!\n"); + ERROR("%s(), can't allocate memory for " + "control block!\n", __FUNCTION__); return -ENOMEM; } memset(self, 0, sizeof(struct nsc_ircc_cb)); @@ -282,8 +279,8 @@ /* Reserve the ioports that we need */ ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name); if (!ret) { - WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.fir_base); + WARNING("%s(), can't get iobase of 0x%03x\n", + __FUNCTION__, self->io.fir_base); dev_self[i] = NULL; kfree(self); return -ENODEV; @@ -333,7 +330,7 @@ self->tx_fifo.tail = self->tx_buff.head; if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); return -ENOMEM; } @@ -352,7 +349,7 @@ err = register_netdevice(dev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); return -1; } MESSAGE("IrDA: Registered device %s\n", dev->name); @@ -388,7 +385,7 @@ { int iobase; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); @@ -402,8 +399,8 @@ } /* Release the PORT that this driver is using */ - IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", - self->io.fir_base); + IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", + __FUNCTION__, self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) @@ -439,7 +436,7 @@ case 0x2e8: outb(0x15, cfg_base+1); break; case 0x3f8: outb(0x16, cfg_base+1); break; case 0x2f8: outb(0x17, cfg_base+1); break; - default: ERROR(__FUNCTION__ "(), invalid base_address"); + default: ERROR("%s(), invalid base_address", __FUNCTION__); } /* Control Signal Routing Register (CSRT) */ @@ -451,7 +448,7 @@ case 9: temp = 0x05; break; case 11: temp = 0x06; break; case 15: temp = 0x07; break; - default: ERROR(__FUNCTION__ "(), invalid irq"); + default: ERROR("%s(), invalid irq", __FUNCTION__); } outb(1, cfg_base); @@ -459,7 +456,7 @@ case 0: outb(0x08+temp, cfg_base+1); break; case 1: outb(0x10+temp, cfg_base+1); break; case 3: outb(0x18+temp, cfg_base+1); break; - default: ERROR(__FUNCTION__ "(), invalid dma"); + default: ERROR("%s(), invalid dma", __FUNCTION__); } outb(2, cfg_base); /* Mode Control Register (MCTL) */ @@ -498,7 +495,7 @@ break; } info->sir_base = info->fir_base; - IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", + IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __FUNCTION__, info->fir_base); /* Read control signals routing register (CSRT) */ @@ -531,7 +528,7 @@ info->irq = 15; break; } - IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq); + IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq); /* Currently we only read Rx DMA but it will also be used for Tx */ switch ((reg >> 3) & 0x03) { @@ -548,7 +545,7 @@ info->dma = 3; break; } - IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma); + IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma); /* Read mode control register (MCTL) */ outb(CFG_MCTL, cfg_base); @@ -694,8 +691,8 @@ switch_bank(iobase, BANK3); version = inb(iobase+MID); - IRDA_DEBUG(2, __FUNCTION__ "() Driver %s Found chip version %02x\n", - driver_name, version); + IRDA_DEBUG(2, "%s() Driver %s Found chip version %02x\n", + __FUNCTION__, driver_name, version); /* Should be 0x2? */ if (0x20 != (version & 0xf0)) { @@ -797,39 +794,39 @@ switch (dongle_id) { case 0x00: /* same as */ case 0x01: /* Differential serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x02: /* same as */ case 0x03: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x04: /* Sharp RY5HD01 */ break; case 0x05: /* Reserved, but this is what the Thinkpad reports */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x06: /* Single-ended serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x07: /* Consumer-IR only */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ outb(0x28, iobase+7); /* Set irsl[0-2] as output */ break; case 0x0A: /* same as */ case 0x0B: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x0C: /* same as */ case 0x0D: /* HP HSDL-1100/HSDL-2100 */ @@ -843,15 +840,15 @@ outb(0x28, iobase+7); /* Set irsl[0-2] as output */ break; case 0x0F: /* No dongle connected */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s\n", + __FUNCTION__, dongle_types[dongle_id]); switch_bank(iobase, BANK0); outb(0x62, iobase+MCR); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", - dongle_id); + IRDA_DEBUG(0, "%s(), invalid dongle_id %#x", + __FUNCTION__, dongle_id); } /* IRCFG1: IRSL1 and 2 are set to IrDA mode */ @@ -870,7 +867,6 @@ */ static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id) { - unsigned long flags; __u8 bank; /* Save current bank */ @@ -883,31 +879,31 @@ switch (dongle_id) { case 0x00: /* same as */ case 0x01: /* Differential serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x02: /* same as */ case 0x03: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x04: /* Sharp RY5HD01 */ break; case 0x05: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x06: /* Single-ended serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x07: /* Consumer-IR only */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s\n", + __FUNCTION__, dongle_types[dongle_id]); outb(0x00, iobase+4); if (speed > 115200) outb(0x01, iobase+4); @@ -916,11 +912,10 @@ outb(0x01, iobase+4); if (speed == 4000000) { - save_flags(flags); - cli(); + /* There was a cli() there, but we now are already + * under spin_lock_irqsave() - JeanII */ outb(0x81, iobase+4); outb(0x80, iobase+4); - restore_flags(flags); } else outb(0x00, iobase+4); break; @@ -1538,8 +1533,8 @@ skb = dev_alloc_skb(len+1); if (skb == NULL) { - WARNING(__FUNCTION__ "(), memory squeeze, " - "dropping frame.\n"); + WARNING("%s(), memory squeeze, " + "dropping frame.\n", __FUNCTION__); self->stats.rx_dropped++; /* Restore bank register */ @@ -1960,33 +1955,30 @@ IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); - /* Disable interrupts & save flags */ - save_flags(flags); - cli(); - switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; - goto out; + break; } + spin_lock_irqsave(&self->lock, flags); nsc_ircc_change_speed(self, irq->ifr_baudrate); + spin_unlock_irqrestore(&self->lock, flags); break; case SIOCSMEDIABUSY: /* Set media busy */ if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; - goto out; + break; } irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ + /* This is already protected */ irq->ifr_receiving = nsc_ircc_is_receiving(self); break; default: ret = -EOPNOTSUPP; } -out: - restore_flags(flags); return ret; } diff -Nru a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c --- a/drivers/net/irda/smc-ircc.c Fri Sep 20 08:20:41 2002 +++ b/drivers/net/irda/smc-ircc.c Fri Sep 20 08:20:41 2002 @@ -431,6 +431,7 @@ struct ircc_cb *self; struct irport_cb *irport; unsigned char low, high, chip, config, dma, irq, version; + unsigned long flags; IRDA_DEBUG(0, __FUNCTION__ "\n"); @@ -484,7 +485,6 @@ return -ENOMEM; } memset(self, 0, sizeof(struct ircc_cb)); - spin_lock_init(&self->lock); /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ self->rx_buff.truesize = 4000; @@ -555,6 +555,9 @@ request_region(self->io->fir_base, CHIP_IO_EXTENT, driver_name); + /* Don't allow irport to change under us - Jean II */ + spin_lock_irqsave(&self->irport->lock, flags); + /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&irport->qos); @@ -581,6 +584,7 @@ self->netdev->stop = &ircc_net_close; irport_start(self->irport); + spin_unlock_irqrestore(&self->irport->lock, flags); self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, ircc_pmproc); if (self->pmdev) @@ -598,6 +602,7 @@ * * Change the speed of the device * + * This function should be called with irq off and spin-lock. */ static void ircc_change_speed(void *priv, u32 speed) { @@ -658,6 +663,7 @@ /* Make special FIR init if necessary */ if (speed > 115200) { + /* No need to lock, already locked - Jean II */ irport_stop(self->irport); /* Install FIR transmit handler */ @@ -674,6 +680,7 @@ } else { /* Install SIR transmit handler */ dev->hard_start_xmit = &irport_hard_xmit; + /* No need to lock, already locked - Jean II */ irport_start(self->irport); IRDA_DEBUG(0, __FUNCTION__ @@ -727,20 +734,26 @@ netif_stop_queue(dev); + /* Make sure tests *& speed change are atomic */ + spin_lock_irqsave(&self->irport->lock, flags); + + /* Note : you should make sure that speed changes are not going + * to corrupt any outgoing frame. Look at nsc-ircc for the gory + * details - Jean II */ + /* Check if we need to change the speed after this frame */ speed = irda_get_next_speed(skb); if ((speed != self->io->speed) && (speed != -1)) { /* Check for empty frame */ if (!skb->len) { ircc_change_speed(self, speed); + spin_unlock_irqrestore(&self->irport->lock, flags); dev_kfree_skb(skb); return 0; } else self->new_speed = speed; } - spin_lock_irqsave(&self->lock, flags); - memcpy(self->tx_buff.head, skb->data, skb->len); self->tx_buff.len = skb->len; @@ -763,7 +776,7 @@ /* Transmit frame */ ircc_dma_xmit(self, iobase, 0); } - spin_unlock_irqrestore(&self->lock, flags); + spin_unlock_irqrestore(&self->irport->lock, flags); dev_kfree_skb(skb); return 0; @@ -936,14 +949,14 @@ len -= 4; if ((len < 2) || (len > 2050)) { - WARNING(__FUNCTION__ "(), bogus len=%d\n", len); + WARNING("%s(), bogus len=%d\n", __FUNCTION__, len); return; } IRDA_DEBUG(2, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len); skb = dev_alloc_skb(len+1); if (!skb) { - WARNING(__FUNCTION__ "(), memory squeeze, dropping frame.\n"); + WARNING("%s(), memory squeeze, dropping frame.\n", __FUNCTION__); return; } /* Make sure IP header gets aligned */ @@ -985,12 +998,13 @@ /* Check if we should use the SIR interrupt handler */ if (self->io->speed < 576000) { + /* Will spinlock itself - Jean II */ irport_interrupt(irq, dev_id, regs); return; } iobase = self->io->fir_base; - spin_lock(&self->lock); + spin_lock(&self->irport->lock); register_bank(iobase, 0); iir = inb(iobase+IRCC_IIR); @@ -1013,7 +1027,7 @@ register_bank(iobase, 0); outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER); - spin_unlock(&self->lock); + spin_unlock(&self->irport->lock); } #if 0 /* unused */ @@ -1072,7 +1086,7 @@ if (request_dma(self->io->dma, dev->name)) { irport_net_close(dev); - WARNING(__FUNCTION__ "(), unable to allocate DMA=%d\n", self->io->dma); + WARNING("%s(), unable to allocate DMA=%d\n", __FUNCTION__, self->io->dma); return -EAGAIN; } @@ -1093,7 +1107,7 @@ struct ircc_cb *self; int iobase; - IRDA_DEBUG(0, __FUNCTION__ "\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); ASSERT(dev != NULL, return -1;); irport = (struct irport_cb *) dev->priv; @@ -1128,17 +1142,15 @@ static void ircc_wakeup(struct ircc_cb *self) { - unsigned long flags; - if (!self->io->suspended) return; - save_flags(flags); - cli(); + /* The code was doing a "cli()" here, but this can't be right. + * If you need protection, do it in net_open with a spinlock + * or give a good reason. - Jean II */ ircc_net_open(self->netdev); - restore_flags(flags); MESSAGE("%s, Waking up\n", driver_name); } @@ -1174,6 +1186,7 @@ iobase = self->irport->io.fir_base; + /* This will destroy irport */ irport_close(self->irport); /* Stop interrupts */ @@ -1187,6 +1200,7 @@ outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA); outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB); #endif + /* Release the PORT that this driver is using */ IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", iobase); @@ -1203,7 +1217,7 @@ return 0; } -int __init smc_init(void) +static int __init smc_init(void) { return ircc_init(); } diff -Nru a/drivers/net/irda/tekram.c b/drivers/net/irda/tekram.c --- a/drivers/net/irda/tekram.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/irda/tekram.c Fri Sep 20 08:20:46 2002 @@ -161,7 +161,7 @@ irda_task_next_state(task, IRDA_TASK_CHILD_DONE); break; case IRDA_TASK_CHILD_WAIT: - WARNING(__FUNCTION__ "(), resetting dongle timed out!\n"); + WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__); ret = -1; break; case IRDA_TASK_CHILD_DONE: @@ -187,7 +187,7 @@ self->speed_task = NULL; break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->speed_task = NULL; ret = -1; @@ -255,7 +255,7 @@ self->reset_task = NULL; break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->reset_task = NULL; ret = -1; diff -Nru a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c --- a/drivers/net/irda/toshoboe.c Fri Sep 20 08:20:41 2002 +++ b/drivers/net/irda/toshoboe.c Fri Sep 20 08:20:41 2002 @@ -421,8 +421,8 @@ } else { - printk (KERN_INFO __FUNCTION__ - "(), memory squeeze, dropping frame.\n"); + printk (KERN_INFO + "%s(), memory squeeze, dropping frame.\n", __FUNCTION__); } self->taskfile->recv[self->rxs].control = 0x83; @@ -824,7 +824,7 @@ if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); err = -ENOMEM; goto freebufs; } @@ -843,7 +843,7 @@ err = register_netdevice(dev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); /* XXX there is not freeing for dev? */ goto freebufs; } diff -Nru a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c --- a/drivers/net/irda/w83977af_ir.c Fri Sep 20 08:20:44 2002 +++ b/drivers/net/irda/w83977af_ir.c Fri Sep 20 08:20:44 2002 @@ -175,6 +175,7 @@ return -ENOMEM; } memset(self, 0, sizeof(struct w83977af_ir)); + spin_lock_init(&self->lock); /* Need to store self somewhere */ dev_self[i] = self; @@ -236,7 +237,7 @@ self->rx_buff.data = self->rx_buff.head; if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); return -ENOMEM; } dev->priv = (void *) self; @@ -254,7 +255,7 @@ err = register_netdevice(dev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdevice() failed!\n"); + ERROR("%s(), register_netdevice() failed!\n", __FUNCTION__); return -1; } MESSAGE("IrDA: Registered device %s\n", dev->name); @@ -603,8 +604,7 @@ switch_bank(iobase, SET2); outb(ADCR1_D_CHSW|/*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase+ADCR1); #ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS - save_flags(flags); - cli(); + spin_lock_irqsave(&self->lock, flags); disable_dma(self->io.dma); clear_dma_ff(self->io.dma); @@ -623,7 +623,7 @@ hcr = inb(iobase+HCR); outb(hcr | HCR_EN_DMA, iobase+HCR); enable_dma(self->io.dma); - restore_flags(flags); + spin_unlock_irqrestore(&self->lock, flags); #else outb(inb(iobase+HCR) | HCR_EN_DMA | HCR_TX_WT, iobase+HCR); #endif @@ -761,8 +761,7 @@ self->rx_buff.data = self->rx_buff.head; #ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS - save_flags(flags); - cli(); + spin_lock_irqsave(&self->lock, flags); disable_dma(self->io.dma); clear_dma_ff(self->io.dma); @@ -788,7 +787,7 @@ hcr = inb(iobase+HCR); outb(hcr | HCR_EN_DMA, iobase+HCR); enable_dma(self->io.dma); - restore_flags(flags); + spin_unlock_irqrestore(&self->lock, flags); #else outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR); #endif @@ -892,8 +891,8 @@ skb = dev_alloc_skb(len+1); if (skb == NULL) { - printk(KERN_INFO __FUNCTION__ - "(), memory squeeze, dropping frame.\n"); + printk(KERN_INFO + "%s(), memory squeeze, dropping frame.\n", __FUNCTION__); /* Restore set register */ outb(set, iobase+SSR); @@ -1334,10 +1333,8 @@ IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); - /* Disable interrupts & save flags */ - save_flags(flags); - cli(); - + spin_lock_irqsave(&self->lock, flags); + switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ if (!capable(CAP_NET_ADMIN)) { @@ -1360,7 +1357,7 @@ ret = -EOPNOTSUPP; } out: - restore_flags(flags); + spin_unlock_irqrestore(&self->lock, flags); return ret; } diff -Nru a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c --- a/drivers/net/lasi_82596.c Fri Sep 20 08:20:42 2002 +++ b/drivers/net/lasi_82596.c Fri Sep 20 08:20:42 2002 @@ -73,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,7 @@ #include #include #include +#include #include #include @@ -94,8 +96,8 @@ #include #include -static char version[] __initdata = - "82596.c $Revision: 1.20 $\n"; +static char version[] __devinitdata = + "82596.c $Revision: 1.29 $\n"; /* DEBUG flags */ @@ -119,7 +121,7 @@ #define DEB_ANY 0xffff -#define DEB(x,y) if (i596_debug & (x)) y +#define DEB(x,y) if (i596_debug & (x)) { y; } #define CHECK_WBACK(addr,len) \ @@ -143,13 +145,13 @@ */ #ifdef __BIG_ENDIAN -#define WSWAPrfd(x) ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) -#define WSWAPrbd(x) ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) -#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16))) -#define WSWAPscb(x) ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) -#define WSWAPcmd(x) ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) -#define WSWAPtbd(x) ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) -#define WSWAPchar(x) ((char *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) +#define WSWAPrfd(x) (((u32)(x)<<16) | ((((u32)(x)))>>16)) +#define WSWAPrbd(x) (((u32)(x)<<16) | ((((u32)(x)))>>16)) +#define WSWAPiscp(x) (((u32)(x)<<16) | ((((u32)(x)))>>16)) +#define WSWAPscb(x) (((u32)(x)<<16) | ((((u32)(x)))>>16)) +#define WSWAPcmd(x) (((u32)(x)<<16) | ((((u32)(x)))>>16)) +#define WSWAPtbd(x) (((u32)(x)<<16) | ((((u32)(x)))>>16)) +#define WSWAPchar(x) (((u32)(x)<<16) | ((((u32)(x)))>>16)) #define ISCP_BUSY 0x00010000 #define MACH_IS_APRICOT 0 #else @@ -182,18 +184,19 @@ MODULE_LICENSE("GPL"); MODULE_PARM(i596_debug, "i"); MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask"); +EXPORT_NO_SYMBOLS; /* Copy frames shorter than rx_copybreak, otherwise pass on up in * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha). */ static int rx_copybreak = 100; +#define MAX_DRIVERS 4 /* max count of drivers */ + #define PKT_BUF_SZ 1536 #define MAX_MC_CNT 64 -#define I596_TOTAL_SIZE 17 - -#define I596_NULL ((void *)0xffffffff) +#define I596_NULL ((u32)0xffffffff) #define CMD_EOL 0x8000 /* The last command of the list, stop. */ #define CMD_SUSP 0x4000 /* Suspend after doing cmd. */ @@ -228,7 +231,7 @@ struct i596_reg { unsigned short porthi; unsigned short portlo; - unsigned long ca; + u32 ca; }; #define EOF 0x8000 @@ -237,9 +240,9 @@ struct i596_tbd { unsigned short size; unsigned short pad; - struct i596_tbd *next; - char *data; - long cache_pad[5]; /* Total 32 bytes... */ + dma_addr_t next; + dma_addr_t data; + u32 cache_pad[5]; /* Total 32 bytes... */ }; /* The command structure has two 'next' pointers; v_next is the address of @@ -256,17 +259,21 @@ struct i596_cmd *v_next; /* Address from CPUs viewpoint */ unsigned short status; unsigned short command; - struct i596_cmd *b_next; /* Address from i596 viewpoint */ + dma_addr_t b_next; /* Address from i596 viewpoint */ }; struct tx_cmd { struct i596_cmd cmd; - struct i596_tbd *tbd; + dma_addr_t tbd; unsigned short size; unsigned short pad; struct sk_buff *skb; /* So we can free it after tx */ dma_addr_t dma_addr; - long cache_pad[1]; /* Total 32 bytes... */ +#ifdef __LP64__ + u32 cache_pad[6]; /* Total 64 bytes... */ +#else + u32 cache_pad[1]; /* Total 32 bytes... */ +#endif }; struct tdr_cmd { @@ -294,27 +301,34 @@ struct i596_rfd { unsigned short stat; unsigned short cmd; - struct i596_rfd *b_next; /* Address from i596 viewpoint */ - struct i596_rbd *rbd; + dma_addr_t b_next; /* Address from i596 viewpoint */ + dma_addr_t rbd; unsigned short count; unsigned short size; struct i596_rfd *v_next; /* Address from CPUs viewpoint */ struct i596_rfd *v_prev; - long cache_pad[2]; /* Total 32 bytes... */ +#ifndef __LP64__ + u32 cache_pad[2]; /* Total 32 bytes... */ +#endif }; struct i596_rbd { + /* hardware data */ unsigned short count; unsigned short zero1; - struct i596_rbd *b_next; - unsigned char *b_data; /* Address from i596 viewpoint */ + dma_addr_t b_next; + dma_addr_t b_data; /* Address from i596 viewpoint */ unsigned short size; unsigned short zero2; + /* driver data */ struct sk_buff *skb; struct i596_rbd *v_next; - struct i596_rbd *b_addr; /* This rbd addr from i596 view */ + dma_addr_t b_addr; /* This rbd addr from i596 view */ unsigned char *v_data; /* Address from CPUs viewpoint */ /* Total 32 bytes... */ +#ifdef __LP64__ + u32 cache_pad[4]; +#endif }; /* These values as chosen so struct i596_private fits in one page... */ @@ -325,27 +339,27 @@ struct i596_scb { unsigned short status; unsigned short command; - struct i596_cmd *cmd; - struct i596_rfd *rfd; - unsigned long crc_err; - unsigned long align_err; - unsigned long resource_err; - unsigned long over_err; - unsigned long rcvdt_err; - unsigned long short_err; + dma_addr_t cmd; + dma_addr_t rfd; + u32 crc_err; + u32 align_err; + u32 resource_err; + u32 over_err; + u32 rcvdt_err; + u32 short_err; unsigned short t_on; unsigned short t_off; }; struct i596_iscp { - unsigned long stat; - struct i596_scb *scb; + u32 stat; + dma_addr_t scb; }; struct i596_scp { - unsigned long sysbus; - unsigned long pad; - struct i596_iscp *iscp; + u32 sysbus; + u32 pad; + dma_addr_t iscp; }; struct i596_private { @@ -360,14 +374,14 @@ struct i596_rbd rbds[RX_RING_SIZE] __attribute__((aligned(32))); struct tx_cmd tx_cmds[TX_RING_SIZE] __attribute__((aligned(32))); struct i596_tbd tbds[TX_RING_SIZE] __attribute__((aligned(32))); - unsigned long stat; + u32 stat; int last_restart; struct i596_rfd *rfd_head; struct i596_rbd *rbd_head; struct i596_cmd *cmd_tail; struct i596_cmd *cmd_head; int cmd_backlog; - unsigned long last_cmd; + u32 last_cmd; struct net_device_stats stats; int next_tx_cmd; int options; @@ -392,6 +406,8 @@ 0x00, 0x7f /* *multi IA */ }; +static struct pci_dev *fake_pci_dev; /* The fake pci_dev needed for + pci_* functions under ccio. */ static int dma_consistent = 1; /* Zero if pci_alloc_consistent() fails */ static int i596_open(struct net_device *dev); @@ -411,22 +427,28 @@ static inline void CA(struct net_device *dev) { - gsc_writel(0, (void*)(dev->base_addr + PA_CHANNEL_ATTENTION)); + gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION); } -static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x) +static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x) { struct i596_private *lp = (struct i596_private *) dev->priv; u32 v = (u32) (c) | (u32) (x); + u16 a, b; - if (lp->options & OPT_SWAP_PORT) - v = ((u32) (v) << 16) | ((u32) (v) >> 16); + if (lp->options & OPT_SWAP_PORT) { + a = v >> 16; + b = v & 0xffff; + } else { + a = v & 0xffff; + b = v >> 16; + } - gsc_writel(v & 0xffff, (void*)(dev->base_addr + PA_CPU_PORT_L_ACCESS)); + gsc_writel(a, dev->base_addr + PA_CPU_PORT_L_ACCESS); udelay(1); - gsc_writel(v >> 16, (void*)(dev->base_addr + PA_CPU_PORT_L_ACCESS)); + gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS); } @@ -438,7 +460,7 @@ CHECK_INV(&(lp->iscp), sizeof(struct i596_iscp)); } if (!delcnt) { - printk("%s: %s, iscp.stat %04lx, didn't clear\n", + printk("%s: %s, iscp.stat %04x, didn't clear\n", dev->name, str, lp->iscp.stat); return -1; } @@ -471,28 +493,28 @@ struct i596_rfd *rfd; struct i596_rbd *rbd; - printk("lp and scp at %p, .sysbus = %08lx, .iscp = %p\n", + printk("lp and scp at %p, .sysbus = %08x, .iscp = %08x\n", &lp->scp, lp->scp.sysbus, lp->scp.iscp); - printk("iscp at %p, iscp.stat = %08lx, .scb = %p\n", + printk("iscp at %p, iscp.stat = %08x, .scb = %08x\n", &lp->iscp, lp->iscp.stat, lp->iscp.scb); printk("scb at %p, scb.status = %04x, .command = %04x," - " .cmd = %p, .rfd = %p\n", + " .cmd = %08x, .rfd = %08x\n", &lp->scb, lp->scb.status, lp->scb.command, lp->scb.cmd, lp->scb.rfd); - printk(" errors: crc %lx, align %lx, resource %lx," - " over %lx, rcvdt %lx, short %lx\n", + printk(" errors: crc %x, align %x, resource %x," + " over %x, rcvdt %x, short %x\n", lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err, lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err); cmd = lp->cmd_head; - while (cmd != I596_NULL) { - printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n", + while (cmd != NULL) { + printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %08x\n", cmd, cmd->status, cmd->command, cmd->b_next); cmd = cmd->v_next; } rfd = lp->rfd_head; printk("rfd_head = %p\n", rfd); do { - printk (" %p .stat %04x, .cmd %04x, b_next %p, rbd %p," + printk (" %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x," " count %04x\n", rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd, rfd->count); @@ -501,7 +523,7 @@ rbd = lp->rbd_head; printk("rbd_head = %p\n", rbd); do { - printk(" %p .count %04x, b_next %p, b_data %p, size %04x\n", + printk(" %p .count %04x, b_next %08x, b_data %08x, size %04x\n", rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size); rbd = rbd->v_next; } while (rbd != lp->rbd_head); @@ -522,7 +544,7 @@ } #endif -#define virt_to_dma(lp,v) ((char *)(v)-(char *)(lp)+(char *)((lp)->dma_addr)) +#define virt_to_dma(lp,v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)(lp))) static inline void init_rx_bufs(struct net_device *dev) { @@ -540,7 +562,7 @@ if (skb == NULL) panic("82596: alloc_skb() failed"); skb_reserve(skb, 2); - dma_addr = pci_map_single(NULL, skb->tail,PKT_BUF_SZ, + dma_addr = pci_map_single(fake_pci_dev, skb->tail,PKT_BUF_SZ, PCI_DMA_FROMDEVICE); skb->dev = dev; rbd->v_next = rbd+1; @@ -568,7 +590,7 @@ lp->rfd_head = lp->rfds; lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds)); rfd = lp->rfds; - rfd->rbd = lp->rbd_head; + rfd->rbd = WSWAPrbd(virt_to_dma(lp,lp->rbd_head)); rfd->v_prev = lp->rfds + rx_ring_size - 1; rfd = lp->rfds + rx_ring_size - 1; rfd->v_next = lp->rfds; @@ -587,7 +609,9 @@ for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) { if (rbd->skb == NULL) break; - pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + pci_unmap_single(fake_pci_dev, + (dma_addr_t)WSWAPchar(rbd->b_data), + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); dev_kfree_skb(rbd->skb); } } @@ -639,14 +663,15 @@ lp->iscp.stat = ISCP_BUSY; lp->cmd_backlog = 0; - lp->cmd_head = lp->scb.cmd = I596_NULL; + lp->cmd_head = NULL; + lp->scb.cmd = I596_NULL; DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name)); CHECK_WBACK(&(lp->scp), sizeof(struct i596_scp)); CHECK_WBACK(&(lp->iscp), sizeof(struct i596_iscp)); - MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_dma(lp,&lp->scp)); + MPU_PORT(dev, PORT_ALTSCP, virt_to_dma(lp,&lp->scp)); CA(dev); @@ -723,7 +748,7 @@ CHECK_INV(rfd, sizeof(struct i596_rfd)); while ((rfd->stat) & STAT_C) { /* Loop while complete frames */ if (rfd->rbd == I596_NULL) - rbd = I596_NULL; + rbd = NULL; else if (rfd->rbd == lp->rbd_head->b_addr) { rbd = lp->rbd_head; CHECK_INV(rbd, sizeof(struct i596_rbd)); @@ -731,12 +756,12 @@ else { printk("%s: rbd chain broken!\n", dev->name); /* XXX Now what? */ - rbd = I596_NULL; + rbd = NULL; } - DEB(DEB_RXFRAME, printk(" rfd %p, rfd.rbd %p, rfd.stat %04x\n", + DEB(DEB_RXFRAME, printk(" rfd %p, rfd.rbd %08x, rfd.stat %04x\n", rfd, rfd->rbd, rfd->stat)); - if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) { + if (rbd != NULL && ((rfd->stat) & STAT_OK)) { /* a good frame */ int pkt_len = rbd->count & 0x3fff; struct sk_buff *skb = rbd->skb; @@ -753,7 +778,7 @@ struct sk_buff *newskb; dma_addr_t dma_addr; - pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + pci_unmap_single(fake_pci_dev,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* Get fresh skbuff to replace filled one. */ newskb = dev_alloc_skb(PKT_BUF_SZ + 4); if (newskb == NULL) { @@ -767,7 +792,7 @@ rx_in_place = 1; rbd->skb = newskb; newskb->dev = dev; - dma_addr = pci_map_single(NULL, newskb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + dma_addr = pci_map_single(fake_pci_dev, newskb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); rbd->v_data = newskb->tail; rbd->b_data = WSWAPchar(dma_addr); CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd)); @@ -784,7 +809,7 @@ skb->dev = dev; if (!rx_in_place) { /* 16 byte align the data fields */ - pci_dma_sync_single(NULL, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + pci_dma_sync_single(fake_pci_dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); skb_reserve(skb, 2); memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len); } @@ -818,7 +843,7 @@ /* Clear the buffer descriptor count and EOF + F flags */ - if (rbd != I596_NULL && (rbd->count & 0x4000)) { + if (rbd != NULL && (rbd->count & 0x4000)) { rbd->count = 0; lp->rbd_head = rbd->v_next; CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd)); @@ -855,7 +880,7 @@ { struct i596_cmd *ptr; - while (lp->cmd_head != I596_NULL) { + while (lp->cmd_head != NULL) { ptr = lp->cmd_head; lp->cmd_head = ptr->v_next; lp->cmd_backlog--; @@ -865,19 +890,21 @@ { struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; struct sk_buff *skb = tx_cmd->skb; - pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(fake_pci_dev, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); lp->stats.tx_errors++; lp->stats.tx_aborted_errors++; - ptr->v_next = ptr->b_next = I596_NULL; + ptr->v_next = NULL; + ptr->b_next = I596_NULL; tx_cmd->cmd.command = 0; /* Mark as free */ break; } default: - ptr->v_next = ptr->b_next = I596_NULL; + ptr->v_next = NULL; + ptr->b_next = I596_NULL; } CHECK_WBACK_INV(ptr, sizeof(struct i596_cmd)); } @@ -888,7 +915,7 @@ } -static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) +static inline void i596_reset(struct net_device *dev, struct i596_private *lp) { unsigned long flags; @@ -920,19 +947,19 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) { struct i596_private *lp = (struct i596_private *) dev->priv; - int ioaddr = dev->base_addr; unsigned long flags; DEB(DEB_ADDCMD,printk("i596_add_cmd cmd_head %p\n", lp->cmd_head)); cmd->status = 0; cmd->command |= (CMD_EOL | CMD_INTR); - cmd->v_next = cmd->b_next = I596_NULL; + cmd->v_next = NULL; + cmd->b_next = I596_NULL; CHECK_WBACK(cmd, sizeof(struct i596_cmd)); spin_lock_irqsave (&lp->lock, flags); - if (lp->cmd_head != I596_NULL) { + if (lp->cmd_head != NULL) { lp->cmd_tail->v_next = cmd; lp->cmd_tail->b_next = WSWAPcmd(virt_to_dma(lp,&cmd->status)); CHECK_WBACK(lp->cmd_tail, sizeof(struct i596_cmd)); @@ -957,7 +984,7 @@ printk("%s: command unit timed out, status resetting.\n", dev->name); #if 1 - i596_reset(dev, lp, ioaddr); + i596_reset(dev, lp); #endif } } @@ -1010,8 +1037,6 @@ goto out_remove_rx_bufs; } - request_mem_region(dev->base_addr, I596_TOTAL_SIZE, "i82596"); - netif_start_queue(dev); return 0; @@ -1028,7 +1053,6 @@ static void i596_tx_timeout (struct net_device *dev) { struct i596_private *lp = (struct i596_private *) dev->priv; - int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n", @@ -1040,7 +1064,7 @@ if (lp->last_restart == lp->stats.tx_packets) { DEB(DEB_ERRORS,printk ("Resetting board.\n")); /* Shutdown and restart */ - i596_reset (dev, lp, ioaddr); + i596_reset (dev, lp); } else { /* Issue a channel attention signal */ DEB(DEB_ERRORS,printk ("Kicking board.\n")); @@ -1063,8 +1087,8 @@ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; dev->trans_start = jiffies; - DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name, - skb->len, (unsigned int)skb->data)); + DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%p) called\n", dev->name, + skb->len, skb->data)); netif_stop_queue(dev); @@ -1091,7 +1115,7 @@ tbd->pad = 0; tbd->size = EOF | length; - tx_cmd->dma_addr = pci_map_single(NULL, skb->data, skb->len, + tx_cmd->dma_addr = pci_map_single(fake_pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); tbd->data = WSWAPchar(tx_cmd->dma_addr); @@ -1125,7 +1149,7 @@ #define LAN_PROM_ADDR 0xF0810000 -static int __init i82596_probe(struct net_device *dev, int options) +static int __devinit i82596_probe(struct net_device *dev) { int i; struct i596_private *lp; @@ -1138,12 +1162,12 @@ sizeof(struct i596_rfd)); return -ENODEV; } - if (sizeof(struct i596_rbd) != 32) { + if ((sizeof(struct i596_rbd) % 32) != 0) { printk("82596: sizeof(struct i596_rbd) = %d\n", sizeof(struct i596_rbd)); return -ENODEV; } - if (sizeof(struct tx_cmd) != 32) { + if ((sizeof(struct tx_cmd) % 32) != 0) { printk("82596: sizeof(struct tx_cmd) = %d\n", sizeof(struct tx_cmd)); return -ENODEV; @@ -1153,27 +1177,25 @@ sizeof(struct i596_tbd)); return -ENODEV; } +#ifndef __LP64__ if (sizeof(struct i596_private) > 4096) { printk("82596: sizeof(struct i596_private) = %d\n", sizeof(struct i596_private)); return -ENODEV; } - - /* FIXME: - Currently this works only, if set-up from lasi.c. - This should be changed to use probing too ! - */ +#endif if (!dev->base_addr || !dev->irq) - return -ENODEV; + return -ENODEV; - if (pdc_lan_station_id( (char*)ð_addr, (void*)dev->base_addr)) { - for(i=0;i<6;i++) - eth_addr[i] = gsc_readb(LAN_PROM_ADDR+i); - printk("82596.c: MAC of HP700 LAN blindely read from the prom!\n"); + if (pdc_lan_station_id(eth_addr, dev->base_addr)) { + for (i=0; i < 6; i++) { + eth_addr[i] = gsc_readb(LAN_PROM_ADDR + i); + } + printk("82596.c: MAC of HP700 LAN read from EEPROM\n"); } - dev->mem_start = (int)pci_alloc_consistent( NULL, + dev->mem_start = (unsigned long) pci_alloc_consistent(fake_pci_dev, sizeof(struct i596_private), &dma_addr); if (!dev->mem_start) { printk("%s: Couldn't get consistent shared memory\n", dev->name); @@ -1183,7 +1205,7 @@ printk("%s: Couldn't get shared memory\n", dev->name); return -ENOMEM; } - dma_addr = virt_to_phys(dev->mem_start); + dma_addr = virt_to_bus(dev->mem_start); } ether_setup(dev); @@ -1209,11 +1231,10 @@ lp = (struct i596_private *) dev->priv; DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n", - dev->name, (unsigned long)lp, - sizeof(struct i596_private), (unsigned long)&lp->scb)); - memset((void *) lp, 0, sizeof(struct i596_private)); + dev->name, (unsigned long)lp, + sizeof(struct i596_private), (unsigned long)&lp->scb)); + memset(lp, 0, sizeof(struct i596_private)); - lp->options = options; lp->scb.command = 0; lp->scb.cmd = I596_NULL; lp->scb.rfd = I596_NULL; @@ -1226,18 +1247,6 @@ } -int __init lasi_i82596_probe(struct net_device *dev) -{ - return i82596_probe(dev, 0); -} - - -int __init asp_i82596_probe(struct net_device *dev) -{ - return i82596_probe(dev, OPT_SWAP_PORT); -} - - static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; @@ -1275,7 +1284,7 @@ if ((status & 0x2000)) DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700)); - while (lp->cmd_head != I596_NULL) { + while (lp->cmd_head != NULL) { CHECK_INV(lp->cmd_head, sizeof(struct i596_cmd)); if (!(lp->cmd_head->status & STAT_C)) break; @@ -1308,7 +1317,7 @@ if ((ptr->status) & 0x1000) lp->stats.tx_aborted_errors++; } - pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(fake_pci_dev, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(skb); tx_cmd->cmd.command = 0; /* Mark free */ @@ -1337,7 +1346,8 @@ ptr->command = 0; break; } - ptr->v_next = ptr->b_next = I596_NULL; + ptr->v_next = NULL; + ptr->b_next = I596_NULL; CHECK_WBACK(ptr, sizeof(struct i596_cmd)); lp->last_cmd = jiffies; } @@ -1347,7 +1357,7 @@ * only add to the cmd queue when the CU is stopped. */ ptr = lp->cmd_head; - while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) { + while ((ptr != NULL) && (ptr != lp->cmd_tail)) { struct i596_cmd *prev = ptr; ptr->command &= 0x1fff; @@ -1355,7 +1365,7 @@ CHECK_WBACK_INV(prev, sizeof(struct i596_cmd)); } - if ((lp->cmd_head != I596_NULL)) + if ((lp->cmd_head != NULL)) ack_cmd |= CUC_START; lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&lp->cmd_head->status)); CHECK_WBACK_INV(&lp->scb, sizeof(struct i596_scb)); @@ -1421,8 +1431,6 @@ free_irq(dev->irq, dev); remove_rx_bufs(dev); - release_mem_region(dev->base_addr, I596_TOTAL_SIZE); - MOD_DEC_USE_COUNT; return 0; @@ -1502,48 +1510,106 @@ } } -#ifdef HAVE_DEVLIST -static unsigned int i596_portlist[] __initdata = -{0x300, 0}; -struct netdev_entry i596_drv = -{"lasi_i82596", lasi_i82596_probe, I596_TOTAL_SIZE, i596_portlist}; -#endif +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "lasi_82596 debug mask"); +static int debug = -1; + +static int num_drivers; +static struct net_device *netdevs[MAX_DRIVERS]; -#ifdef MODULE -static char devicename[9] = -{0,}; -static struct net_device dev_82596 = +static int __devinit +lan_init_chip(struct parisc_device *dev) { - .name = devicename, /* device name inserted by drivers/net/net_init.c */ - .init = lasi_i82596_probe, + struct net_device *netdevice; + int retval; + + if (num_drivers >= MAX_DRIVERS) { + /* max count of possible i82596 drivers reached */ + return -ENODEV; + } + + fake_pci_dev = ccio_get_fake(dev); + + if (!dev->irq) { + printk(KERN_ERR __FILE__ ": IRQ not found for i82596 at 0x%lx\n", dev->hpa); + return -ENODEV; + } + + printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa, dev->irq); + + netdevice = alloc_etherdev(0); + if (!netdevice) + return -ENOMEM; + + netdevice->base_addr = dev->hpa; + netdevice->irq = dev->irq; + netdevice->init = i82596_probe; + + retval = register_netdev(netdevice); + if (retval) { + printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval); + kfree(netdevice); + return -ENODEV; + }; + if (dev->id.sversion == 0x72) { + ((struct i596_private *)netdevice->priv)->options = OPT_SWAP_PORT; + } + + netdevs[num_drivers++] = netdevice; + + return retval; +} + + +static struct parisc_device_id lan_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a }, + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00072 }, + { 0, } }; +MODULE_DEVICE_TABLE(parisc, lan_tbl); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "lasi_82596 debug mask"); -static int debug = -1; +static struct parisc_driver lan_driver = { + name: "Apricot", + id_table: lan_tbl, + probe: lan_init_chip, +}; -int init_module(void) +static int __devinit lasi_82596_init(void) { if (debug >= 0) i596_debug = debug; - if (register_netdev(&dev_82596) != 0) - return -EIO; - return 0; + return register_parisc_driver(&lan_driver); } -void cleanup_module(void) +module_init(lasi_82596_init); + +static void __exit lasi_82596_exit(void) { - unregister_netdev(&dev_82596); - lp = (struct i596_private *) dev_82596.priv; + int i; - if (dma_consistent) - pci_free_consistent( NULL, sizeof( struct i596_private), - dev_82596.mem_start, lp->dma_addr); - else - free_page ((u32)(dev_82596.mem_start)); + for (i=0; ipriv; + if (dma_consistent) + pci_free_consistent(fake_pci_dev, + sizeof(struct i596_private), + (void *)netdevice->mem_start, lp->dma_addr); + else + free_page(netdevice->mem_start); + + netdevice->priv = NULL; + } - dev_82596.priv = NULL; + unregister_parisc_driver(&lan_driver); } -#endif /* MODULE */ +module_exit(lasi_82596_exit); diff -Nru a/drivers/net/natsemi.c b/drivers/net/natsemi.c --- a/drivers/net/natsemi.c Fri Sep 20 08:20:41 2002 +++ b/drivers/net/natsemi.c Fri Sep 20 08:20:41 2002 @@ -100,20 +100,65 @@ * ETHTOOL_* further support (Tim Hockin) version 1.0.13: - * ETHTOOL_[GS]EEPROM support (Tim Hockin) + * ETHTOOL_[G]EEPROM support (Tim Hockin) version 1.0.13: * crc cleanup (Matt Domsch ) + version 1.0.14: + * Cleanup some messages and autoneg in ethtool (Tim Hockin) + + version 1.0.15: + * Get rid of cable_magic flag + * use new (National provided) solution for cable magic issue + + version 1.0.16: + * call netdev_rx() for RxErrors (Manfred Spraul) + * formatting and cleanups + * change options and full_duplex arrays to be zero + initialized + * enable only the WoL and PHY interrupts in wol mode + TODO: * big endian support with CFG:BEM instead of cpu_to_le32 * support for an external PHY * flow control */ +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include + #define DRV_NAME "natsemi" -#define DRV_VERSION "1.07+LK1.0.13" -#define DRV_RELDATE "Nov 12, 2001" +#define DRV_VERSION "1.07+LK1.0.16" +#define DRV_RELDATE "Aug 28, 2002" /* Updated to recommendations in pci-skeleton v2.03. */ @@ -132,7 +177,12 @@ /* The user-configurable values. These may be modified when a driver module is loaded.*/ -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +#define NATSEMI_DEF_MSG (NETIF_MSG_DRV | \ + NETIF_MSG_LINK | \ + NETIF_MSG_WOL | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) +static int debug = NATSEMI_DEF_MSG; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -152,8 +202,8 @@ The media type is usually passed in 'options[]'. */ #define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int options[MAX_UNITS]; +static int full_duplex[MAX_UNITS]; /* Operational parameters that are set at compile time. */ @@ -164,7 +214,7 @@ There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */ -#define RX_RING_SIZE 64 +#define RX_RING_SIZE 32 /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -183,37 +233,6 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ -#if !defined(__OPTIMIZE__) -#warning You must compile this file with the correct options! -#warning See the last lines of the source file. -#error You must compile this driver with "-O". -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Processor type for cache alignment. */ -#include -#include -#include -#include - /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = KERN_INFO DRV_NAME ".c:v1.07 1/9/2001 Written by Donald Becker \n" @@ -232,7 +251,7 @@ MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(max_interrupt_work, "DP8381x maximum events handled per interrupt"); MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); -MODULE_PARM_DESC(debug, "DP8381x debug level (0-5)"); +MODULE_PARM_DESC(debug, "DP8381x default debug bitmask"); MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex"); MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)"); @@ -394,14 +413,12 @@ SDCFG = 0xF8 }; /* the values for the 'magic' registers above (PGSEL=1) */ -#ifdef CONFIG_NATSEMI_CABLE_MAGIC -#define PMDCSR_VAL 0x1898 -#else -#define PMDCSR_VAL 0x189C -#endif +#define PMDCSR_VAL 0x189c /* enable preferred adaptation circuitry */ #define TSTDAT_VAL 0x0 #define DSPCFG_VAL 0x5040 -#define SDCFG_VAL 0x008c +#define SDCFG_VAL 0x008c /* set voltage thresholds for Signal Detect */ +#define DSPCFG_LOCK 0x20 /* coefficient lock bit in DSPCFG */ +#define TSTDAT_FIXED 0xe8 /* magic number for bad coefficients */ /* misc PCI space registers */ enum pci_register_offsets { @@ -421,6 +438,7 @@ enum ChipConfig_bits { CfgPhyDis = 0x200, CfgPhyRst = 0x400, + CfgExtPhy = 0x1000, CfgAnegEnable = 0x2000, CfgAneg100 = 0x4000, CfgAnegFull = 0x8000, @@ -630,10 +648,13 @@ u32 SavedClkRun; /* silicon revision */ u32 srr; + /* expected DSPCFG value */ + u16 dspcfg; /* MII transceiver section. */ u16 advertising; /* NWay media advertisement */ unsigned int iosize; spinlock_t lock; + u32 msg_enable; }; static int eeprom_read(long ioaddr, int location); @@ -643,6 +664,8 @@ static void natsemi_reload_eeprom(struct net_device *dev); static void natsemi_stop_rxtx(struct net_device *dev); static int netdev_open(struct net_device *dev); +static void do_cable_magic(struct net_device *dev); +static void undo_cable_magic(struct net_device *dev); static void check_link(struct net_device *dev); static void netdev_timer(unsigned long data); static void tx_timeout(struct net_device *dev); @@ -753,6 +776,7 @@ pci_set_drvdata(pdev, dev); np->iosize = iosize; spin_lock_init(&np->lock); + np->msg_enable = debug; /* Reset the chip to erase previous misconfiguration. */ natsemi_reload_eeprom(dev); @@ -763,14 +787,15 @@ option = dev->mem_start; /* The lower four bits are the media type. */ - if (option > 0) { + if (option) { if (option & 0x200) np->full_duplex = 1; if (option & 15) - printk(KERN_INFO "%s: ignoring user supplied media type %d", + printk(KERN_INFO + "%s: ignoring user supplied media type %d", dev->name, option & 15); } - if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) + if (find_cnt < MAX_UNITS && full_duplex[find_cnt]) np->full_duplex = 1; /* The chip-specific entries in the device structure. */ @@ -796,14 +821,17 @@ } netif_carrier_off(dev); - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, natsemi_pci_info[chip_idx].name, ioaddr); - for (i = 0; i < ETH_ALEN-1; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + if (netif_msg_drv(np)) { + printk(KERN_INFO "%s: %s at %#08lx, ", + dev->name, natsemi_pci_info[chip_idx].name, ioaddr); + for (i = 0; i < ETH_ALEN-1; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x, IRQ %d.\n", dev->dev_addr[i], irq); + } np->advertising = mdio_read(dev, 1, MII_ADVERTISE); - if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) { + if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000 + && netif_msg_probe(np)) { u32 chip_config = readl(ioaddr + ChipConfig); printk(KERN_INFO "%s: Transceiver default autonegotiation %s " "10%s %s duplex.\n", @@ -812,12 +840,18 @@ chip_config & CfgAneg100 ? "0" : "", chip_config & CfgAnegFull ? "full" : "half"); } - printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", - dev->name, mdio_read(dev, 1, MII_BMSR), - np->advertising); + if (netif_msg_probe(np)) + printk(KERN_INFO + "%s: Transceiver status %#04x advertising %#04x.\n", + dev->name, mdio_read(dev, 1, MII_BMSR), + np->advertising); /* save the silicon revision for later querying */ np->srr = readl(ioaddr + SiliconRev); + if (netif_msg_hw(np)) + printk(KERN_INFO "%s: silicon revision %#04x.\n", + dev->name, np->srr); + return 0; } @@ -914,6 +948,7 @@ u32 rfcr; u16 pmatch[3]; u16 sopass[3]; + struct netdev_private *np = dev->priv; /* * Resetting the chip causes some registers to be lost. @@ -947,10 +982,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: reset did not complete in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: reset completed in %d usec.\n", dev->name, i*5); } @@ -979,6 +1014,7 @@ static void natsemi_reload_eeprom(struct net_device *dev) { + struct netdev_private *np = dev->priv; int i; writel(EepromReload, dev->base_addr + PCIBusCfg); @@ -987,10 +1023,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: EEPROM did not reload in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: EEPROM reloaded in %d usec.\n", dev->name, i*5); } @@ -999,6 +1035,7 @@ static void natsemi_stop_rxtx(struct net_device *dev) { long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; int i; writel(RxOff | TxOff, ioaddr + ChipCmd); @@ -1007,10 +1044,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n", dev->name, i*5); } @@ -1028,7 +1065,7 @@ i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); if (i) return i; - if (debug > 1) + if (netif_msg_ifup(np)) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", dev->name, dev->irq); i = alloc_ring(dev); @@ -1043,8 +1080,8 @@ netif_start_queue(dev); - if (debug > 2) - printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n", + if (netif_msg_ifup(np)) + printk(KERN_DEBUG "%s: Done netdev_open(), status: %#08x.\n", dev->name, (int)readl(ioaddr + ChipCmd)); /* Set the timer to check for link beat. */ @@ -1057,6 +1094,54 @@ return 0; } +static void do_cable_magic(struct net_device *dev) +{ + /* + * 100 MBit links with short cables can trip an issue with the chip. + * The problem manifests as lots of CRC errors and/or flickering + * activity LED while idle. This process is based on instructions + * from engineers at National. + */ + if (readl(dev->base_addr + ChipConfig) & CfgSpeed100) { + u16 data; + + writew(1, dev->base_addr + PGSEL); + /* + * coefficient visibility should already be enabled via + * DSPCFG | 0x1000 + */ + data = readw(dev->base_addr + TSTDAT) & 0xff; + /* + * the value must be negative, and within certain values + * (these values all come from National) + */ + if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) { + struct netdev_private *np = dev->priv; + + /* the bug has been triggered - fix the coefficient */ + writew(TSTDAT_FIXED, dev->base_addr + TSTDAT); + /* lock the value */ + data = readw(dev->base_addr + DSPCFG); + np->dspcfg = data | DSPCFG_LOCK; + writew(np->dspcfg, dev->base_addr + DSPCFG); + } + writew(0, dev->base_addr + PGSEL); + } +} + +static void undo_cable_magic(struct net_device *dev) +{ + u16 data; + struct netdev_private *np = dev->priv; + + writew(1, dev->base_addr + PGSEL); + /* make sure the lock bit is clear */ + data = readw(dev->base_addr + DSPCFG); + np->dspcfg = data & ~DSPCFG_LOCK; + writew(np->dspcfg, dev->base_addr + DSPCFG); + writew(0, dev->base_addr + PGSEL); +} + static void check_link(struct net_device *dev) { struct netdev_private *np = dev->priv; @@ -1064,30 +1149,32 @@ int duplex; int chipcfg = readl(ioaddr + ChipConfig); - if(!(chipcfg & CfgLink)) { + if (!(chipcfg & CfgLink)) { if (netif_carrier_ok(dev)) { - if (debug) - printk(KERN_INFO "%s: no link. Disabling watchdog.\n", + if (netif_msg_link(np)) + printk(KERN_NOTICE "%s: link down.\n", dev->name); netif_carrier_off(dev); + undo_cable_magic(dev); } return; } if (!netif_carrier_ok(dev)) { - if (debug) - printk(KERN_INFO "%s: link is back. Enabling watchdog.\n", - dev->name); + if (netif_msg_link(np)) + printk(KERN_NOTICE "%s: link up.\n", dev->name); netif_carrier_on(dev); + do_cable_magic(dev); } duplex = np->full_duplex || (chipcfg & CfgFullDuplex ? 1 : 0); /* if duplex is set then bit 28 must be set, too */ if (duplex ^ !!(np->rx_config & RxAcceptTx)) { - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link" - " capability.\n", dev->name, - duplex ? "full" : "half"); + if (netif_msg_link(np)) + printk(KERN_INFO + "%s: Setting %s-duplex based on negotiated " + "link capability.\n", dev->name, + duplex ? "full" : "half"); if (duplex) { np->rx_config |= RxAcceptTx; np->tx_config |= TxCarrierIgn | TxHeartIgn; @@ -1106,17 +1193,12 @@ long ioaddr = dev->base_addr; int i; - /* save the silicon revision for later */ - if (debug > 4) - printk(KERN_DEBUG "%s: found silicon revision %xh.\n", - dev->name, np->srr); - for (i=0;ibase_addr + ChipConfig) & CfgAnegDone) break; udelay(10); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_link(np)) { printk(KERN_INFO "%s: autonegotiation did not complete in %d usec.\n", dev->name, i*10); @@ -1135,6 +1217,7 @@ writew(DSPCFG_VAL, ioaddr + DSPCFG); writew(SDCFG_VAL, ioaddr + SDCFG); writew(0, ioaddr + PGSEL); + np->dspcfg = DSPCFG_VAL; /* Enable PHY Specific event based interrupts. Link state change and Auto-Negotiation Completion are among the affected. @@ -1181,8 +1264,8 @@ * nothing will be written to memory. */ np->SavedClkRun = readl(ioaddr + ClkRun); writel(np->SavedClkRun & ~PMEEnable, ioaddr + ClkRun); - if (np->SavedClkRun & PMEStatus) { - printk(KERN_NOTICE "%s: Wake-up event %8.8x\n", + if (np->SavedClkRun & PMEStatus && netif_msg_wol(np)) { + printk(KERN_NOTICE "%s: Wake-up event %#08x\n", dev->name, readl(ioaddr + WOLCmd)); } @@ -1197,8 +1280,10 @@ writel(StatsClear, ioaddr + StatsCtrl); /* Clear Stats */ } -/* - * The frequency on this has been increased because of a nasty little problem. +/* + * Purpose: + * check for sudden death of the NIC: + * * It seems that a reference set for this chip went out with incorrect info, * and there exist boards that aren't quite right. An unexpected voltage drop * can cause the PHY to get itself in a weird state (basically reset..). @@ -1212,7 +1297,7 @@ long ioaddr = dev->base_addr; u16 dspcfg; - if (debug > 3) { + if (netif_msg_timer(np)) { /* DO NOT read the IntrStatus register, * a read clears any pending interrupts. */ @@ -1220,15 +1305,18 @@ dev->name); } + spin_lock_irq(&np->lock); + /* check for a nasty random phy-reset - use dspcfg as a flag */ writew(1, ioaddr+PGSEL); dspcfg = readw(ioaddr+DSPCFG); writew(0, ioaddr+PGSEL); - if (dspcfg != DSPCFG_VAL) { + if (dspcfg != np->dspcfg) { if (!netif_queue_stopped(dev)) { - printk(KERN_INFO - "%s: possible phy reset: re-initializing\n", - dev->name); + spin_unlock_irq(&np->lock); + if (netif_msg_hw(np)) + printk(KERN_NOTICE "%s: possible phy reset: " + "re-initializing\n", dev->name); disable_irq(dev->irq); spin_lock_irq(&np->lock); init_registers(dev); @@ -1237,10 +1325,10 @@ } else { /* hurry back */ next_tick = HZ; + spin_unlock_irq(&np->lock); } } else { /* init_registers() calls check_link() for the above case */ - spin_lock_irq(&np->lock); check_link(dev); spin_unlock_irq(&np->lock); } @@ -1251,18 +1339,18 @@ { struct netdev_private *np = dev->priv; - if (debug > 2) { + if (netif_msg_pktdata(np)) { int i; printk(KERN_DEBUG " Tx ring at %p:\n", np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) { - printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n", i, np->tx_ring[i].next_desc, np->tx_ring[i].cmd_status, np->tx_ring[i].addr); } printk(KERN_DEBUG " Rx ring %p:\n", np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) { - printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n", i, np->rx_ring[i].next_desc, np->rx_ring[i].cmd_status, np->rx_ring[i].addr); @@ -1278,9 +1366,11 @@ disable_irq(dev->irq); spin_lock_irq(&np->lock); if (netif_device_present(dev)) { - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", - dev->name, readl(ioaddr + IntrStatus)); + if (netif_msg_tx_err(np)) + printk(KERN_WARNING + "%s: Transmit timed out, status %#08x," + " resetting...\n", + dev->name, readl(ioaddr + IntrStatus)); dump_ring(dev); natsemi_reset(dev); @@ -1304,8 +1394,8 @@ { struct netdev_private *np = dev->priv; np->rx_ring = pci_alloc_consistent(np->pci_dev, - sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE), - &np->ring_dma); + sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE), + &np->ring_dma); if (!np->rx_ring) return -ENOMEM; np->tx_ring = &np->rx_ring[RX_RING_SIZE]; @@ -1438,7 +1528,7 @@ dev->trans_start = jiffies; - if (debug > 4) { + if (netif_msg_tx_queued(np)) { printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } @@ -1451,14 +1541,11 @@ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; - if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) { - if (debug > 4) - printk(KERN_DEBUG "%s: tx frame #%d is busy.\n", - dev->name, np->dirty_tx); + if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) break; - } - if (debug > 4) - printk(KERN_DEBUG "%s: tx frame #%d finished with status %8.8xh.\n", + if (netif_msg_tx_done(np)) + printk(KERN_DEBUG + "%s: tx frame #%d finished, status %#08x.\n", dev->name, np->dirty_tx, le32_to_cpu(np->tx_ring[entry].cmd_status)); if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescPktOK)) { @@ -1495,30 +1582,31 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = dev_instance; - struct netdev_private *np; - long ioaddr; + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; int boguscnt = max_interrupt_work; - ioaddr = dev->base_addr; - np = dev->priv; - if (!netif_device_present(dev)) return; do { /* Reading automatically acknowledges all int sources. */ u32 intr_status = readl(ioaddr + IntrStatus); - if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + if (netif_msg_intr(np)) + printk(KERN_DEBUG "%s: Interrupt, status %#08x.\n", dev->name, intr_status); if (intr_status == 0) break; - if (intr_status & (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | IntrRxErr | IntrRxOverrun )) + if (intr_status & + (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | + IntrRxErr | IntrRxOverrun)) { netdev_rx(dev); + } - if (intr_status & (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr) ) { + if (intr_status & + (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) { spin_lock(&np->lock); netdev_tx_done(dev); spin_unlock(&np->lock); @@ -1529,16 +1617,16 @@ netdev_error(dev, intr_status); if (--boguscnt < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, " - "status=0x%4.4x.\n", - dev->name, intr_status); + if (netif_msg_intr(np)) + printk(KERN_WARNING + "%s: Too much work at interrupt, " + "status=%#08x.\n", dev->name, intr_status); break; } } while (1); - if (debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt.\n", - dev->name); + if (netif_msg_intr(np)) + printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name); } /* This routine is logically part of the interrupt handler, but separated @@ -1552,22 +1640,24 @@ /* If the driver owns the next entry it's a new packet. Send it up. */ while (desc_status < 0) { /* e.g. & DescOwn */ - if (debug > 4) - printk(KERN_DEBUG " In netdev_rx() entry %d status was %8.8x.\n", - entry, desc_status); + if (netif_msg_rx_status(np)) + printk(KERN_DEBUG + " netdev_rx() entry %d status was %#08x.\n", + entry, desc_status); if (--boguscnt < 0) break; - if ((desc_status & (DescMore|DescPktOK|DescRxLong)) != DescPktOK) { + if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){ if (desc_status & DescMore) { - printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " - "multiple buffers, entry %#x status %x.\n", - dev->name, np->cur_rx, desc_status); + if (netif_msg_rx_err(np)) + printk(KERN_WARNING + "%s: Oversized(?) Ethernet " + "frame spanned multiple " + "buffers, entry %#08x " + "status %#08x.\n", dev->name, + np->cur_rx, desc_status); np->stats.rx_length_errors++; } else { - /* There was a error. */ - if (debug > 2) - printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", - desc_status); + /* There was an error. */ np->stats.rx_errors++; if (desc_status & (DescRxAbort|DescRxOver)) np->stats.rx_over_errors++; @@ -1582,8 +1672,8 @@ struct sk_buff *skb; /* Omit CRC size. */ int pkt_len = (desc_status & DescSizeMask) - 4; - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ + /* Check if the packet is long enough to accept + * without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; @@ -1646,11 +1736,16 @@ spin_lock(&np->lock); if (intr_status & LinkChange) { - printk(KERN_NOTICE - "%s: Link changed: Autonegotiation advertising" - " %4.4x partner %4.4x.\n", dev->name, - (int)mdio_read(dev, 1, MII_ADVERTISE), - (int)mdio_read(dev, 1, MII_LPA)); + u16 adv = mdio_read(dev, 1, MII_ADVERTISE); + u16 lpa = mdio_read(dev, 1, MII_LPA); + if (mdio_read(dev, 1, MII_BMCR) & BMCR_ANENABLE + && netif_msg_link(np)) { + printk(KERN_INFO + "%s: Autonegotiation advertising" + " %#04x partner %#04x.\n", dev->name, + adv, lpa); + } + /* read MII int status to clear the flag */ readw(ioaddr + MIntrStatus); check_link(dev); @@ -1661,29 +1756,28 @@ if (intr_status & IntrTxUnderrun) { if ((np->tx_config & TxDrthMask) < 62) np->tx_config += 2; - if (debug > 2) - printk(KERN_NOTICE "%s: increasing Tx threshold, new tx cfg %8.8xh.\n", - dev->name, np->tx_config); + if (netif_msg_tx_err(np)) + printk(KERN_NOTICE + "%s: increased Tx threshold, txcfg %#08x.\n", + dev->name, np->tx_config); writel(np->tx_config, ioaddr + TxConfig); } - if (intr_status & WOLPkt) { + if (intr_status & WOLPkt && netif_msg_wol(np)) { int wol_status = readl(ioaddr + WOLCmd); - printk(KERN_NOTICE "%s: Link wake-up event %8.8x\n", + printk(KERN_NOTICE "%s: Link wake-up event %#08x\n", dev->name, wol_status); } if (intr_status & RxStatusFIFOOver) { - if (debug >= 2) { - printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", + if (netif_msg_rx_err(np) && netif_msg_intr(np)) { + printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", dev->name); } np->stats.rx_fifo_errors++; } /* Hmmmmm, it's not clear how to recover from PCI faults. */ if (intr_status & IntrPCIErr) { - if (debug) { - printk(KERN_NOTICE "%s: PCI error %08x\n", dev->name, - intr_status & IntrPCIErr); - } + printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name, + intr_status & IntrPCIErr); np->stats.tx_fifo_errors++; np->stats.rx_fifo_errors++; } @@ -1761,7 +1855,8 @@ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ - printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", + dev->name); rx_mode = RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys; } else if ((dev->mc_count > multicast_filter_limit) @@ -1896,7 +1991,7 @@ /* get message-level */ case ETHTOOL_GMSGLVL: { struct ethtool_value edata = {ETHTOOL_GMSGLVL}; - edata.data = debug; + edata.data = np->msg_enable; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; @@ -1906,7 +2001,7 @@ struct ethtool_value edata; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; - debug = edata.data; + np->msg_enable = edata.data; return 0; } /* restart autonegotiation */ @@ -1941,6 +2036,9 @@ if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) return -EFAULT; + if (eeprom.offset > eeprom.offset+eeprom.len) + return -EINVAL; + if ((eeprom.offset+eeprom.len) > NATSEMI_EEPROM_SIZE) { eeprom.len = NATSEMI_EEPROM_SIZE-eeprom.offset; } @@ -2096,18 +2194,22 @@ ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_TP); + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); - /* only supports twisted-pair */ - ecmd->port = PORT_TP; + /* only supports twisted-pair or MII */ + tmp = readl(dev->base_addr + ChipConfig); + if (tmp & CfgExtPhy) + ecmd->port = PORT_MII; + else + ecmd->port = PORT_TP; /* only supports internal transceiver */ ecmd->transceiver = XCVR_INTERNAL; - /* this isn't fully supported at higher layers */ + /* not sure what this is for */ ecmd->phy_address = readw(dev->base_addr + PhyCtrl) & PhyAddrMask; - ecmd->advertising = ADVERTISED_TP; + ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; tmp = mdio_read(dev, 1, MII_ADVERTISE); if (tmp & ADVERTISE_10HALF) ecmd->advertising |= ADVERTISED_10baseT_Half; @@ -2118,20 +2220,21 @@ if (tmp & ADVERTISE_100FULL) ecmd->advertising |= ADVERTISED_100baseT_Full; - tmp = readl(dev->base_addr + ChipConfig); - if (tmp & CfgAnegEnable) { + tmp = mdio_read(dev, 1, MII_BMCR); + if (tmp & BMCR_ANENABLE) { ecmd->advertising |= ADVERTISED_Autoneg; ecmd->autoneg = AUTONEG_ENABLE; } else { ecmd->autoneg = AUTONEG_DISABLE; } + tmp = readl(dev->base_addr + ChipConfig); if (tmp & CfgSpeed100) { ecmd->speed = SPEED_100; } else { ecmd->speed = SPEED_10; } - + if (tmp & CfgFullDuplex) { ecmd->duplex = DUPLEX_FULL; } else { @@ -2152,7 +2255,7 @@ return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; - if (ecmd->port != PORT_TP) + if (ecmd->port != PORT_TP && ecmd->port != PORT_MII) return -EINVAL; if (ecmd->transceiver != XCVR_INTERNAL) return -EINVAL; @@ -2162,39 +2265,22 @@ /* WHEW! now lets bang some bits */ + tmp = mdio_read(dev, 1, MII_BMCR); if (ecmd->autoneg == AUTONEG_ENABLE) { - /* advertise only what has been requested */ - tmp = readl(dev->base_addr + ChipConfig); - tmp &= ~(CfgAneg100 | CfgAnegFull); - tmp |= CfgAnegEnable; - if (ecmd->advertising & ADVERTISED_100baseT_Half - || ecmd->advertising & ADVERTISED_100baseT_Full) { - tmp |= CfgAneg100; - } - if (ecmd->advertising & ADVERTISED_10baseT_Full - || ecmd->advertising & ADVERTISED_100baseT_Full) { - tmp |= CfgAnegFull; - } - writel(tmp, dev->base_addr + ChipConfig); - /* turn on autonegotiation, and force a renegotiate */ - tmp = mdio_read(dev, 1, MII_BMCR); - tmp |= (BMCR_ANENABLE | BMCR_ANRESTART); - mdio_write(dev, 1, MII_BMCR, tmp); + /* turn on autonegotiation */ + tmp |= BMCR_ANENABLE; np->advertising = mdio_read(dev, 1, MII_ADVERTISE); } else { /* turn off auto negotiation, set speed and duplexity */ - tmp = mdio_read(dev, 1, MII_BMCR); tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); - if (ecmd->speed == SPEED_100) { + if (ecmd->speed == SPEED_100) tmp |= BMCR_SPEED100; - } - if (ecmd->duplex == DUPLEX_FULL) { + if (ecmd->duplex == DUPLEX_FULL) tmp |= BMCR_FULLDPLX; - } else { + else np->full_duplex = 0; - } - mdio_write(dev, 1, MII_BMCR, tmp); } + mdio_write(dev, 1, MII_BMCR, tmp); return 0; } @@ -2229,7 +2315,7 @@ /* the interrupt status is clear-on-read - see if we missed any */ if (rbuf[4] & rbuf[5]) { printk(KERN_WARNING - "%s: shoot, we dropped an interrupt (0x%x)\n", + "%s: shoot, we dropped an interrupt (%#08x)\n", dev->name, rbuf[4] & rbuf[5]); } @@ -2296,7 +2382,7 @@ long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; - if (debug > 1) + if (netif_msg_wol(np)) printk(KERN_INFO "%s: remaining active for wake-on-lan\n", dev->name); @@ -2319,7 +2405,8 @@ /* enable the WOL interrupt. * Could be used to send a netlink message. */ - writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask); + writel(WOLPkt | LinkChange, ioaddr + IntrMask); + writel(1, ioaddr + IntrEnable); } } @@ -2331,12 +2418,15 @@ netif_stop_queue(dev); netif_carrier_off(dev); - if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", - dev->name, (int)readl(ioaddr + ChipCmd)); - printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", - dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); - } + if (netif_msg_ifdown(np)) + printk(KERN_DEBUG + "%s: Shutting down ethercard, status was %#04x.\n", + dev->name, (int)readl(ioaddr + ChipCmd)); + if (netif_msg_pktdata(np)) + printk(KERN_DEBUG + "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, + np->cur_rx, np->dirty_rx); del_timer_sync(&np->timer); @@ -2375,7 +2465,7 @@ drain_ring(dev); free_ring(dev); - { + { u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary; if (wol) { /* restart the NIC in WOL mode. diff -Nru a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c --- a/drivers/net/pci-skeleton.c Fri Sep 20 08:20:41 2002 +++ b/drivers/net/pci-skeleton.c Fri Sep 20 08:20:41 2002 @@ -1411,10 +1411,6 @@ tp->stats.tx_carrier_errors++; if (txstatus & TxOutOfWindow) tp->stats.tx_window_errors++; -#ifdef ETHER_STATS - if ((txstatus & 0x0f000000) == 0x0f000000) - tp->stats.collisions16++; -#endif } else { if (txstatus & TxUnderrun) { /* Add 64 to the Tx FIFO threshold. */ diff -Nru a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c --- a/drivers/net/pcmcia/axnet_cs.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/pcmcia/axnet_cs.c Fri Sep 20 08:20:46 2002 @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -817,6 +819,27 @@ add_timer(&info->watchdog); } +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + + strncpy(info.driver, "axnet_cs", sizeof(info.driver)-1); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + /*====================================================================*/ static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) @@ -825,6 +848,8 @@ u16 *data = (u16 *)&rq->ifr_data; ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP; switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCDEVPRIVATE: data[0] = info->phy_id; case SIOCDEVPRIVATE+1: diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c --- a/drivers/net/pcmcia/pcnet_cs.c Fri Sep 20 08:20:47 2002 +++ b/drivers/net/pcmcia/pcnet_cs.c Fri Sep 20 08:20:47 2002 @@ -66,7 +66,7 @@ #define SOCKET_START_PG 0x01 #define SOCKET_STOP_PG 0xff -#define PCNET_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */ +#define PCNET_RDC_TIMEOUT (2*HZ/100) /* Max wait in jiffies for Tx RDC */ static char *if_names[] = { "auto", "10baseT", "10base2"}; @@ -1188,7 +1188,7 @@ } info->link_status = link; } - if (info->pna_phy && (jiffies - info->mii_reset > 6*HZ)) { + if (info->pna_phy && time_after(jiffies, info->mii_reset + 6*HZ)) { link = mdio_read(mii_addr, info->eth_phy, 1) & 0x0004; if (((info->phy_id == info->pna_phy) && link) || ((info->phy_id != info->pna_phy) && !link)) { @@ -1426,7 +1426,7 @@ #endif while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) - if (jiffies - dma_start > PCNET_RDC_TIMEOUT) { + if (time_after(jiffies, dma_start + PCNET_RDC_TIMEOUT)) { printk(KERN_NOTICE "%s: timeout waiting for Tx RDC.\n", dev->name); pcnet_reset_8390(dev); diff -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c --- a/drivers/net/ppp_generic.c Fri Sep 20 08:20:48 2002 +++ b/drivers/net/ppp_generic.c Fri Sep 20 08:20:48 2002 @@ -1401,7 +1401,7 @@ if (skb->len > 0) /* note: a 0-length skb is used as an error indication */ ++ppp->stats.rx_length_errors; -err: + kfree_skb(skb); ppp_receive_error(ppp); } diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c --- a/drivers/net/sundance.c Fri Sep 20 08:20:47 2002 +++ b/drivers/net/sundance.c Fri Sep 20 08:20:47 2002 @@ -18,26 +18,62 @@ http://www.scyld.com/network/sundance.html - Version 1.01a (jgarzik): + Version LK1.01a (jgarzik): - Replace some MII-related magic numbers with constants - Version 1.02 (D-Link): + Version LK1.02 (D-Link): - Add new board to PCI ID list - Fix multicast bug + Version LK1.03 (D-Link): + - New Rx scheme, reduce Rx congestion + - Option to disable flow control + + Version LK1.04 (D-Link): + - Tx timeout recovery + - More support for ethtool. + + Version LK1.04a: + - Remove unused/constant members from struct pci_id_info + (which then allows removal of 'drv_flags' from private struct) + (jgarzik) + - If no phy is found, fail to load that board (jgarzik) + - Always start phy id scan at id 1 to avoid problems (Donald Becker) + - Autodetect where mii_preable_required is needed, + default to not needed. (Donald Becker) + + Version LK1.04b: + - Remove mii_preamble_required module parameter (Donald Becker) + - Add per-interface mii_preamble_required (setting is autodetected) + (Donald Becker) + - Remove unnecessary cast from void pointer (jgarzik) + - Re-align comments in private struct (jgarzik) + + Version LK1.04c (jgarzik): + - Support bitmapped message levels (NETIF_MSG_xxx), and the + two ethtool ioctls that get/set them + - Don't hand-code MII ethtool support, use standard API/lib + + Version LK1.04d: + - Merge from Donald Becker's sundance.c: (Jason Lunz) + * proper support for variably-sized MTUs + * default to PIO, to fix chip bugs + - Add missing unregister_netdev (Jason Lunz) + - Add CONFIG_SUNDANCE_MMIO config option (jgarzik) + - Better rx buf size calculation (Donald Becker) + */ #define DRV_NAME "sundance" -#define DRV_VERSION "1.02" -#define DRV_RELDATE "17-Jan-2002" +#define DRV_VERSION "1.01+LK1.04d" +#define DRV_RELDATE "19-Sep-2002" /* The user-configurable values. These may be modified when a driver module is loaded.*/ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 30; -static int mtu; +static int max_interrupt_work = 0; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). Typical is a 64 element hash table based on the Ethernet CRC. */ static int multicast_filter_limit = 32; @@ -47,6 +83,8 @@ This chip can receive into offset buffers, so the Alpha does not need a copy-align. */ static int rx_copybreak; +static int tx_coalesce=1; +static int flowctrl=1; /* media[] specifies the media type the NIC operates at. autosense Autosensing active media. @@ -60,8 +98,10 @@ 3 100Mbps half duplex. 4 100Mbps full duplex. */ -#define MAX_UNITS 8 +#define MAX_UNITS 8 static char *media[MAX_UNITS]; + + /* Operational parameters that are set at compile time. */ /* Keep the ring sizes a power of two for compile efficiency. @@ -70,9 +110,10 @@ bonding and packet priority, and more than 128 requires modifying the Tx error recovery. Large receive rings merely waste memory. */ -#define TX_RING_SIZE 16 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ -#define RX_RING_SIZE 32 +#define TX_RING_SIZE 64 +#define TX_QUEUE_LEN (TX_RING_SIZE - 1) /* Limit ring entries actually used. */ +#define RX_RING_SIZE 64 +#define RX_BUDGET 32 #define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct netdev_desc) #define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct netdev_desc) @@ -107,13 +148,17 @@ #include #include #include -#include #include #include /* Processor type for cache alignment. */ #include #include #include #include +#ifndef _LOCAL_CRC32 +#include +#else +#include "crc32.h" +#endif /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = @@ -125,14 +170,15 @@ MODULE_LICENSE("GPL"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(mtu, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s"); +MODULE_PARM(flowctrl, "i"); MODULE_PARM_DESC(max_interrupt_work, "Sundance Alta maximum events handled per interrupt"); -MODULE_PARM_DESC(mtu, "Sundance Alta MTU (all boards)"); MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)"); MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]"); + /* Theory of Operation @@ -207,20 +253,9 @@ */ - - -enum pci_id_flags_bits { - /* Set PCI command register bits before calling probe1(). */ - PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, - /* Read and map the single following PCI BAR. */ - PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, - PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, -}; -enum chip_capability_flags {CanHaveMII=1, }; -#ifdef USE_IO_OPS -#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) -#else -#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) +/* Work-around for Kendin chip bugs. */ +#ifndef CONFIG_SUNDANCE_MMIO +#define USE_IO_OPS 1 #endif static struct pci_device_id sundance_pci_tbl[] __devinitdata = { @@ -234,31 +269,20 @@ }; MODULE_DEVICE_TABLE(pci, sundance_pci_tbl); +enum { + netdev_io_size = 128 +}; + struct pci_id_info { const char *name; - struct match_info { - int pci, pci_mask, subsystem, subsystem_mask; - int revision, revision_mask; /* Only 8 bits. */ - } id; - enum pci_id_flags_bits pci_flags; - int io_size; /* Needed for I/O region check or ioremap(). */ - int drv_flags; /* Driver use, intended as capability flags. */ }; static struct pci_id_info pci_id_tbl[] = { - {"D-Link DFE-550TX FAST Ethernet Adapter", {0x10021186, 0xffffffff,}, - PCI_IOTYPE, 128, CanHaveMII}, - {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter", - {0x10031186, 0xffffffff,}, - PCI_IOTYPE, 128, CanHaveMII}, - {"D-Link DFE-580TX 4 port Server Adapter", {0x10121186, 0xffffffff,}, - PCI_IOTYPE, 128, CanHaveMII}, - {"D-Link DFE-530TXS FAST Ethernet Adapter", {0x10021186, 0xffffffff,}, - PCI_IOTYPE, 128, CanHaveMII}, - {"D-Link DL10050-based FAST Ethernet Adapter", - {0x10021186, 0xffffffff,}, - PCI_IOTYPE, 128, CanHaveMII}, - {"Sundance Technology Alta", {0x020113F0, 0xffffffff,}, - PCI_IOTYPE, 128, CanHaveMII}, + {"D-Link DFE-550TX FAST Ethernet Adapter"}, + {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"}, + {"D-Link DFE-580TX 4 port Server Adapter"}, + {"D-Link DFE-530TXS FAST Ethernet Adapter"}, + {"D-Link DL10050-based FAST Ethernet Adapter"}, + {"Sundance Technology Alta"}, {0,}, /* 0 terminated list. */ }; @@ -290,20 +314,24 @@ enum alta_offsets { DMACtrl = 0x00, TxListPtr = 0x04, - TxDMACtrl = 0x08, - TxDescPoll = 0x0a, + TxDMABurstThresh = 0x08, + TxDMAUrgentThresh = 0x09, + TxDMAPollPeriod = 0x0a, RxDMAStatus = 0x0c, RxListPtr = 0x10, - RxDMACtrl = 0x14, - RxDescPoll = 0x16, + RxDMABurstThresh = 0x14, + RxDMAUrgentThresh = 0x15, + RxDMAPollPeriod = 0x16, LEDCtrl = 0x1a, ASICCtrl = 0x30, EEData = 0x34, EECtrl = 0x36, - TxThreshold = 0x3c, + TxStartThresh = 0x3c, + RxEarlyThresh = 0x3e, FlashAddr = 0x40, FlashData = 0x44, TxStatus = 0x46, + TxFrameId = 0x47, DownCounter = 0x18, IntrClear = 0x4a, IntrEnable = 0x4c, @@ -311,7 +339,7 @@ MACCtrl0 = 0x50, MACCtrl1 = 0x52, StationAddr = 0x54, - MaxTxSize = 0x5A, + MaxFrameSize = 0x5A, RxMode = 0x5c, MIICtrl = 0x5e, MulticastFilter0 = 0x60, @@ -337,6 +365,16 @@ /* Aliased and bogus values! */ RxStatus = 0x0c, }; +enum ASICCtrl_HiWord_bit { + GlobalReset = 0x0001, + RxReset = 0x0002, + TxReset = 0x0004, + DMAReset = 0x0008, + FIFOReset = 0x0010, + NetworkReset = 0x0020, + HostReset = 0x0040, + ResetBusy = 0x0400, +}; /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { @@ -396,35 +434,40 @@ dma_addr_t tx_ring_dma; dma_addr_t rx_ring_dma; struct net_device_stats stats; - struct timer_list timer; /* Media monitoring timer. */ + struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */ spinlock_t lock; - int chip_id, drv_flags; + spinlock_t rx_lock; /* Group with Tx control cache line. */ + int msg_enable; + int chip_id; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - spinlock_t txlock; /* Group with Tx control cache line. */ + unsigned int rx_buf_sz; /* Based on MTU+slack. */ struct netdev_desc *last_tx; /* Last Tx descriptor used. */ unsigned int cur_tx, dirty_tx; - unsigned int tx_full:1; /* The Tx queue is full. */ /* These values are keep track of the transceiver/media in use. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int medialock:1; /* Do not sense media. */ + unsigned int flowctrl:1; unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int an_enable:1; unsigned int speed; + struct tasklet_struct rx_tasklet; + int budget; /* Multicast and receive mode. */ - spinlock_t mcastlock; /* SMP lock multicast updates. */ + spinlock_t mcastlock; /* SMP lock multicast updates. */ u16 mcast_filter[4]; /* MII transceiver section. */ - int mii_cnt; /* MII device addresses. */ - u16 advertising; /* NWay media advertisement */ + struct mii_if_info mii_if; + int mii_preamble_required; unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ struct pci_dev *pci_dev; }; /* The station address location in the EEPROM. */ #define EEPROM_SA_OFFSET 0x10 +#define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \ + IntrDrvRqst | IntrTxDone | StatsMax | \ + LinkChange) +static int change_mtu(struct net_device *dev, int new_mtu); static int eeprom_read(long ioaddr, int location); static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); @@ -434,16 +477,18 @@ static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); +static int reset_tx (struct net_device *dev, int irq); static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static void rx_poll(unsigned long data); +static void refill_rx (struct net_device *dev); static void netdev_error(struct net_device *dev, int intr_status); -static int netdev_rx(struct net_device *dev); static void netdev_error(struct net_device *dev, int intr_status); static void set_rx_mode(struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct net_device *dev); - + static int __devinit sundance_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -485,7 +530,7 @@ ioaddr = pci_resource_start(pdev, 0); #else ioaddr = pci_resource_start(pdev, 1); - ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size); + ioaddr = (long) ioremap (ioaddr, netdev_io_size); if (!ioaddr) goto err_out_res; #endif @@ -498,10 +543,11 @@ dev->irq = irq; np = dev->priv; - np->chip_id = chip_idx; - np->drv_flags = pci_id_tbl[chip_idx].drv_flags; np->pci_dev = pdev; + np->chip_id = chip_idx; + np->msg_enable = (1 << debug) - 1; spin_lock_init(&np->lock); + tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev); ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); if (!ring_space) @@ -515,6 +561,10 @@ np->rx_ring = (struct netdev_desc *)ring_space; np->rx_ring_dma = ring_dma; + np->mii_if.dev = dev; + np->mii_if.mdio_read = mdio_read; + np->mii_if.mdio_write = mdio_write; + /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; dev->hard_start_xmit = &start_tx; @@ -524,11 +574,9 @@ dev->do_ioctl = &netdev_ioctl; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + dev->change_mtu = &change_mtu; pci_set_drvdata(pdev, dev); - if (mtu) - dev->mtu = mtu; - i = register_netdev(dev); if (i) goto err_out_unmap_rx; @@ -542,21 +590,30 @@ if (1) { int phy, phy_idx = 0; np->phys[0] = 1; /* Default setting */ - for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, 1); + np->mii_preamble_required++; + for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { + int mii_status = mdio_read(dev, phy, MII_BMSR); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; - np->advertising = mdio_read(dev, phy, 4); + np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); + if ((mii_status & 0x0040) == 0) + np->mii_preamble_required++; printk(KERN_INFO "%s: MII PHY found at address %d, status " "0x%4.4x advertising %4.4x.\n", - dev->name, phy, mii_status, np->advertising); + dev->name, phy, mii_status, np->mii_if.advertising); } } - np->mii_cnt = phy_idx; - if (phy_idx == 0) - printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n", + np->mii_preamble_required--; + + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", dev->name, readl(ioaddr + ASICCtrl)); + goto err_out_unregister; + } + + np->mii_if.phy_id = np->phys[0]; } + /* Parse override configuration */ np->an_enable = 1; if (card_idx < MAX_UNITS) { @@ -565,23 +622,29 @@ if (strcmp (media[card_idx], "100mbps_fd") == 0 || strcmp (media[card_idx], "4") == 0) { np->speed = 100; - np->full_duplex = 1; + np->mii_if.full_duplex = 1; } else if (strcmp (media[card_idx], "100mbps_hd") == 0 || strcmp (media[card_idx], "3") == 0) { np->speed = 100; - np->full_duplex = 0; + np->mii_if.full_duplex = 0; } else if (strcmp (media[card_idx], "10mbps_fd") == 0 || strcmp (media[card_idx], "2") == 0) { np->speed = 10; - np->full_duplex = 1; + np->mii_if.full_duplex = 1; } else if (strcmp (media[card_idx], "10mbps_hd") == 0 || strcmp (media[card_idx], "1") == 0) { np->speed = 10; - np->full_duplex = 0; + np->mii_if.full_duplex = 0; } else { np->an_enable = 1; } } + if (tx_coalesce < 1) + tx_coalesce = 1; + else if (tx_coalesce > TX_QUEUE_LEN - 1) + tx_coalesce = TX_QUEUE_LEN - 1; + if (flowctrl == 0) + np->flowctrl = 0; } /* Fibre PHY? */ @@ -589,7 +652,7 @@ /* Default 100Mbps Full */ if (np->an_enable) { np->speed = 100; - np->full_duplex = 1; + np->mii_if.full_duplex = 1; np->an_enable = 0; } } @@ -601,24 +664,26 @@ if (!np->an_enable) { mii_ctl = 0; mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0; - mii_ctl |= (np->full_duplex) ? BMCR_FULLDPLX : 0; + mii_ctl |= (np->mii_if.full_duplex) ? BMCR_FULLDPLX : 0; mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl); printk (KERN_INFO "Override speed=%d, %s duplex\n", - np->speed, np->full_duplex ? "Full" : "Half"); + np->speed, np->mii_if.full_duplex ? "Full" : "Half"); } /* Perhaps move the reset here? */ /* Reset the chip to erase previous misconfiguration. */ - if (debug > 1) + if (netif_msg_hw(np)) printk("ASIC Control is %x.\n", readl(ioaddr + ASICCtrl)); writew(0x007f, ioaddr + ASICCtrl + 2); - if (debug > 1) + if (netif_msg_hw(np)) printk("ASIC Control is now %x.\n", readl(ioaddr + ASICCtrl)); card_idx++; return 0; +err_out_unregister: + unregister_netdev(dev); err_out_unmap_rx: pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); err_out_unmap_tx: @@ -635,7 +700,16 @@ return -ENODEV; } - +static int change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > 8191)) /* Set by RxDMAFrameLen */ + return -EINVAL; + if (netif_running(dev)) + return -EBUSY; + dev->mtu = new_mtu; + return 0; +} + /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */ static int __devinit eeprom_read(long ioaddr, int location) { @@ -658,11 +732,6 @@ met by back-to-back 33Mhz PCI cycles. */ #define mdio_delay() readb(mdio_addr) -/* Set iff a MII transceiver on any interface requires mdio preamble. - This only set with older tranceivers, so the extra - code size of a per-interface flag is not worthwhile. */ -static const char mii_preamble_required = 1; - enum mii_reg_bits { MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004, }; @@ -687,11 +756,12 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) { + struct netdev_private *np = dev->priv; long mdio_addr = dev->base_addr + MIICtrl; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int i, retval = 0; - if (mii_preamble_required) + if (np->mii_preamble_required) mdio_sync(mdio_addr); /* Shift the read command bits out. */ @@ -716,11 +786,12 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { + struct netdev_private *np = dev->priv; long mdio_addr = dev->base_addr + MIICtrl; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; - if (mii_preamble_required) + if (np->mii_preamble_required) mdio_sync(mdio_addr); /* Shift the command bits out. */ @@ -742,7 +813,6 @@ return; } - static int netdev_open(struct net_device *dev) { struct netdev_private *np = dev->priv; @@ -755,7 +825,7 @@ if (i) return i; - if (debug > 1) + if (netif_msg_ifup(np)) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", dev->name, dev->irq); @@ -768,6 +838,10 @@ writeb(dev->dev_addr[i], ioaddr + StationAddr + i); /* Initialize other registers. */ + writew(dev->mtu + 14, ioaddr + MaxFrameSize); + if (dev->mtu > 2047) + writel(readl(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl); + /* Configure the PCI bus bursts and FIFO thresholds. */ if (dev->if_port == 0) @@ -779,17 +853,13 @@ writew(0, ioaddr + IntrEnable); writew(0, ioaddr + DownCounter); /* Set the chip to poll every N*320nsec. */ - writeb(100, ioaddr + RxDescPoll); - writeb(127, ioaddr + TxDescPoll); + writeb(100, ioaddr + RxDMAPollPeriod); + writeb(127, ioaddr + TxDMAPollPeriod); netif_start_queue(dev); - /* Enable interrupts by setting the interrupt mask. */ - writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone - | StatsMax | LinkChange, ioaddr + IntrEnable); - writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); - if (debug > 2) + if (netif_msg_ifup(np)) printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x " "MAC Control %x, %4.4x %4.4x.\n", dev->name, readl(ioaddr + RxStatus), readb(ioaddr + TxStatus), @@ -803,6 +873,9 @@ np->timer.function = &netdev_timer; /* timer handler */ add_timer(&np->timer); + /* Enable interrupts by setting the interrupt mask. */ + writew(DEFAULT_INTR, ioaddr + IntrEnable); + return 0; } @@ -811,21 +884,22 @@ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); - int negotiated = mii_lpa & np->advertising; + int negotiated = mii_lpa & np->mii_if.advertising; int duplex; - + /* Force media */ if (!np->an_enable || mii_lpa == 0xffff) { - if (np->full_duplex) + if (np->mii_if.full_duplex) writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex, ioaddr + MACCtrl0); return; } + /* Autonegotiation */ duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - if (np->full_duplex != duplex) { - np->full_duplex = duplex; - if (debug) + if (np->mii_if.full_duplex != duplex) { + np->mii_if.full_duplex = duplex; + if (netif_msg_link(np)) printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d " "negotiated capability %4.4x.\n", dev->name, duplex ? "full" : "half", np->phys[0], negotiated); @@ -840,7 +914,7 @@ long ioaddr = dev->base_addr; int next_tick = 10*HZ; - if (debug > 3) { + if (netif_msg_timer(np)) { printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, " "Tx %x Rx %x.\n", dev->name, readw(ioaddr + IntrEnable), @@ -855,9 +929,12 @@ { struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; + long flag; - printk(KERN_WARNING "%s: Transmit timed out, status %2.2x," - " resetting...\n", dev->name, readb(ioaddr + TxStatus)); + printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x " + "TxFrameId %2.2x," + " resetting...\n", dev->name, readb(ioaddr + TxStatus), + readb(ioaddr + TxFrameId)); { int i; @@ -866,22 +943,24 @@ printk(" %8.8x", (unsigned int)np->rx_ring[i].status); printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) - printk(" %4.4x", np->tx_ring[i].status); + printk(" %8.8x", np->tx_ring[i].status); printk("\n"); } + spin_lock_irqsave(&np->lock, flag); + reset_tx(dev, 0); + spin_unlock_irqrestore(&np->lock, flag); /* Perhaps we should reinitialize the hardware here. */ dev->if_port = 0; /* Stop and restart the chip's Tx processes . */ /* Trigger an immediate transmit demand. */ - writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone - | StatsMax | LinkChange, ioaddr + IntrEnable); + writew(DEFAULT_INTR, ioaddr + IntrEnable); dev->trans_start = jiffies; np->stats.tx_errors++; - if (!np->tx_full) + if (!netif_queue_stopped(dev)) netif_wake_queue(dev); } @@ -892,15 +971,14 @@ struct netdev_private *np = dev->priv; int i; - np->tx_full = 0; np->cur_rx = np->cur_tx = 0; np->dirty_rx = np->dirty_tx = 0; - np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + np->rx_buf_sz = (dev->mtu <= 1520 ? PKT_BUF_SZ : dev->mtu + 16); /* Initialize all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma + + np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma + ((i+1)%RX_RING_SIZE)*sizeof(*np->rx_ring)); np->rx_ring[i].status = 0; np->rx_ring[i].frag[0].length = 0; @@ -916,7 +994,7 @@ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ np->rx_ring[i].frag[0].addr = cpu_to_le32( - pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, + pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag); } @@ -929,15 +1007,16 @@ return; } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static int +start_tx (struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = dev->priv; struct netdev_desc *txdesc; unsigned entry; + long ioaddr = dev->base_addr; /* Note: Ordering is important here, set the field with the "ownership" bit last, and only then increment cur_tx. */ - /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; np->tx_skbuff[entry] = skb; @@ -945,11 +1024,17 @@ txdesc->next_desc = 0; /* Note: disable the interrupt generation here before releasing. */ - txdesc->status = - cpu_to_le32((entry<<2) | DescIntrOnDMADone | DescIntrOnTx | DisableAlign); - txdesc->frag[0].addr = cpu_to_le32(pci_map_single(np->pci_dev, - skb->data, skb->len, PCI_DMA_TODEVICE)); - txdesc->frag[0].length = cpu_to_le32(skb->len | LastFrag); + if (entry % tx_coalesce == 0) { + txdesc->status = cpu_to_le32 ((entry << 2) | + DescIntrOnTx | DisableAlign); + + } else { + txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign); + } + txdesc->frag[0].addr = cpu_to_le32 (pci_map_single (np->pci_dev, skb->data, + skb->len, + PCI_DMA_TODEVICE)); + txdesc->frag[0].length = cpu_to_le32 (skb->len | LastFrag); if (np->last_tx) np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma + entry*sizeof(struct netdev_desc)); @@ -957,24 +1042,63 @@ np->cur_tx++; /* On some architectures: explicitly flush cache lines here. */ - - if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1) { + if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1 + && !netif_queue_stopped(dev)) { /* do nothing */ } else { - np->tx_full = 1; - netif_stop_queue(dev); + netif_stop_queue (dev); } /* Side effect: The read wakes the potentially-idle transmit channel. */ - if (readl(dev->base_addr + TxListPtr) == 0) - writel(np->tx_ring_dma + entry*sizeof(*np->tx_ring), + if (readl (dev->base_addr + TxListPtr) == 0) + writel (np->tx_ring_dma + entry*sizeof(*np->tx_ring), dev->base_addr + TxListPtr); dev->trans_start = jiffies; - if (debug > 4) { - printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", - dev->name, np->cur_tx, entry); + if (netif_msg_tx_queued(np)) { + printk (KERN_DEBUG + "%s: Transmit frame #%d queued in slot %d.\n", + dev->name, np->cur_tx, entry); + } + if (tx_coalesce > 1) + writel (1000, ioaddr + DownCounter); + return 0; +} +static int +reset_tx (struct net_device *dev, int irq) +{ + struct netdev_private *np = (struct netdev_private*) dev->priv; + long ioaddr = dev->base_addr; + int i; + int frame_id; + + frame_id = readb(ioaddr + TxFrameId); + writew (TxReset | DMAReset | FIFOReset | NetworkReset, + ioaddr + ASICCtrl + 2); + for (i=50; i > 0; i--) { + if ((readw(ioaddr + ASICCtrl + 2) & ResetBusy) == 0) + break; + mdelay(1); + } + for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { + int entry = np->dirty_tx % TX_RING_SIZE; + struct sk_buff *skb; + if (!(np->tx_ring[entry].status & 0x00010000)) + break; + skb = np->tx_skbuff[entry]; + /* Free the original skb. */ + pci_unmap_single(np->pci_dev, + np->tx_ring[entry].frag[0].addr, + skb->len, PCI_DMA_TODEVICE); + if (irq) + dev_kfree_skb_irq (np->tx_skbuff[entry]); + else + dev_kfree_skb (np->tx_skbuff[entry]); + + np->tx_skbuff[entry] = 0; } + writel (np->tx_ring_dma + frame_id * sizeof(*np->tx_ring), + dev->base_addr + TxListPtr); return 0; } @@ -989,139 +1113,131 @@ ioaddr = dev->base_addr; np = dev->priv; - spin_lock(&np->lock); do { int intr_status = readw(ioaddr + IntrStatus); - writew(intr_status & (IntrRxDone | IntrRxDMADone | IntrPCIErr | - IntrDrvRqst | IntrTxDone | IntrTxDMADone | StatsMax | - LinkChange), ioaddr + IntrStatus); + writew(intr_status, ioaddr + IntrStatus); - if (debug > 4) + if (netif_msg_intr(np)) printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", dev->name, intr_status); - if (intr_status == 0) + if (!(intr_status & DEFAULT_INTR)) break; - if (intr_status & (IntrRxDone|IntrRxDMADone)) - netdev_rx(dev); + if (intr_status & (IntrRxDMADone)) { + writew(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone), + ioaddr + IntrEnable); + if (np->budget < 0) + np->budget = RX_BUDGET; + tasklet_schedule(&np->rx_tasklet); + } - if (intr_status & IntrTxDone) { + if (intr_status & (IntrTxDone | IntrDrvRqst)) { int boguscnt = 32; - int tx_status = readw(ioaddr + TxStatus); + int tx_status = readw (ioaddr + TxStatus); while (tx_status & 0x80) { - if (debug > 4) - printk("%s: Transmit status is %2.2x.\n", - dev->name, tx_status); + if (netif_msg_tx_done(np)) + printk + ("%s: Transmit status is %2.2x.\n", + dev->name, tx_status); if (tx_status & 0x1e) { np->stats.tx_errors++; - if (tx_status & 0x10) np->stats.tx_fifo_errors++; -#ifdef ETHER_STATS - if (tx_status & 0x08) np->stats.collisions16++; -#else - if (tx_status & 0x08) np->stats.collisions++; -#endif - if (tx_status & 0x04) np->stats.tx_fifo_errors++; - if (tx_status & 0x02) np->stats.tx_window_errors++; + if (tx_status & 0x10) + np->stats.tx_fifo_errors++; + if (tx_status & 0x08) + np->stats.collisions++; + if (tx_status & 0x02) + np->stats.tx_window_errors++; /* This reset has not been verified!. */ - if (tx_status & 0x10) { /* Reset the Tx. */ - writew(0x001c, ioaddr + ASICCtrl + 2); -#if 0 /* Do we need to reset the Tx pointer here? */ - writel(np->tx_ring_dma - + np->dirty_tx*sizeof(*np->tx_ring), - dev->base_addr + TxListPtr); -#endif + if (tx_status & 0x10) { /* Reset the Tx. */ + np->stats.tx_fifo_errors++; + spin_lock(&np->lock); + reset_tx(dev, 1); + spin_unlock(&np->lock); } - if (tx_status & 0x1e) /* Restart the Tx. */ - writew(TxEnable, ioaddr + MACCtrl1); + if (tx_status & 0x1e) /* Restart the Tx. */ + writew (TxEnable, + ioaddr + MACCtrl1); } /* Yup, this is a documentation bug. It cost me *hours*. */ - writew(0, ioaddr + TxStatus); - tx_status = readb(ioaddr + TxStatus); + writew (0, ioaddr + TxStatus); + tx_status = readw (ioaddr + TxStatus); if (--boguscnt < 0) break; } } + spin_lock(&np->lock); for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; struct sk_buff *skb; - - if ( ! (np->tx_ring[entry].status & 0x00010000)) + if (!(np->tx_ring[entry].status & 0x00010000)) break; skb = np->tx_skbuff[entry]; /* Free the original skb. */ - pci_unmap_single(np->pci_dev, - np->tx_ring[entry].frag[0].addr, + pci_unmap_single(np->pci_dev, + np->tx_ring[entry].frag[0].addr, skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); + dev_kfree_skb_irq (np->tx_skbuff[entry]); np->tx_skbuff[entry] = 0; } - if (np->tx_full - && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { + spin_unlock(&np->lock); + if (netif_queue_stopped(dev) && + np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { /* The ring is no longer full, clear tbusy. */ - np->tx_full = 0; - netif_wake_queue(dev); + netif_wake_queue (dev); } /* Abnormal error summary/uncommon events handlers. */ - if (intr_status & (IntrDrvRqst | IntrPCIErr | LinkChange | StatsMax)) + if (intr_status & (IntrPCIErr | LinkChange | StatsMax)) netdev_error(dev, intr_status); if (--boguscnt < 0) { get_stats(dev); - if (debug > 1) + if (netif_msg_hw(np)) printk(KERN_WARNING "%s: Too much work at interrupt, " "status=0x%4.4x / 0x%4.4x.\n", dev->name, intr_status, readw(ioaddr + IntrClear)); - /* Re-enable us in 3.2msec. */ - writew(0, ioaddr + IntrEnable); - writew(1000, ioaddr + DownCounter); - writew(IntrDrvRqst, ioaddr + IntrEnable); break; } } while (1); - - if (debug > 3) + if (netif_msg_intr(np)) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); + if (np->cur_tx - np->dirty_tx > 0 && tx_coalesce > 1) + writel(100, ioaddr + DownCounter); - spin_unlock(&np->lock); } -/* This routine is logically part of the interrupt handler, but separated - for clarity and better register allocation. */ -static int netdev_rx(struct net_device *dev) +static void rx_poll(unsigned long data) { + struct net_device *dev = (struct net_device *)data; struct netdev_private *np = dev->priv; int entry = np->cur_rx % RX_RING_SIZE; - int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; - - if (debug > 4) { - printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n", - entry, np->rx_ring[entry].status); - } + int boguscnt = np->budget; + long ioaddr = dev->base_addr; + int received = 0; /* If EOP is set on the next entry, it's a new packet. Send it up. */ while (1) { struct netdev_desc *desc = &(np->rx_ring[entry]); - u32 frame_status; + u32 frame_status = le32_to_cpu(desc->status); int pkt_len; + if (--boguscnt < 0) { + goto not_done; + } if (!(desc->status & DescOwn)) break; - frame_status = le32_to_cpu(desc->status); pkt_len = frame_status & 0x1fff; /* Chip omits the CRC. */ - if (debug > 4) + if (netif_msg_rx_status(np)) printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", frame_status); - if (--boguscnt < 0) - break; pci_dma_sync_single(np->pci_dev, desc->frag[0].addr, np->rx_buf_sz, PCI_DMA_FROMDEVICE); - + if (frame_status & 0x001f4000) { /* There was a error. */ - if (debug > 2) + if (netif_msg_rx_err(np)) printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", frame_status); np->stats.rx_errors++; @@ -1136,9 +1252,8 @@ } } else { struct sk_buff *skb; - #ifndef final_version - if (debug > 4) + if (netif_msg_rx_status(np)) printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" ", bogus_cnt %d.\n", pkt_len, boguscnt); @@ -1152,9 +1267,9 @@ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); skb_put(skb, pkt_len); } else { - pci_unmap_single(np->pci_dev, + pci_unmap_single(np->pci_dev, desc->frag[0].addr, - np->rx_buf_sz, + np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb_put(skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; @@ -1164,11 +1279,36 @@ netif_rx(skb); dev->last_rx = jiffies; } - entry = (++np->cur_rx) % RX_RING_SIZE; + entry = (entry + 1) % RX_RING_SIZE; + received++; } + np->cur_rx = entry; + refill_rx (dev); + np->budget -= received; + writew(DEFAULT_INTR, ioaddr + IntrEnable); + return; + +not_done: + np->cur_rx = entry; + refill_rx (dev); + if (!received) + received = 1; + np->budget -= received; + if (np->budget <= 0) + np->budget = RX_BUDGET; + tasklet_schedule(&np->rx_tasklet); + return; +} + +static void refill_rx (struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + int entry; + int cnt = 0; /* Refill the Rx ring buffers. */ - for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + for (;(np->cur_rx - np->dirty_rx + RX_RING_SIZE) % RX_RING_SIZE > 0; + np->dirty_rx = (np->dirty_rx + 1) % RX_RING_SIZE) { struct sk_buff *skb; entry = np->dirty_rx % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { @@ -1179,19 +1319,17 @@ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ np->rx_ring[entry].frag[0].addr = cpu_to_le32( - pci_map_single(np->pci_dev, skb->tail, + pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); } /* Perhaps we need not reset this field. */ np->rx_ring[entry].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag); np->rx_ring[entry].status = 0; + cnt++; } - - /* No need to restart Rx engine, it will poll. */ - return 0; + return; } - static void netdev_error(struct net_device *dev, int intr_status) { long ioaddr = dev->base_addr; @@ -1199,43 +1337,40 @@ u16 mii_ctl, mii_advertise, mii_lpa; int speed; - if (intr_status & IntrDrvRqst) { - /* Stop the down counter and turn interrupts back on. */ - if (debug > 1) - printk("%s: Turning interrupts back on.\n", dev->name); - writew(0, ioaddr + IntrEnable); - writew(0, ioaddr + DownCounter); - writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | - IntrTxDone | StatsMax | LinkChange, ioaddr + IntrEnable); - /* Ack buggy InRequest */ - writew (IntrDrvRqst, ioaddr + IntrStatus); - } if (intr_status & LinkChange) { if (np->an_enable) { mii_advertise = mdio_read (dev, np->phys[0], MII_ADVERTISE); mii_lpa= mdio_read (dev, np->phys[0], MII_LPA); mii_advertise &= mii_lpa; printk (KERN_INFO "%s: Link changed: ", dev->name); - if (mii_advertise & ADVERTISE_100FULL) + if (mii_advertise & ADVERTISE_100FULL) { + np->speed = 100; printk ("100Mbps, full duplex\n"); - else if (mii_advertise & ADVERTISE_100HALF) + } else if (mii_advertise & ADVERTISE_100HALF) { + np->speed = 100; printk ("100Mbps, half duplex\n"); - else if (mii_advertise & ADVERTISE_10FULL) + } else if (mii_advertise & ADVERTISE_10FULL) { + np->speed = 10; printk ("10Mbps, full duplex\n"); - else if (mii_advertise & ADVERTISE_10HALF) + } else if (mii_advertise & ADVERTISE_10HALF) { + np->speed = 10; printk ("10Mbps, half duplex\n"); - else + } else printk ("\n"); } else { mii_ctl = mdio_read (dev, np->phys[0], MII_BMCR); speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; + np->speed = speed; printk (KERN_INFO "%s: Link changed: %dMbps ,", dev->name, speed); printk ("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ? "full" : "half"); } check_duplex (dev); + if (np->flowctrl == 0) + writew(readw(ioaddr + MACCtrl0) & ~EnbFlowCtrl, + ioaddr + MACCtrl0); } if (intr_status & StatsMax) { get_stats(dev); @@ -1319,24 +1454,80 @@ { struct netdev_private *np = dev->priv; u32 ethcmd; - + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) return -EFAULT; switch (ethcmd) { - case ETHTOOL_GDRVINFO: { - struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; - strcpy(info.driver, DRV_NAME); - strcpy(info.version, DRV_VERSION); - strcpy(info.bus_info, np->pci_dev->slot_name); - if (copy_to_user(useraddr, &info, sizeof(info))) - return -EFAULT; - return 0; - } + /* get constant driver settings/info */ + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strcpy(info.driver, DRV_NAME); + strcpy(info.version, DRV_VERSION); + strcpy(info.bus_info, np->pci_dev->slot_name); + memset(&info.fw_version, 0, sizeof(info.fw_version)); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + /* get media settings */ + case ETHTOOL_GSET: { + struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + spin_lock_irq(&np->lock); + mii_ethtool_gset(&np->mii_if, &ecmd); + spin_unlock_irq(&np->lock); + if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } + /* set media settings */ + case ETHTOOL_SSET: { + int r; + struct ethtool_cmd ecmd; + if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) + return -EFAULT; + spin_lock_irq(&np->lock); + r = mii_ethtool_sset(&np->mii_if, &ecmd); + spin_unlock_irq(&np->lock); + return r; + } + + /* restart autonegotiation */ + case ETHTOOL_NWAY_RST: { + return mii_nway_restart(&np->mii_if); + } + + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + edata.data = mii_link_ok(&np->mii_if); + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = np->msg_enable; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + np->msg_enable = edata.data; + return 0; + } + + default: + return -EOPNOTSUPP; } - - return -EOPNOTSUPP; } static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) @@ -1373,7 +1564,7 @@ netif_stop_queue(dev); - if (debug > 1) { + if (netif_msg_ifdown(np)) { printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x " "Rx %4.4x Int %2.2x.\n", dev->name, readb(ioaddr + TxStatus), @@ -1389,7 +1580,7 @@ writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1); #ifdef __i386__ - if (debug > 2) { + if (netif_msg_hw(np)) { printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", (int)(np->tx_ring_dma)); for (i = 0; i < TX_RING_SIZE; i++) @@ -1416,8 +1607,8 @@ np->rx_ring[i].frag[0].addr = 0xBADF00D0; /* An invalid address. */ skb = np->rx_skbuff[i]; if (skb) { - pci_unmap_single(np->pci_dev, - np->rx_ring[i].frag[0].addr, np->rx_buf_sz, + pci_unmap_single(np->pci_dev, + np->rx_ring[i].frag[0].addr, np->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); np->rx_skbuff[i] = 0; @@ -1426,7 +1617,7 @@ for (i = 0; i < TX_RING_SIZE; i++) { skb = np->tx_skbuff[i]; if (skb) { - pci_unmap_single(np->pci_dev, + pci_unmap_single(np->pci_dev, np->tx_ring[i].frag[0].addr, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); @@ -1440,15 +1631,15 @@ static void __devexit sundance_remove1 (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ if (dev) { struct netdev_private *np = dev->priv; unregister_netdev(dev); - pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, + pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); - pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, + pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); pci_release_regions(pdev); #ifndef USE_IO_OPS @@ -1460,10 +1651,10 @@ } static struct pci_driver sundance_driver = { - .name = DRV_NAME, - .id_table = sundance_pci_tbl, - .probe = sundance_probe1, - .remove = __devexit_p(sundance_remove1), + name: DRV_NAME, + id_table: sundance_pci_tbl, + probe: sundance_probe1, + remove: __devexit_p(sundance_remove1), }; static int __init sundance_init(void) @@ -1482,3 +1673,5 @@ module_init(sundance_init); module_exit(sundance_exit); + + diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c --- a/drivers/net/tg3.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/tg3.c Fri Sep 20 08:20:46 2002 @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -49,7 +51,9 @@ #endif #ifdef NETIF_F_TSO -/* XXX some bug in tso firmware hangs tx cpu, disabled until fixed */ +/* XXX Works but still disabled, decreases TCP performance to 7MB/sec even + * XXX over gigabit. + */ #define TG3_DO_TSO 0 #else #define TG3_DO_TSO 0 @@ -237,6 +241,39 @@ tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); } +static inline void tg3_mask_ints(struct tg3 *tp) +{ + tw32(TG3PCI_MISC_HOST_CTRL, + (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); +} + +static inline void tg3_unmask_ints(struct tg3 *tp) +{ + tw32(TG3PCI_MISC_HOST_CTRL, + (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); + if (tp->hw_status->status & SD_STATUS_UPDATED) { + tw32(GRC_LOCAL_CTRL, + tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); + } +} + +static void tg3_switch_clocks(struct tg3 *tp) +{ + if (tr32(TG3PCI_CLOCK_CTRL) & CLOCK_CTRL_44MHZ_CORE) { + tw32(TG3PCI_CLOCK_CTRL, + (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK)); + tr32(TG3PCI_CLOCK_CTRL); + udelay(40); + tw32(TG3PCI_CLOCK_CTRL, + (CLOCK_CTRL_ALTCLK)); + tr32(TG3PCI_CLOCK_CTRL); + udelay(40); + } + tw32(TG3PCI_CLOCK_CTRL, 0); + tr32(TG3PCI_CLOCK_CTRL); + udelay(40); +} + #define PHY_BUSY_LOOPS 5000 static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) @@ -443,10 +480,12 @@ tp->link_config.orig_autoneg = tp->link_config.autoneg; } - tp->link_config.speed = SPEED_10; - tp->link_config.duplex = DUPLEX_HALF; - tp->link_config.autoneg = AUTONEG_ENABLE; - tg3_setup_phy(tp); + if (tp->phy_id != PHY_ID_SERDES) { + tp->link_config.speed = SPEED_10; + tp->link_config.duplex = DUPLEX_HALF; + tp->link_config.autoneg = AUTONEG_ENABLE; + tg3_setup_phy(tp); + } tg3_halt(tp); @@ -455,14 +494,19 @@ if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) { u32 mac_mode; - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); - udelay(40); + if (tp->phy_id != PHY_ID_SERDES) { + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); + udelay(40); - mac_mode = MAC_MODE_PORT_MODE_MII; + mac_mode = MAC_MODE_PORT_MODE_MII; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 || + !(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)) + mac_mode |= MAC_MODE_LINK_POLARITY; + } else { + mac_mode = MAC_MODE_PORT_MODE_TBI; + } - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 || - !(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)) - mac_mode |= MAC_MODE_LINK_POLARITY; if (((power_caps & PCI_PM_CAP_PME_D3cold) && (tp->tg3_flags & TG3_FLAG_WOL_ENABLE))) @@ -470,7 +514,7 @@ tw32(MAC_MODE, mac_mode); tr32(MAC_MODE); - udelay(40); + udelay(100); tw32(MAC_RX_MODE, RX_MODE_ENABLE); tr32(MAC_RX_MODE); @@ -1033,16 +1077,15 @@ tp->mac_mode |= MAC_MODE_HALF_DUPLEX; tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) { - if (current_link_up == 1) - tp->mac_mode |= MAC_MODE_LINK_POLARITY; - tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1); - } else { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) { if ((tp->led_mode == led_mode_link10) || (current_link_up == 1 && tp->link_config.active_speed == SPEED_10)) tp->mac_mode |= MAC_MODE_LINK_POLARITY; + } else { + if (current_link_up == 1) + tp->mac_mode |= MAC_MODE_LINK_POLARITY; + tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1); } /* ??? Without this setting Netgear GA302T PHY does not @@ -2068,7 +2111,7 @@ if (done) { netif_rx_complete(netdev); - tg3_enable_ints(tp); + tg3_unmask_ints(tp); } spin_unlock_irq(&tp->lock); @@ -2095,11 +2138,10 @@ return; if (netif_rx_schedule_prep(dev)) { - /* NOTE: This write is posted by the readback of + /* NOTE: These writes are posted by the readback of * the mailbox register done by our caller. */ - tw32(TG3PCI_MISC_HOST_CTRL, - (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); + tg3_mask_ints(tp); __netif_rx_schedule(dev); } else { printk(KERN_ERR PFX "%s: Error, poll already scheduled\n", @@ -2352,9 +2394,20 @@ if (skb->ip_summed == CHECKSUM_HW) base_flags |= TXD_FLAG_TCPUDP_CSUM; #if TG3_DO_TSO != 0 - if ((mss = skb_shinfo(skb)->tso_size) != 0) + if ((mss = skb_shinfo(skb)->tso_size) != 0) { + static int times = 0; + + mss += ((skb->h.th->doff * 4) - 20); base_flags |= (TXD_FLAG_CPU_PRE_DMA | TXD_FLAG_CPU_POST_DMA); + + if (times++ < 5) { + printk("tg3_xmit: tso_size[%u] tso_segs[%u] len[%u]\n", + (unsigned int) skb_shinfo(skb)->tso_size, + (unsigned int) skb_shinfo(skb)->tso_segs, + skb->len); + } + } #else mss = 0; #endif @@ -2405,7 +2458,7 @@ } tg3_set_txd(tp, entry, mapping, len, - base_flags, (i == last) | (mss << 1)); + base_flags, (i == last)); entry = NEXT_TX(entry); } @@ -2517,9 +2570,24 @@ if (skb->ip_summed == CHECKSUM_HW) base_flags |= TXD_FLAG_TCPUDP_CSUM; #if TG3_DO_TSO != 0 - if ((mss = skb_shinfo(skb)->tso_size) != 0) + if ((mss = skb_shinfo(skb)->tso_size) != 0) { + static int times = 0; + + /* TSO firmware wants TCP options included in + * tx descriptor MSS value. + */ + mss += ((skb->h.th->doff * 4) - 20); + base_flags |= (TXD_FLAG_CPU_PRE_DMA | TXD_FLAG_CPU_POST_DMA); + + if (times++ < 5) { + printk("tg3_xmit: tso_size[%u] tso_segs[%u] len[%u]\n", + (unsigned int) skb_shinfo(skb)->tso_size, + (unsigned int) skb_shinfo(skb)->tso_segs, + skb->len); + } + } #else mss = 0; #endif @@ -2559,7 +2627,7 @@ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); tg3_set_txd(tp, entry, mapping, len, - base_flags, (i == last) | (mss << 1)); + base_flags, (i == last)); entry = NEXT_TX(entry); } @@ -4291,9 +4359,11 @@ } #if TG3_DO_TSO != 0 - err = tg3_load_tso_firmware(tp); - if (err) - return err; + if (tp->dev->features & NETIF_F_TSO) { + err = tg3_load_tso_firmware(tp); + if (err) + return err; + } #endif tp->tx_mode = TX_MODE_ENABLE; @@ -4385,6 +4455,8 @@ if (err) goto out; + tg3_switch_clocks(tp); + tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0); err = tg3_reset_hw(tp); @@ -5259,6 +5331,11 @@ return -EFAULT; if (wol.wolopts & ~WAKE_MAGIC) return -EINVAL; + if ((wol.wolopts & WAKE_MAGIC) && + tp->phy_id == PHY_ID_SERDES && + !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP)) + return -EINVAL; + spin_lock_irq(&tp->lock); if (wol.wolopts & WAKE_MAGIC) tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; @@ -5793,6 +5870,8 @@ if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; + if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL) + tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP; } /* Now read the physical PHY_ID from the chip and verify @@ -6131,8 +6210,9 @@ /* Initialize data/descriptor byte/word swapping. */ tw32(GRC_MODE, tp->grc_mode); - /* Clear these out for sanity. */ - tw32(TG3PCI_CLOCK_CTRL, 0); + tg3_switch_clocks(tp); + + /* Clear this out for sanity. */ tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0); pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, @@ -6704,9 +6784,6 @@ dev->vlan_rx_register = tg3_vlan_rx_register; dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid; #endif -#if TG3_DO_TSO != 0 - dev->features |= NETIF_F_TSO; -#endif tp = dev->priv; tp->pdev = pdev; @@ -6806,6 +6883,17 @@ tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; } else tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; + +#if TG3_DO_TSO != 0 + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 && + tp->pci_chip_rev_id <= CHIPREV_ID_5701_B2)) { + /* Not TSO capable. */ + dev->features &= ~NETIF_F_TSO; + } else { + dev->features |= NETIF_F_TSO; + } +#endif err = register_netdev(dev); if (err) { diff -Nru a/drivers/net/tg3.h b/drivers/net/tg3.h --- a/drivers/net/tg3.h Fri Sep 20 08:20:43 2002 +++ b/drivers/net/tg3.h Fri Sep 20 08:20:43 2002 @@ -1274,6 +1274,7 @@ #define NIC_SRAM_DATA_CFG_WOL_ENABLE 0x00000040 #define NIC_SRAM_DATA_CFG_ASF_ENABLE 0x00000080 #define NIC_SRAM_DATA_CFG_EEPROM_WP 0x00000100 +#define NIC_SRAM_DATA_CFG_FIBER_WOL 0x00004000 #define NIC_SRAM_DATA_PHY_ID 0x00000b74 #define NIC_SRAM_DATA_PHY_ID1_MASK 0xffff0000 @@ -1311,7 +1312,7 @@ #define NIC_SRAM_RX_JUMBO_BUFFER_DESC 0x00007000 /* 256 entries */ #define NIC_SRAM_MBUF_POOL_BASE 0x00008000 #define NIC_SRAM_MBUF_POOL_SIZE96 0x00018000 -#define NIC_SRAM_MBUF_POOL_SIZE64 0x00018000 +#define NIC_SRAM_MBUF_POOL_SIZE64 0x00010000 /* Currently this is fixed. */ #define PHY_ADDR 0x01 @@ -1779,7 +1780,7 @@ #define TG3_FLAG_PCI_32BIT 0x00080000 #define TG3_FLAG_NO_TX_PSEUDO_CSUM 0x00100000 #define TG3_FLAG_NO_RX_PSEUDO_CSUM 0x00200000 -#define TG3_FLAG_AUTONEG_DISABLE 0x00400000 +#define TG3_FLAG_SERDES_WOL_CAP 0x00400000 #define TG3_FLAG_JUMBO_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 diff -Nru a/drivers/net/tulip/ChangeLog b/drivers/net/tulip/ChangeLog --- a/drivers/net/tulip/ChangeLog Fri Sep 20 08:20:43 2002 +++ b/drivers/net/tulip/ChangeLog Fri Sep 20 08:20:43 2002 @@ -1,3 +1,14 @@ +2002-09-18 Ryan Bradetich + + tulip hppa support: + * eeprom.c (tulip_build_fake_mediatable): new function + (tulip_parse_eeprom): call it, when no media table + * interrupt.c (phy_interrupt): new function + (tulip_interrupt): call it, before checking for no-irq-work + * tulip.c: add HAS_PHY_IRQ chip feature flag. + add csr12_shadow to tulip_private struct, only for hppa currently. + * tulip_core (tulip_init_one): support hppa wonky eeproms + 2002-05-11 Juan Quintela * 21142.c (t21142_lnk_change): Revert earlier patch diff -Nru a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c --- a/drivers/net/tulip/eeprom.c Fri Sep 20 08:20:48 2002 +++ b/drivers/net/tulip/eeprom.c Fri Sep 20 08:20:48 2002 @@ -75,6 +75,61 @@ }; +/** + * tulip_build_fake_mediatable - Build a fake mediatable entry. + * @tp: Ptr to the tulip private data. + * + * Some cards like the 3x5 HSC cards (J3514A) do not have a standard + * srom and can not be handled under the fixup routine. These cards + * still need a valid mediatable entry for correct csr12 setup and + * mii handling. + * + * Since this is currently a parisc-linux specific function, the + * #ifdef __hppa__ should completely optimize this function away for + * non-parisc hardware. + */ +static void __devinit tulip_build_fake_mediatable(struct tulip_private *tp) +{ +#ifdef __hppa__ + unsigned char *ee_data = tp->eeprom; + + if (ee_data[0] == 0x3c && ee_data[1] == 0x10 && + (ee_data[2] == 0x63 || ee_data[2] == 0x61) && ee_data[3] == 0x10) { + + static unsigned char leafdata[] = + { 0x01, /* phy number */ + 0x02, /* gpr setup sequence length */ + 0x02, 0x00, /* gpr setup sequence */ + 0x02, /* phy reset sequence length */ + 0x01, 0x00, /* phy reset sequence */ + 0x00, 0x78, /* media capabilities */ + 0x00, 0xe0, /* nway advertisment */ + 0x00, 0x05, /* fdx bit map */ + 0x00, 0x06 /* ttm bit map */ + }; + + tp->mtable = (struct mediatable *) + kmalloc(sizeof(struct mediatable) + sizeof(struct medialeaf), GFP_KERNEL); + + if (tp->mtable == NULL) + return; /* Horrible, impossible failure. */ + + tp->mtable->defaultmedia = 0x800; + tp->mtable->leafcount = 1; + tp->mtable->csr12dir = 0x3f; /* inputs on bit7 for hsc-pci, bit6 for pci-fx */ + tp->mtable->has_nonmii = 0; + tp->mtable->has_reset = 0; + tp->mtable->has_mii = 1; + tp->mtable->csr15dir = tp->mtable->csr15val = 0; + tp->mtable->mleaf[0].type = 1; + tp->mtable->mleaf[0].media = 11; + tp->mtable->mleaf[0].leafdata = &leafdata[0]; + tp->flags |= HAS_PHY_IRQ; + tp->csr12_shadow = -1; + } +#endif +} + void __devinit tulip_parse_eeprom(struct net_device *dev) { /* The last media info list parsed, for multiport boards. */ @@ -136,6 +191,7 @@ subsequent_board: if (ee_data[27] == 0) { /* No valid media table. */ + tulip_build_fake_mediatable(tp); } else { unsigned char *p = (void *)ee_data + ee_data[27]; unsigned char csr12dir = 0; diff -Nru a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c --- a/drivers/net/tulip/interrupt.c Fri Sep 20 08:20:43 2002 +++ b/drivers/net/tulip/interrupt.c Fri Sep 20 08:20:43 2002 @@ -291,6 +291,25 @@ #endif } +static inline void phy_interrupt (struct net_device *dev) +{ +#ifdef __hppa__ + int csr12 = inl(dev->base_addr + CSR12) & 0xff; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + + if (csr12 != tp->csr12_shadow) { + /* ack interrupt */ + outl(csr12 | 0x02, dev->base_addr + CSR12); + tp->csr12_shadow = csr12; + /* do link change stuff */ + spin_lock(&tp->lock); + tulip_check_duplex(dev); + spin_unlock(&tp->lock); + /* clear irq ack bit */ + outl(csr12 & ~0x02, dev->base_addr + CSR12); + } +#endif +} /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -313,6 +332,9 @@ /* Let's see whether the interrupt really is for us */ csr5 = inl(ioaddr + CSR5); + if (tp->flags & HAS_PHY_IRQ) + phy_interrupt (dev); + if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) return; diff -Nru a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h --- a/drivers/net/tulip/tulip.h Fri Sep 20 08:20:48 2002 +++ b/drivers/net/tulip/tulip.h Fri Sep 20 08:20:48 2002 @@ -63,6 +63,7 @@ HAS_8023X = 0x0400, COMET_MAC_ADDR = 0x0800, HAS_PCI_MWI = 0x1000, + HAS_PHY_IRQ = 0x2000, }; @@ -388,7 +389,8 @@ int susp_rx; unsigned long nir; unsigned long base_addr; - int pad0, pad1; /* Used for 8-byte alignment */ + int csr12_shadow; + int pad0; /* Used for 8-byte alignment */ }; diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c --- a/drivers/net/tulip/tulip_core.c Fri Sep 20 08:20:47 2002 +++ b/drivers/net/tulip/tulip_core.c Fri Sep 20 08:20:47 2002 @@ -1490,6 +1490,25 @@ tp->flags &= ~HAS_MEDIA_TABLE; } #endif +#ifdef __hppa__ + /* 3x5 HSC (J3514A) has a broken srom */ + if(ee_data[0] == 0x61 && ee_data[1] == 0x10) { + /* pci_vendor_id and subsystem_id are swapped */ + ee_data[0] = ee_data[2]; + ee_data[1] = ee_data[3]; + ee_data[2] = 0x61; + ee_data[3] = 0x10; + + /* srom need to be byte-swaped and shifted up 1 word. + * This shift needs to happen at the end of the MAC + * first because of the 2 byte overlap. + */ + for(i = 4; i >= 0; i -= 2) { + ee_data[17 + i + 3] = ee_data[17 + i]; + ee_data[16 + i + 5] = ee_data[16 + i]; + } + } +#endif for (i = 0; i < 6; i ++) { dev->dev_addr[i] = ee_data[i + sa_offset]; sum += ee_data[i + sa_offset]; diff -Nru a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c --- a/drivers/net/tulip/winbond-840.c Fri Sep 20 08:20:43 2002 +++ b/drivers/net/tulip/winbond-840.c Fri Sep 20 08:20:43 2002 @@ -1136,13 +1136,7 @@ if (tx_status & 0x0002) np->stats.tx_fifo_errors++; if ((tx_status & 0x0080) && np->mii_if.full_duplex == 0) np->stats.tx_heartbeat_errors++; -#ifdef ETHER_STATS - if (tx_status & 0x0100) np->stats.collisions16++; -#endif } else { -#ifdef ETHER_STATS - if (tx_status & 0x0001) np->stats.tx_deferred++; -#endif #ifndef final_version if (debug > 3) printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %8.8x.\n", diff -Nru a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c --- a/drivers/net/tulip/xircom_tulip_cb.c Fri Sep 20 08:20:42 2002 +++ b/drivers/net/tulip/xircom_tulip_cb.c Fri Sep 20 08:20:43 2002 @@ -1105,9 +1105,6 @@ tp->stats.tx_errors++; if (status & Tx0ManyColl) { tp->stats.tx_aborted_errors++; -#ifdef ETHER_STATS - tp->stats.collisions16++; -#endif } if (status & Tx0NoCarrier) tp->stats.tx_carrier_errors++; if (status & Tx0LateColl) tp->stats.tx_window_errors++; diff -Nru a/drivers/net/tun.c b/drivers/net/tun.c --- a/drivers/net/tun.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/tun.c Fri Sep 20 08:20:46 2002 @@ -275,7 +275,7 @@ total += sizeof(pi); } - len = min(skb->len, len); + len = min_t(int, skb->len, len); skb_copy_datagram_iovec(skb, 0, iv, len); total += len; @@ -306,6 +306,8 @@ return -EFAULT; len += iv[i].iov_len; } + if (len < 0) + return -EINVAL; add_wait_queue(&tun->read_wait, &wait); while (len) { diff -Nru a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c --- a/drivers/net/wan/c101.c Fri Sep 20 08:20:43 2002 +++ b/drivers/net/wan/c101.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,7 @@ /* * Moxa C101 synchronous serial card driver for Linux * - * Copyright (C) 2000-2001 Krzysztof Halasa + * Copyright (C) 2000-2002 Krzysztof Halasa * * 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 @@ -31,7 +31,7 @@ #include "hd64570.h" -static const char* version = "Moxa C101 driver version: 1.09"; +static const char* version = "Moxa C101 driver version: 1.10"; static const char* devname = "C101"; #define C101_PAGE 0x1D00 @@ -107,18 +107,13 @@ #include "hd6457x.c" -static int c101_set_iface(port_t *port) +static void c101_set_iface(port_t *port) { u8 msci = get_msci(port); u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; switch(port->settings.clock_type) { - case CLOCK_EXT: - rxs |= CLK_LINE_RX; /* RXC input */ - txs |= CLK_LINE_TX; /* TXC input */ - break; - case CLOCK_INT: rxs |= CLK_BRG_RX; /* TX clock */ txs |= CLK_RXCLK_TX; /* BRG output */ @@ -134,8 +129,9 @@ txs |= CLK_RXCLK_TX; /* RX clock */ break; - default: - return -EINVAL; + default: /* EXTernal clock */ + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_LINE_TX; /* TXC input */ } port->rxs = rxs; @@ -143,7 +139,6 @@ sca_out(rxs, msci + RXS, port); sca_out(txs, msci + TXS, port); sca_set_port(port); - return 0; } @@ -159,7 +154,8 @@ writeb(1, port->win0base + C101_DTR); sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ sca_open(hdlc); - return c101_set_iface(port); + c101_set_iface(port); + return 0; } @@ -181,6 +177,7 @@ { union line_settings *line = &ifr->ifr_settings->ifs_line; const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; hdlc_device *hdlc = dev_to_hdlc(dev); port_t *port = hdlc_to_port(hdlc); @@ -204,10 +201,21 @@ if(!capable(CAP_NET_ADMIN)) return -EPERM; - if (copy_from_user(&port->settings, &line->sync, size)) + if (copy_from_user(&new_line, &line->sync, size)) return -EFAULT; - /* FIXME - put sanity checks here */ - return c101_set_iface(port); + + if (new_line.clock_type != CLOCK_EXT && + new_line.clock_type != CLOCK_TXFROMRX && + new_line.clock_type != CLOCK_INT && + new_line.clock_type != CLOCK_TXINT) + return -EINVAL; /* No such clock setting */ + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + memcpy(&port->settings, &new_line, size); /* Update settings */ + c101_set_iface(port); + return 0; default: return hdlc_ioctl(dev, ifr, cmd); diff -Nru a/drivers/net/wan/comx-hw-munich.c b/drivers/net/wan/comx-hw-munich.c --- a/drivers/net/wan/comx-hw-munich.c Fri Sep 20 08:20:43 2002 +++ b/drivers/net/wan/comx-hw-munich.c Fri Sep 20 08:20:43 2002 @@ -55,11 +55,9 @@ #include "falc-lh.h" #endif -MODULE_AUTHOR - ("Bartok Istvan , Gergely Madarasz , Szilard Pasztor "); -MODULE_DESCRIPTION - ("Hardware-level driver for the SliceCOM and PciCOM (WelCOM) adapters"); - +MODULE_AUTHOR("Bartok Istvan , Gergely Madarasz , Szilard Pasztor "); +MODULE_DESCRIPTION("Hardware-level driver for the SliceCOM and PciCOM (WelCOM) adapters"); +MODULE_LICENSE("GPL"); /* * TODO: az ilyenek a comxhw.h -ban szoktak lenni, idovel menjenek majd oda: */ @@ -1253,8 +1251,6 @@ /* jon interrupt, de nincs mit feldolgozni, akkor torlom a STAT-ot. */ /* 'needs a rewrite', de elso megoldasnak jo lesz */ // { - -udelay(10000); int_info = board->tiq[board->tiq_ptr]; if (int_info.all & 0xF0000000) /* ha ez nem 0, akkor itt interrupt_info van */ { @@ -2779,8 +2775,6 @@ static int BOARD_exit(struct net_device *dev) { struct comx_channel *ch = (struct comx_channel *)dev->priv; - struct slicecom_privdata *hw = ch->HW_privdata; -// munich_board_t *board; /* Free private data area */ // board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); diff -Nru a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c --- a/drivers/net/wan/hd6457x.c Fri Sep 20 08:20:43 2002 +++ b/drivers/net/wan/hd6457x.c Fri Sep 20 08:20:43 2002 @@ -291,9 +291,9 @@ #endif port->hdlc.stats.rx_packets++; port->hdlc.stats.rx_bytes += skb->len; - skb->dev->last_rx = jiffies; skb->mac.raw = skb->data; skb->dev = hdlc_to_dev(&port->hdlc); + skb->dev->last_rx = jiffies; skb->protocol = htons(ETH_P_HDLC); netif_rx(skb); } diff -Nru a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c --- a/drivers/net/wan/hdlc_cisco.c Fri Sep 20 08:20:44 2002 +++ b/drivers/net/wan/hdlc_cisco.c Fri Sep 20 08:20:44 2002 @@ -249,6 +249,7 @@ { cisco_proto *cisco_s = &ifr->ifr_settings->ifs_hdlc.cisco; const size_t size = sizeof(cisco_proto); + cisco_proto new_settings; struct net_device *dev = hdlc_to_dev(hdlc); int result; @@ -266,17 +267,20 @@ if(dev->flags & IFF_UP) return -EBUSY; - if (copy_from_user(&hdlc->state.cisco.settings, cisco_s, size)) + if (copy_from_user(&new_settings, cisco_s, size)) return -EFAULT; - /* FIXME - put sanity checks here */ - hdlc_detach(hdlc); + if (new_settings.interval < 1 || + new_settings.timeout < 2) + return -EINVAL; result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); - if (result) { - hdlc->proto = -1; + + if (result) return result; - } + + hdlc_proto_detach(hdlc); + memcpy(&hdlc->state.cisco.settings, &new_settings, size); hdlc->open = cisco_open; hdlc->stop = cisco_close; diff -Nru a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c --- a/drivers/net/wan/hdlc_fr.c Fri Sep 20 08:20:44 2002 +++ b/drivers/net/wan/hdlc_fr.c Fri Sep 20 08:20:44 2002 @@ -602,13 +602,15 @@ } if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD) { - u16 oui = ntohl(*(u16*)(data + 6)); - u16 pid = ntohl(*(u16*)(data + 8)); + u16 oui = ntohs(*(u16*)(data + 6)); + u16 pid = ntohs(*(u16*)(data + 8)); skb_pull(skb, 10); switch ((((u32)oui) << 16) | pid) { case ETH_P_ARP: /* routed frame with SNAP */ case ETH_P_IPX: + case ETH_P_IP: /* a long variant */ + case ETH_P_IPV6: skb->protocol = htons(pid); break; @@ -762,7 +764,7 @@ pvc_device *pvc = hdlc->state.fr.first_pvc; while(pvc) { pvc_device *next = pvc->next; - unregister_netdevice(&pvc->netdev); + unregister_netdev(&pvc->netdev); kfree(pvc); pvc = next; } @@ -778,6 +780,7 @@ { fr_proto *fr_s = &ifr->ifr_settings->ifs_hdlc.fr; const size_t size = sizeof(fr_proto); + fr_proto new_settings; struct net_device *dev = hdlc_to_dev(hdlc); fr_proto_pvc pvc; int result; @@ -796,26 +799,40 @@ if(dev->flags & IFF_UP) return -EBUSY; - if (copy_from_user(&hdlc->state.fr.settings, fr_s, size)) + if (copy_from_user(&new_settings, fr_s, size)) return -EFAULT; - /* FIXME - put sanity checks here */ - if (hdlc->proto != IF_PROTO_FR) { - hdlc_detach(hdlc); - hdlc->state.fr.first_pvc = NULL; - hdlc->state.fr.pvc_count = 0; - } + if (new_settings.lmi == LMI_DEFAULT) + new_settings.lmi = LMI_ANSI; + + if ((new_settings.lmi != LMI_NONE && + new_settings.lmi != LMI_ANSI && + new_settings.lmi != LMI_CCITT) || + new_settings.t391 < 1 || + new_settings.t392 < 2 || + new_settings.n391 < 1 || + new_settings.n392 < 1 || + new_settings.n393 < new_settings.n392 || + new_settings.n393 > 32 || + (new_settings.dce != 0 && + new_settings.dce != 1)) + return -EINVAL; result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); - if (result) { - hdlc->proto = -1; + if (result) return result; + + if (hdlc->proto != IF_PROTO_FR) { + hdlc_proto_detach(hdlc); + hdlc->state.fr.first_pvc = NULL; + hdlc->state.fr.pvc_count = 0; } + memcpy(&hdlc->state.fr.settings, &new_settings, size); hdlc->open = fr_open; hdlc->stop = fr_close; hdlc->netif_rx = fr_rx; - hdlc->detach = fr_destroy; + hdlc->proto_detach = fr_destroy; hdlc->proto = IF_PROTO_FR; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = fr_hard_header; diff -Nru a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c --- a/drivers/net/wan/hdlc_generic.c Fri Sep 20 08:20:42 2002 +++ b/drivers/net/wan/hdlc_generic.c Fri Sep 20 08:20:42 2002 @@ -38,7 +38,7 @@ #include -static const char* version = "HDLC support module revision 1.08"; +static const char* version = "HDLC support module revision 1.10"; static int hdlc_change_mtu(struct net_device *dev, int new_mtu) @@ -66,6 +66,26 @@ } +#ifndef CONFIG_HDLC_RAW +#define hdlc_raw_ioctl(hdlc, ifr) -ENOSYS +#endif + +#ifndef CONFIG_HDLC_PPP +#define hdlc_ppp_ioctl(hdlc, ifr) -ENOSYS +#endif + +#ifndef CONFIG_HDLC_CISCO +#define hdlc_cisco_ioctl(hdlc, ifr) -ENOSYS +#endif + +#ifndef CONFIG_HDLC_FR +#define hdlc_fr_ioctl(hdlc, ifr) -ENOSYS +#endif + +#ifndef CONFIG_HDLC_X25 +#define hdlc_x25_ioctl(hdlc, ifr) -ENOSYS +#endif + int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -89,22 +109,12 @@ } switch(proto) { -#ifdef CONFIG_HDLC_RAW case IF_PROTO_HDLC: return hdlc_raw_ioctl(hdlc, ifr); -#endif -#ifdef CONFIG_HDLC_PPP case IF_PROTO_PPP: return hdlc_ppp_ioctl(hdlc, ifr); -#endif -#ifdef CONFIG_HDLC_CISCO case IF_PROTO_CISCO: return hdlc_cisco_ioctl(hdlc, ifr); -#endif -#ifdef CONFIG_HDLC_FR case IF_PROTO_FR: return hdlc_fr_ioctl(hdlc, ifr); -#endif -#ifdef CONFIG_HDLC_X25 case IF_PROTO_X25: return hdlc_x25_ioctl(hdlc, ifr); -#endif - default: return -ENOSYS; + default: return -EINVAL; } } @@ -125,7 +135,7 @@ dev->flags = IFF_POINTOPOINT | IFF_NOARP; hdlc->proto = -1; - hdlc->detach = NULL; + hdlc->proto_detach = NULL; result = dev_alloc_name(dev, "hdlc%d"); if (result<0) @@ -143,7 +153,7 @@ void unregister_hdlc_device(hdlc_device *hdlc) { - hdlc_detach(hdlc); + hdlc_proto_detach(hdlc); unregister_netdev(hdlc_to_dev(hdlc)); MOD_DEC_USE_COUNT; diff -Nru a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c --- a/drivers/net/wan/hdlc_ppp.c Fri Sep 20 08:20:41 2002 +++ b/drivers/net/wan/hdlc_ppp.c Fri Sep 20 08:20:41 2002 @@ -96,13 +96,11 @@ /* no settable parameters */ - hdlc_detach(hdlc); - result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); - if (result) { - hdlc->proto = -1; + if (result) return result; - } + + hdlc_proto_detach(hdlc); hdlc->open = ppp_open; hdlc->stop = ppp_close; diff -Nru a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c --- a/drivers/net/wan/hdlc_raw.c Fri Sep 20 08:20:47 2002 +++ b/drivers/net/wan/hdlc_raw.c Fri Sep 20 08:20:47 2002 @@ -39,35 +39,40 @@ { raw_hdlc_proto *raw_s = &ifr->ifr_settings->ifs_hdlc.raw_hdlc; const size_t size = sizeof(raw_hdlc_proto); + raw_hdlc_proto new_settings; struct net_device *dev = hdlc_to_dev(hdlc); int result; switch (ifr->ifr_settings->type) { case IF_GET_PROTO: + ifr->ifr_settings->type = IF_PROTO_HDLC; if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size)) return -EFAULT; return 0; case IF_PROTO_HDLC: - if(!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; - if(dev->flags & IFF_UP) + if (dev->flags & IFF_UP) return -EBUSY; - if (copy_from_user(&hdlc->state.raw_hdlc.settings, raw_s, size)) + if (copy_from_user(&new_settings, raw_s, size)) return -EFAULT; + if (new_settings.encoding == ENCODING_DEFAULT) + new_settings.encoding = ENCODING_NRZ; - /* FIXME - put sanity checks here */ - hdlc_detach(hdlc); + if (new_settings.parity == PARITY_DEFAULT) + new_settings.parity = PARITY_NONE; - result=hdlc->attach(hdlc, hdlc->state.raw_hdlc.settings.encoding, - hdlc->state.raw_hdlc.settings.parity); - if (result) { - hdlc->proto = -1; + result = hdlc->attach(hdlc, new_settings.encoding, + new_settings.parity); + if (result) return result; - } + + hdlc_proto_detach(hdlc); + memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); hdlc->open = NULL; hdlc->stop = NULL; diff -Nru a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c --- a/drivers/net/wan/hdlc_x25.c Fri Sep 20 08:20:48 2002 +++ b/drivers/net/wan/hdlc_x25.c Fri Sep 20 08:20:48 2002 @@ -196,13 +196,11 @@ if(dev->flags & IFF_UP) return -EBUSY; - hdlc_detach(hdlc); - result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); - if (result) { - hdlc->proto = -1; + if (result) return result; - } + + hdlc_proto_detach(hdlc); hdlc->open = x25_open; hdlc->stop = x25_close; diff -Nru a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c --- a/drivers/net/wan/n2.c Fri Sep 20 08:20:43 2002 +++ b/drivers/net/wan/n2.c Fri Sep 20 08:20:43 2002 @@ -1,7 +1,7 @@ /* * SDL Inc. RISCom/N2 synchronous serial card driver for Linux * - * Copyright (C) 1998-2001 Krzysztof Halasa + * Copyright (C) 1998-2002 Krzysztof Halasa * * 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 @@ -35,7 +35,7 @@ #include "hd64570.h" -static const char* version = "SDL RISCom/N2 driver version: 1.09"; +static const char* version = "SDL RISCom/N2 driver version: 1.10"; static const char* devname = "RISCom/N2"; #define USE_WINDOWSIZE 16384 @@ -159,7 +159,7 @@ -static int n2_set_iface(port_t *port) +static void n2_set_iface(port_t *port) { card_t *card = port->card; int io = card->io; @@ -169,12 +169,6 @@ u8 txs = port->txs & CLK_BRG_MASK; switch(port->settings.clock_type) { - case CLOCK_EXT: - mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0; - rxs |= CLK_LINE_RX; /* RXC input */ - txs |= CLK_LINE_TX; /* TXC input */ - break; - case CLOCK_INT: mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; rxs |= CLK_BRG_RX; /* BRG output */ @@ -193,8 +187,10 @@ txs |= CLK_RXCLK_TX; /* RX clock */ break; - default: - return -EINVAL; + default: /* Clock EXTernal */ + mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0; + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_LINE_TX; /* TXC input */ } outb(mcr, io + N2_MCR); @@ -203,7 +199,6 @@ sca_out(rxs, msci + RXS, card); sca_out(txs, msci + TXS, card); sca_set_port(port); - return 0; } @@ -226,7 +221,8 @@ outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */ outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */ sca_open(hdlc); - return n2_set_iface(port); + n2_set_iface(port); + return 0; } @@ -252,6 +248,7 @@ { union line_settings *line = &ifr->ifr_settings->ifs_line; const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; hdlc_device *hdlc = dev_to_hdlc(dev); port_t *port = hdlc_to_port(hdlc); @@ -275,10 +272,21 @@ if(!capable(CAP_NET_ADMIN)) return -EPERM; - if (copy_from_user(&port->settings, &line->sync, size)) + if (copy_from_user(&new_line, &line->sync, size)) return -EFAULT; - /* FIXME - put sanity checks here */ - return n2_set_iface(port); + + if (new_line.clock_type != CLOCK_EXT && + new_line.clock_type != CLOCK_TXFROMRX && + new_line.clock_type != CLOCK_INT && + new_line.clock_type != CLOCK_TXINT) + return -EINVAL; /* No such clock setting */ + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + memcpy(&port->settings, &new_line, size); /* Update settings */ + n2_set_iface(port); + return 0; default: return hdlc_ioctl(dev, ifr, cmd); diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c --- a/drivers/net/wireless/airo.c Fri Sep 20 08:20:42 2002 +++ b/drivers/net/wireless/airo.c Fri Sep 20 08:20:42 2002 @@ -273,26 +273,76 @@ #define NO_PACKET -2 /* Commands */ -#define NOP 0x0010 -#define MAC_ENABLE 0x0001 -#define MAC_DISABLE 0x0002 -#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */ -#define CMD_MAGIC_PKT 0x0006 -#define CMD_ACCESS 0x0021 -#define CMD_ALLOCATETX 0x000a -#define CMD_TRANSMIT 0x000b -#define CMD_DEALLOCATETX 0x000c -#define HOSTSLEEP 0x85 -#define CMD_SETMODE 0x0009 -#define CMD_ENABLEAUX 0x0111 -#define CMD_SOFTRESET 0x0004 -#define CMD_ALLOCBUF 0x0028 -#define CMD_PSPNODES 0x0030 -#define CMD_SETPHYREG 0x003e -#define CMD_TXTEST 0x003f -#define CMD_READCFG 0x0008 -#define CMD_SAVECFG 0x0108 -#define CMD_LISTBSS 0x0103 +#define NOP2 0x00 +#define MAC_ENABLE 0x01 +#define MAC_ENABLETX 0x101 +#define CMD_ENABLEAUX 0x111 +#define MAC_ENABLERX 0x201 +#define MAC_DISABLE 0x02 +#define CMD_LOSE_SYNC 0x03 +#define CMD_LOSE_SYNC_BSS 0x103 +#define CMD_SOFTRESET 0x04 +#define HOSTSLEEP 0x05 +#define CMD_MAGICPACKET 0x06 +#define CMD_SETWAKEMASK 0x07 +#define CMD_SAVECONFIG 0x108 +#define CMD_READCONFIG 0x08 +#define CMD_SETMODE 0x09 +#define CMD_ALLOCATETX 0x0A +#define CMD_TRANSMIT 0x0B +#define CMD_DEALLOC 0x0C +#define CMD_LISTBSS 0x103 +#define NOP 0x10 +#define CMD_WORKAROUND 0x11 +#define CMD_ACCESS 0x21 +#define CMD_WRITERID 0x121 +#define CMD_PCIBAP 0x22 +#define CMD_PCIAUX 0x23 +#define CMD_ALLOCTLV 0x28 +#define CMD_GETTLV 0x29 +#define CMD_PUTTLV 0x2A +#define CMD_DELTLV 0x2B +#define CMD_FINDNEXTTLV 0x2C +#define CMD_SETPHYREG 0x3E +#define CMD_TXTEST 0x3F +#define CMD_NOPSPNODES 0x30 +#define CMD_USEPSPNODES 0x130 +#define CMD_SETCW 0x31 +#define CMD_SETPCF 0x32 + +/* Command errors */ +#define ERROR_QUALIF 0x00 +#define ERROR_ILLCMD 0x01 +#define ERROR_ILLFMT 0x02 +#define ERROR_INVFID 0x03 +#define ERROR_INVRID 0x04 +#define ERROR_LARGE 0x05 +#define ERROR_NDISABL 0x06 +#define ERROR_ALLOCBSY 0x07 +#define ERROR_NORD 0x0B +#define ERROR_NOWR 0x0C +#define ERROR_INVFIDTX 0x0D +#define ERROR_TESTACT 0x0E +#define ERROR_TAGNFND 0x12 +#define ERROR_DECODE 0x20 +#define ERROR_DESCUNAV 0x21 +#define ERROR_BADLEN 0x22 +#define ERROR_MODE 0x80 +#define ERROR_HOP 0x81 +#define ERROR_BINTER 0x82 +#define ERROR_RXMODE 0x83 +#define ERROR_MACADDR 0x84 +#define ERROR_RATES 0x85 +#define ERROR_ORDER 0x86 +#define ERROR_SCAN 0x87 +#define ERROR_AUTH 0x88 +#define ERROR_PSMODE 0x89 +#define ERROR_RTYPE 0x8A +#define ERROR_DIVER 0x8B +#define ERROR_SSID 0x8C +#define ERROR_APLIST 0x8D +#define ERROR_AUTOWAKE 0x8E +#define ERROR_LEAP 0x8F /* Registers */ #define COMMAND 0x00 @@ -386,8 +436,8 @@ #define RID_STATS 0xFF68 #define RID_STATSDELTA 0xFF69 #define RID_STATSDELTACLEAR 0xFF6A -#define RID_UNKNOWN70 0xFF70 -#define RID_UNKNOWN71 0xFF71 +#define RID_ECHOTEST_RID 0xFF70 +#define RID_ECHOTEST_RESULTS 0xFF71 #define RID_BSSLISTFIRST 0xFF72 #define RID_BSSLISTNEXT 0xFF73 diff -Nru a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c --- a/drivers/net/wireless/netwave_cs.c Fri Sep 20 08:20:45 2002 +++ b/drivers/net/wireless/netwave_cs.c Fri Sep 20 08:20:45 2002 @@ -324,6 +324,7 @@ typedef struct netwave_private { dev_link_t link; struct net_device dev; + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ dev_node_t node; u_char *ramBase; int timeoutCounter; @@ -415,8 +416,7 @@ wstats = &priv->iw_stats; - save_flags(flags); - cli(); + spin_lock_irqsave(&priv->spinlock, flags); netwave_snapshot( priv, ramBase, iobase); @@ -428,7 +428,7 @@ wstats->discard.code = 0L; wstats->discard.misc = 0L; - restore_flags(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return &priv->iw_stats; } @@ -491,6 +491,10 @@ link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; + /* Netwave private struct init. link/dev/node already taken care of, + * other stuff zero'd - Jean II */ + spin_lock_init(&priv->spinlock); + /* Netwave specific entries in the device structure */ dev->hard_start_xmit = &netwave_start_xmit; dev->set_config = &netwave_config; @@ -640,8 +644,7 @@ u_char *ramBase = priv->ramBase; /* Disable interrupts & save flags */ - save_flags(flags); - cli(); + spin_lock_irqsave(&priv->spinlock, flags); #if WIRELESS_EXT > 8 if(!wrqu->nwid.disabled) { @@ -660,7 +663,7 @@ } /* ReEnable interrupts & restore flags */ - restore_flags(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return 0; } @@ -699,8 +702,7 @@ u_char *ramBase = priv->ramBase; /* Disable interrupts & save flags */ - save_flags(flags); - cli(); + spin_lock_irqsave(&priv->spinlock, flags); scramble_key = (key[0] << 8) | key[1]; wait_WOC(iobase); @@ -710,7 +712,7 @@ writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); /* ReEnable interrupts & restore flags */ - restore_flags(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return 0; } @@ -816,8 +818,7 @@ u_char *ramBase = priv->ramBase; /* Disable interrupts & save flags */ - save_flags(flags); - cli(); + spin_lock_irqsave(&priv->spinlock, flags); /* Take snapshot of environment */ netwave_snapshot( priv, ramBase, iobase); @@ -827,7 +828,7 @@ priv->lastExec = jiffies; /* ReEnable interrupts & restore flags */ - restore_flags(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return(0); } @@ -1376,8 +1377,7 @@ ioaddr_t iobase = dev->base_addr; /* Disable interrupts & save flags */ - save_flags(flags); - cli(); + spin_lock_irqsave(&priv->spinlock, flags); /* Check if there are transmit buffers available */ wait_WOC(iobase); @@ -1385,7 +1385,7 @@ /* No buffers available */ printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n", dev->name); - restore_flags(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return 1; } @@ -1426,7 +1426,7 @@ writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); - restore_flags( flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return 0; } @@ -1618,16 +1618,15 @@ } static void update_stats(struct net_device *dev) { - unsigned long flags; + //unsigned long flags; +/* netwave_private *priv = (netwave_private*) dev->priv; */ - save_flags(flags); - cli(); + //spin_lock_irqsave(&priv->spinlock, flags); -/* netwave_private *priv = (netwave_private*) dev->priv; - priv->stats.rx_packets = readb(priv->ramBase + 0x18e); +/* priv->stats.rx_packets = readb(priv->ramBase + 0x18e); priv->stats.tx_packets = readb(priv->ramBase + 0x18f); */ - restore_flags(flags); + //spin_unlock_irqrestore(&priv->spinlock, flags); } static int netwave_rx(struct net_device *dev) { diff -Nru a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c --- a/drivers/net/wireless/wavelan.c Fri Sep 20 08:20:47 2002 +++ b/drivers/net/wireless/wavelan.c Fri Sep 20 08:20:47 2002 @@ -312,8 +312,11 @@ */ static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d) { + int count = 0; + /* Wait for MMC to go idle */ - while (inw(HASR(ioaddr)) & HASR_MMC_BUSY); + while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) + udelay(10); outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr)); } @@ -339,10 +342,14 @@ */ static inline u8 mmc_in(unsigned long ioaddr, u16 o) { - while (inw(HASR(ioaddr)) & HASR_MMC_BUSY); + int count = 0; + + while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) + udelay(10); outw(o << 1, MMCR(ioaddr)); - while (inw(HASR(ioaddr)) & HASR_MMC_BUSY); + while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) + udelay(10); return (u8) (inw(MMCR(ioaddr)) >> 8); } @@ -2958,6 +2965,9 @@ (unsigned char *) &nop.nop_h.ac_link, sizeof(nop.nop_h.ac_link)); + /* Make sure the watchdog will keep quiet for a while */ + dev->trans_start = jiffies; + /* Keep stats up to date. */ lp->stats.tx_bytes += length; @@ -3874,29 +3884,48 @@ * the spinlock. */ spin_lock(&lp->spinlock); + /* We always had spurious interrupts at startup, but lately I + * saw them comming *between* the request_irq() and the + * spin_lock_irqsave() in wavelan_open(), so the spinlock + * protection is no enough. + * So, we also check lp->hacr that will tell us is we enabled + * irqs or not (see wv_ints_on()). + * We can't use netif_running(dev) because we depend on the + * proper processing of the irq generated during the config. */ + + /* Which interrupt it is ? */ + hasr = hasr_read(ioaddr); + +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO + "%s: wavelan_interrupt(): hasr 0x%04x; hacr 0x%04x.\n", + dev->name, hasr, lp->hacr); +#endif + /* Check modem interrupt */ - if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) { + if ((hasr & HASR_MMC_INTR) && (lp->hacr & HACR_MMC_INT_ENABLE)) { u8 dce_status; +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", + dev->name, dce_status); +#endif /* * Interrupt from the modem management controller. * This will clear it -- ignored for now. */ mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, sizeof(dce_status)); -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO - "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", - dev->name, dce_status); -#endif } /* Check if not controller interrupt */ - if ((hasr & HASR_82586_INTR) == 0) { + if (((hasr & HASR_82586_INTR) == 0) || + ((lp->hacr & HACR_82586_INT_ENABLE) == 0)) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO - "%s: wavelan_interrupt(): interrupt not coming from i82586\n", - dev->name); + "%s: wavelan_interrupt(): interrupt not coming from i82586 - hasr 0x%04x.\n", + dev->name, hasr); #endif spin_unlock (&lp->spinlock); return; diff -Nru a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h --- a/drivers/net/wireless/wavelan.p.h Fri Sep 20 08:20:47 2002 +++ b/drivers/net/wireless/wavelan.p.h Fri Sep 20 08:20:47 2002 @@ -351,6 +351,12 @@ * o got rid of wavelan_ioctl() * o use a bunch of iw_handler instead * + * Changes made for release in 2.5.35 : + * ---------------------------------- + * - Set dev->trans_start to avoid filling the logs + * - Handle better spurious/bogus interrupt + * - Avoid deadlocks in mmc_out()/mmc_in() + * * Wishes & dreams: * ---------------- * - roaming (see Pcmcia driver) diff -Nru a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c --- a/drivers/net/wireless/wavelan_cs.c Fri Sep 20 08:20:46 2002 +++ b/drivers/net/wireless/wavelan_cs.c Fri Sep 20 08:20:46 2002 @@ -56,6 +56,8 @@ * */ +#include +#include #include "wavelan_cs.p.h" /* Private header */ /************************* MISC SUBROUTINES **************************/ @@ -282,9 +284,11 @@ u_short o, u_char d) { + int count = 0; + /* Wait for MMC to go idle */ - while(inb(HASR(base)) & HASR_MMI_BUSY) - ; + while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) + udelay(10); outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base)); outb(d, MMD(base)); @@ -317,14 +321,16 @@ mmc_in(u_long base, u_short o) { - while(inb(HASR(base)) & HASR_MMI_BUSY) - ; + int count = 0; + + while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) + udelay(10); outb(o << 1, MMR(base)); /* Set the read address */ outb(0, MMD(base)); /* Required dummy write */ - while(inb(HASR(base)) & HASR_MMI_BUSY) - ; + while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) + udelay(10); return (u_char) (inb(MMD(base))); /* Now do the actual read */ } @@ -1854,6 +1860,27 @@ } #endif /* HISTOGRAM */ +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + + strncpy(info.driver, "wavelan_cs", sizeof(info.driver)-1); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + /*------------------------------------------------------------------*/ /* * Wireless Handler : get protocol name @@ -2885,6 +2912,10 @@ /* Look what is the request */ switch(cmd) { + case SIOCETHTOOL: + ret = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + break; + /* --------------- WIRELESS EXTENSIONS --------------- */ case SIOCGIWNAME: @@ -3581,6 +3612,9 @@ /* Send the transmit command */ wv_82593_cmd(dev, "wv_packet_write(): transmit", OP0_TRANSMIT, SR0_NO_RESULT); + + /* Make sure the watchdog will keep quiet for a while */ + dev->trans_start = jiffies; /* Keep stats up to date */ lp->stats.tx_bytes += length; diff -Nru a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h --- a/drivers/net/wireless/wavelan_cs.p.h Fri Sep 20 08:20:44 2002 +++ b/drivers/net/wireless/wavelan_cs.p.h Fri Sep 20 08:20:44 2002 @@ -400,6 +400,12 @@ * o got rid of wavelan_ioctl() * o use a bunch of iw_handler instead * + * Changes made for release in 3.2.1 : + * --------------------------------- + * - Set dev->trans_start to avoid filling the logs + * (and generating useless abort commands) + * - Avoid deadlocks in mmc_out()/mmc_in() + * * Wishes & dreams: * ---------------- * - Cleanup and integrate the roaming code diff -Nru a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c --- a/drivers/net/yellowfin.c Fri Sep 20 08:20:44 2002 +++ b/drivers/net/yellowfin.c Fri Sep 20 08:20:44 2002 @@ -1025,17 +1025,11 @@ if (tx_errs & 0x0800) yp->stats.tx_carrier_errors++; if (tx_errs & 0x2000) yp->stats.tx_window_errors++; if (tx_errs & 0x8000) yp->stats.tx_fifo_errors++; -#ifdef ETHER_STATS - if (tx_errs & 0x1000) yp->stats.collisions16++; -#endif } else { #ifndef final_version if (yellowfin_debug > 4) printk(KERN_DEBUG "%s: Normal transmit, Tx status %4.4x.\n", dev->name, tx_errs); -#endif -#ifdef ETHER_STATS - if (tx_errs & 0x0400) yp->stats.tx_deferred++; #endif yp->stats.tx_bytes += skb->len; yp->stats.collisions += tx_errs & 15; diff -Nru a/drivers/pci/pool.c b/drivers/pci/pool.c --- a/drivers/pci/pool.c Fri Sep 20 08:20:48 2002 +++ b/drivers/pci/pool.c Fri Sep 20 08:20:48 2002 @@ -69,7 +69,7 @@ } /* per-pool info, no real statistics yet */ - temp = snprintf (next, size, "%-16s %4u %4u %4u %2u\n", + temp = snprintf (next, size, "%-16s %4u %4Zu %4Zu %2u\n", pool->name, blocks, pages * pool->blocks_per_page, pool->size, pages); diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c --- a/drivers/pci/probe.c Fri Sep 20 08:20:43 2002 +++ b/drivers/pci/probe.c Fri Sep 20 08:20:43 2002 @@ -444,6 +444,8 @@ return NULL; } + pci_name_device(dev); + /* now put in global tree */ strcpy(dev->dev.name,dev->name); strcpy(dev->dev.bus_id,dev->slot_name); @@ -471,7 +473,6 @@ dev = pci_scan_device(temp); if (!dev) continue; - pci_name_device(dev); if (!func) { is_multi = hdr_type & 0x80; first_dev = dev; diff -Nru a/drivers/pci/proc.c b/drivers/pci/proc.c --- a/drivers/pci/proc.c Fri Sep 20 08:20:46 2002 +++ b/drivers/pci/proc.c Fri Sep 20 08:20:46 2002 @@ -371,7 +371,7 @@ show: show_device }; -static struct proc_dir_entry *proc_bus_pci_dir; +struct proc_dir_entry *proc_bus_pci_dir; /* driverfs files */ static ssize_t pci_show_irq(struct device * dev, char * buf, size_t count, loff_t off) @@ -621,5 +621,6 @@ EXPORT_SYMBOL(pci_proc_detach_device); EXPORT_SYMBOL(pci_proc_attach_bus); EXPORT_SYMBOL(pci_proc_detach_bus); +EXPORT_SYMBOL(proc_bus_pci_dir); #endif diff -Nru a/drivers/pcmcia/sa1100.h b/drivers/pcmcia/sa1100.h --- a/drivers/pcmcia/sa1100.h Fri Sep 20 08:20:47 2002 +++ b/drivers/pcmcia/sa1100.h Fri Sep 20 08:20:47 2002 @@ -160,7 +160,7 @@ */ socket_state_t cs_state; pccard_io_map io_map[MAX_IO_WIN]; - pccard_mem_map mem_map[MAX_WIN]; + pccard_mem_map pc_mem_map[MAX_WIN]; void (*handler)(void *, unsigned int); void *handler_info; diff -Nru a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c --- a/drivers/pcmcia/sa1100_generic.c Fri Sep 20 08:20:47 2002 +++ b/drivers/pcmcia/sa1100_generic.c Fri Sep 20 08:20:47 2002 @@ -686,7 +686,7 @@ DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); if (map->map < MAX_WIN) { - *map = skt->mem_map[map->map]; + *map = skt->pc_mem_map[map->map]; ret = 0; } @@ -754,7 +754,7 @@ map->sys_stop += start; map->sys_start = start; - skt->mem_map[map->map] = *map; + skt->pc_mem_map[map->map] = *map; return 0; } /* sa1100_pcmcia_set_mem_map() */ diff -Nru a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c --- a/drivers/s390/net/iucv.c Fri Sep 20 08:20:41 2002 +++ b/drivers/s390/net/iucv.c Fri Sep 20 08:20:41 2002 @@ -418,7 +418,7 @@ /** * grab_param: - Get a parameter buffer from the pre-allocated pool. * - * This function searches for an unused element in the the pre-allocated pool + * This function searches for an unused element in the pre-allocated pool * of parameter buffers. If one is found, it marks it "in use" and returns * a pointer to it. The calling function is responsible for releasing it * when it has finished its usage. @@ -1525,7 +1525,7 @@ * buflen - length of reply buffer * Output: ipbfadr2 - Address of buffer updated by the number * of bytes you have moved. - * ipbfln2f - Contains on the the following values + * ipbfln2f - Contains one of the following values: * If the answer buffer is the same length as the reply, this field * contains zero. * If the answer buffer is longer than the reply, this field contains @@ -1590,7 +1590,7 @@ * buffer - address of array of reply buffers * buflen - total length of reply buffers * Output: ipbfadr2 - Address of buffer which IUCV is currently working on. - * ipbfln2f - Contains on the the following values + * ipbfln2f - Contains one of the following values: * If the answer buffer is the same length as the reply, this field * contains zero. * If the answer buffer is longer than the reply, this field contains diff -Nru a/drivers/sbus/char/Config.in b/drivers/sbus/char/Config.in --- a/drivers/sbus/char/Config.in Fri Sep 20 08:20:42 2002 +++ b/drivers/sbus/char/Config.in Fri Sep 20 08:20:42 2002 @@ -18,7 +18,7 @@ # XXX Why don't we do "source drivers/char/Config.in" somewhere? if [ "$CONFIG_PCI" = "y" ]; then define_bool CONFIG_APM_RTC_IS_GMT y # no shit - bool 'PC-style RTC' CONFIG_RTC + tristate 'PC-style Real Time Clock Support' CONFIG_RTC fi fi fi diff -Nru a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c --- a/drivers/sbus/char/bbc_envctrl.c Fri Sep 20 08:20:44 2002 +++ b/drivers/sbus/char/bbc_envctrl.c Fri Sep 20 08:20:44 2002 @@ -612,7 +612,7 @@ int found = 0; read_lock(&tasklist_lock); - for_each_task(p) { + for_each_process(p) { if (p == kenvctrld_task) { found = 1; break; diff -Nru a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c --- a/drivers/sbus/char/envctrl.c Fri Sep 20 08:20:43 2002 +++ b/drivers/sbus/char/envctrl.c Fri Sep 20 08:20:43 2002 @@ -1141,7 +1141,7 @@ int found = 0; read_lock(&tasklist_lock); - for_each_task(p) { + for_each_process(p) { if (p == kenvctrld_task) { found = 1; break; diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile Fri Sep 20 08:20:44 2002 +++ b/drivers/scsi/Makefile Fri Sep 20 08:20:44 2002 @@ -120,8 +120,9 @@ obj-$(CONFIG_CHR_DEV_SG) += sg.o scsi_mod-objs := scsi.o hosts.o scsi_ioctl.o constants.o scsicam.o \ - scsi_proc.o scsi_error.o scsi_queue.o scsi_lib.o \ - scsi_merge.o scsi_scan.o scsi_syms.o + scsi_proc.o scsi_error.o scsi_lib.o scsi_merge.o \ + scsi_scan.o scsi_syms.o + sd_mod-objs := sd.o sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o initio-objs := ini9100u.o i91uscsi.o diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c Fri Sep 20 08:20:46 2002 +++ b/drivers/scsi/scsi.c Fri Sep 20 08:20:46 2002 @@ -594,6 +594,90 @@ } /* + * Function: scsi_mlqueue_insert() + * + * Purpose: Insert a command in the midlevel queue. + * + * Arguments: cmd - command that we are adding to queue. + * reason - why we are inserting command to queue. + * + * Lock status: Assumed that lock is not held upon entry. + * + * Returns: Nothing. + * + * Notes: We do this for one of two cases. Either the host is busy + * and it cannot accept any more commands for the time being, + * or the device returned QUEUE_FULL and can accept no more + * commands. + * Notes: This could be called either from an interrupt context or a + * normal process context. + */ +static int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason) +{ + struct Scsi_Host *host = cmd->host; + unsigned long flags; + + SCSI_LOG_MLQUEUE(1, + printk("Inserting command %p into mlqueue\n", cmd)); + + /* + * We are inserting the command into the ml queue. First, we + * cancel the timer, so it doesn't time out. + */ + scsi_delete_timer(cmd); + + /* + * Next, set the appropriate busy bit for the device/host. + * + * If the host/device isn't busy, assume that something actually + * completed, and that we should be able to queue a command now. + * + * Note that there is an implicit assumption that every host can + * always queue at least one command. If a host is inactive and + * cannot queue any commands, I don't see how things could + * possibly work anyways. + */ + if (reason == SCSI_MLQUEUE_HOST_BUSY) { + if (host->host_busy == 0) { + if (scsi_retry_command(cmd) == 0) { + return 0; + } + } + host->host_blocked = TRUE; + } else { + if (cmd->device->device_busy == 0) { + if (scsi_retry_command(cmd) == 0) { + return 0; + } + } + cmd->device->device_blocked = TRUE; + } + + /* + * Register the fact that we own the thing for now. + */ + cmd->state = SCSI_STATE_MLQUEUE; + cmd->owner = SCSI_OWNER_MIDLEVEL; + cmd->bh_next = NULL; + + /* + * Decrement the counters, since these commands are no longer + * active on the host/device. + */ + spin_lock_irqsave(cmd->host->host_lock, flags); + cmd->host->host_busy--; + cmd->device->device_busy--; + spin_unlock_irqrestore(cmd->host->host_lock, flags); + + /* + * Insert this command at the head of the queue for it's device. + * It will go before all other commands that are already in the queue. + */ + scsi_insert_special_cmd(cmd, 1); + return 0; +} + +/* * Function: scsi_release_command * * Purpose: Release a command block. @@ -2453,6 +2537,7 @@ { struct scsi_host_sg_pool *sgp; struct scatterlist *sgl; + int pf_flags; BUG_ON(!SCpnt->use_sg); @@ -2467,9 +2552,10 @@ sgp = scsi_sg_pools + SCpnt->sglist_len; + pf_flags = current->flags; current->flags |= PF_NOWARN; sgl = mempool_alloc(sgp->pool, gfp_mask); - current->flags &= ~PF_NOWARN; + current->flags = pf_flags; if (sgl) { memset(sgl, 0, sgp->size); return sgl; diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h --- a/drivers/scsi/scsi.h Fri Sep 20 08:20:43 2002 +++ b/drivers/scsi/scsi.h Fri Sep 20 08:20:43 2002 @@ -461,11 +461,6 @@ extern int scsi_init_io(Scsi_Cmnd *SCpnt); /* - * Prototypes for functions in scsi_queue.c - */ -extern int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason); - -/* * Prototypes for functions in scsi_lib.c */ extern int scsi_maybe_unblock_host(Scsi_Device * SDpnt); diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Fri Sep 20 08:20:46 2002 +++ b/drivers/scsi/scsi_lib.c Fri Sep 20 08:20:46 2002 @@ -317,13 +317,11 @@ ASSERT_LOCK(q->queue_lock, 0); - spin_lock_irqsave(q->queue_lock, flags); /* * If there are blocks left over at the end, set up the command * to queue the remainder of them. */ if (end_that_request_first(req, uptodate, sectors)) { - spin_unlock_irqrestore(q->queue_lock, flags); if (!requeue) return SCpnt; @@ -337,7 +335,9 @@ add_blkdev_randomness(major(req->rq_dev)); - if(blk_rq_tagged(req)) + spin_lock_irqsave(q->queue_lock, flags); + + if (blk_rq_tagged(req)) blk_queue_end_tag(q, req); end_that_request_last(req); diff -Nru a/drivers/scsi/scsi_queue.c b/drivers/scsi/scsi_queue.c --- a/drivers/scsi/scsi_queue.c Fri Sep 20 08:20:47 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,149 +0,0 @@ -/* - * scsi_queue.c Copyright (C) 1997 Eric Youngdale - * - * generic mid-level SCSI queueing. - * - * The point of this is that we need to track when hosts are unable to - * accept a command because they are busy. In addition, we track devices - * that cannot accept a command because of a QUEUE_FULL condition. In both - * of these cases, we enter the command in the queue. At some later point, - * we attempt to remove commands from the queue and retry them. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define __KERNEL_SYSCALLS__ - -#include - -#include -#include -#include - -#include "scsi.h" -#include "hosts.h" - -/* - * TODO: - * 1) Prevent multiple traversals of list to look for commands to - * queue. - * 2) Protect against multiple insertions of list at the same time. - * DONE: - * 1) Set state of scsi command to a new state value for ml queue. - * 2) Insert into queue when host rejects command. - * 3) Make sure status code is properly passed from low-level queue func - * so that internal_cmnd properly returns the right value. - * 4) Insert into queue when QUEUE_FULL. - * 5) Cull queue in bottom half handler. - * 6) Check usage count prior to queue insertion. Requeue if usage - * count is 0. - * 7) Don't send down any more commands if the host/device is busy. - */ - -static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_queue.c,v 1.1 1997/10/21 11:16:38 eric Exp $"; - - -/* - * Function: scsi_mlqueue_insert() - * - * Purpose: Insert a command in the midlevel queue. - * - * Arguments: cmd - command that we are adding to queue. - * reason - why we are inserting command to queue. - * - * Lock status: Assumed that lock is not held upon entry. - * - * Returns: Nothing. - * - * Notes: We do this for one of two cases. Either the host is busy - * and it cannot accept any more commands for the time being, - * or the device returned QUEUE_FULL and can accept no more - * commands. - * Notes: This could be called either from an interrupt context or a - * normal process context. - */ -int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason) -{ - struct Scsi_Host *host; - unsigned long flags; - - SCSI_LOG_MLQUEUE(1, printk("Inserting command %p into mlqueue\n", cmd)); - - /* - * We are inserting the command into the ml queue. First, we - * cancel the timer, so it doesn't time out. - */ - scsi_delete_timer(cmd); - - host = cmd->host; - - /* - * Next, set the appropriate busy bit for the device/host. - */ - if (reason == SCSI_MLQUEUE_HOST_BUSY) { - /* - * Protect against race conditions. If the host isn't busy, - * assume that something actually completed, and that we should - * be able to queue a command now. Note that there is an implicit - * assumption that every host can always queue at least one command. - * If a host is inactive and cannot queue any commands, I don't see - * how things could possibly work anyways. - */ - if (host->host_busy == 0) { - if (scsi_retry_command(cmd) == 0) { - return 0; - } - } - host->host_blocked = TRUE; - } else { - /* - * Protect against race conditions. If the device isn't busy, - * assume that something actually completed, and that we should - * be able to queue a command now. Note that there is an implicit - * assumption that every host can always queue at least one command. - * If a host is inactive and cannot queue any commands, I don't see - * how things could possibly work anyways. - */ - if (cmd->device->device_busy == 0) { - if (scsi_retry_command(cmd) == 0) { - return 0; - } - } - cmd->device->device_blocked = TRUE; - } - - /* - * Register the fact that we own the thing for now. - */ - cmd->state = SCSI_STATE_MLQUEUE; - cmd->owner = SCSI_OWNER_MIDLEVEL; - cmd->bh_next = NULL; - - /* - * Decrement the counters, since these commands are no longer - * active on the host/device. - */ - spin_lock_irqsave(cmd->host->host_lock, flags); - cmd->host->host_busy--; - cmd->device->device_busy--; - spin_unlock_irqrestore(cmd->host->host_lock, flags); - - /* - * Insert this command at the head of the queue for it's device. - * It will go before all other commands that are already in the queue. - */ - scsi_insert_special_cmd(cmd, 1); - return 0; -} diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Fri Sep 20 08:20:43 2002 +++ b/drivers/scsi/sd.c Fri Sep 20 08:20:43 2002 @@ -1314,6 +1314,7 @@ p = kmalloc(sizeof(*p), GFP_KERNEL); if (!p) return 1; + memset(p, 0, sizeof(*p)); gd = &p->disk; SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c --- a/drivers/scsi/sg.c Fri Sep 20 08:20:46 2002 +++ b/drivers/scsi/sg.c Fri Sep 20 08:20:46 2002 @@ -1462,6 +1462,7 @@ } SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); + memset(sdp, 0, sizeof(*sdp)); sdp->device = scsidp; init_waitqueue_head(&sdp->o_excl_wait); sdp->headfp = NULL; diff -Nru a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c --- a/drivers/serial/sunsu.c Fri Sep 20 08:20:43 2002 +++ b/drivers/serial/sunsu.c Fri Sep 20 08:20:43 2002 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -28,11 +29,12 @@ #include #include #include +#include #include -#include #ifdef CONFIG_SERIO #include #endif +#include #include #include @@ -44,8 +46,12 @@ #include #endif +/* #if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) */ +#if defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + #include -#include #include "suncore.h" @@ -88,6 +94,7 @@ /* Probing information. */ enum su_type su_type; + unsigned int type_probed; /* XXX Stupid */ int port_node; unsigned int irq; @@ -333,7 +340,8 @@ if (*status & UART_LSR_BI) { *status &= ~(UART_LSR_FE | UART_LSR_PE); up->port.icount.brk++; - if (up->port.line == up->port.cons->index) + if (up->port.cons != NULL && + up->port.line == up->port.cons->index) saw_console_brk = 1; /* * We do the SysRQ and SAK checking @@ -355,7 +363,8 @@ */ *status &= up->port.read_status_mask; - if (up->port.line == up->port.cons->index) { + if (up->port.cons != NULL && + up->port.line == up->port.cons->index) { /* Recover the break flag from console xmit */ *status |= up->lsr_break_flag; up->lsr_break_flag = 0; @@ -910,6 +919,16 @@ static void sunsu_config_port(struct uart_port *port, int flags) { + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + + if (flags & UART_CONFIG_TYPE) { + /* + * We are supposed to call autoconfig here, but this requires + * splitting all the OBP probing crap from the UART probing. + * We'll do it when we kill sunsu.c altogether. + */ + port->type = up->type_probed; /* XXX */ + } } static int @@ -1020,6 +1039,7 @@ if (!up->port_node || !up->su_type) return; + up->type_probed = PORT_UNKNOWN; up->port.iotype = SERIAL_IO_MEM; /* @@ -1028,7 +1048,16 @@ for_each_ebus(ebus) { for_each_ebusdev(dev, ebus) { if (dev->prom_node == up->port_node) { + /* + * The EBus is broken on sparc; it delivers + * virtual addresses in resources. Oh well... + * This is correct on sparc64, though. + */ up->port.membase = (char *) dev->resource[0].start; + /* + * This is correct on both architectures. + */ + up->port.mapbase = dev->resource[0].start; up->irq = dev->irqs[0]; goto ebus_done; } @@ -1039,7 +1068,9 @@ for_each_isa(isa_br) { for_each_isadev(isa_dev, isa_br) { if (isa_dev->prom_node == up->port_node) { + /* Same on sparc64. Cool architecure... */ up->port.membase = (char *) isa_dev->resource.start; + up->port.mapbase = isa_dev->resource.start; up->irq = isa_dev->irq; goto ebus_done; } @@ -1067,6 +1098,7 @@ reg0.which_io, reg0.phys_addr); return; } + up->port.mapbase = reg0.phys_addr; if ((up->port.membase = ioremap(reg0.phys_addr, reg0.reg_size)) == 0) { prom_printf("sunsu: Cannot map registers.\n"); return; @@ -1203,6 +1235,7 @@ if (up->port.type == PORT_UNKNOWN) goto out; + up->type_probed = up->port.type; /* XXX */ /* * Reset the UART. @@ -1454,6 +1487,7 @@ up->su_type == SU_PORT_KBD) continue; + up->port.flags |= ASYNC_BOOT_AUTOCONF; up->port.type = PORT_UNKNOWN; up->port.uartclk = (SU_BASE_BAUD * 16); @@ -1475,7 +1509,6 @@ if (ret < 0) return ret; - instance = 0; for (i = 0; i < UART_NR; i++) { struct uart_sunsu_port *up = &sunsu_ports[i]; @@ -1645,9 +1678,6 @@ /* * Console must be initiated after the generic initialization. */ - sunsu_reg.cons = &sunsu_cons; - sunsu_reg.nr = scan.devices; - sunsu_serial_init(); sunsu_serial_console_init(); diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c --- a/drivers/usb/serial/visor.c Fri Sep 20 08:20:44 2002 +++ b/drivers/usb/serial/visor.c Fri Sep 20 08:20:44 2002 @@ -591,7 +591,7 @@ info("%s: port %d, is for %s use", serial->type->name, connection_info->connections[i].port, string); /* save off our num_ports info so that we can use it in the calc_num_ports call */ - serial->private = (void *)num_ports; + serial->private = (void *)(long)num_ports; } } @@ -637,7 +637,7 @@ int num_ports = 0; if (serial->private) { - num_ports = (int)serial->private; + num_ports = (int)(long)serial->private; serial->private = NULL; } return num_ports; diff -Nru a/drivers/video/clgenfb.c b/drivers/video/clgenfb.c --- a/drivers/video/clgenfb.c Fri Sep 20 08:20:44 2002 +++ b/drivers/video/clgenfb.c Fri Sep 20 08:20:44 2002 @@ -280,6 +280,7 @@ { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_4 }, { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5430 }, /* GD-5440 has identical id */ { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7543 }, + { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7548 }, { BT_GD5480, NULL, PCI_DEVICE_ID_CIRRUS_5480 }, /* MacPicasso probably */ { BT_PICASSO4, NULL, PCI_DEVICE_ID_CIRRUS_5446 }, /* Picasso 4 is a GD5446 */ { BT_LAGUNA, "CL Laguna", PCI_DEVICE_ID_CIRRUS_5462 }, diff -Nru a/fs/Makefile b/fs/Makefile --- a/fs/Makefile Fri Sep 20 08:20:46 2002 +++ b/fs/Makefile Fri Sep 20 08:20:46 2002 @@ -5,8 +5,6 @@ # Rewritten to use lists instead of if-statements. # -O_TARGET := fs.o - export-objs := open.o dcache.o buffer.o bio.o inode.o dquot.o mpage.o aio.o \ fcntl.o diff -Nru a/fs/aio.c b/fs/aio.c --- a/fs/aio.c Fri Sep 20 08:20:46 2002 +++ b/fs/aio.c Fri Sep 20 08:20:46 2002 @@ -53,7 +53,7 @@ /* Used for rare fput completion. */ static void aio_fput_routine(void *); static struct tq_struct fput_tqueue = { - routine: aio_fput_routine, + .routine = aio_fput_routine, }; static spinlock_t fput_lock = SPIN_LOCK_UNLOCKED; diff -Nru a/fs/bad_inode.c b/fs/bad_inode.c --- a/fs/bad_inode.c Fri Sep 20 08:20:43 2002 +++ b/fs/bad_inode.c Fri Sep 20 08:20:43 2002 @@ -30,37 +30,37 @@ static struct file_operations bad_file_ops = { - llseek: EIO_ERROR, - read: EIO_ERROR, - write: EIO_ERROR, - readdir: EIO_ERROR, - poll: EIO_ERROR, - ioctl: EIO_ERROR, - mmap: EIO_ERROR, - open: EIO_ERROR, - flush: EIO_ERROR, - release: EIO_ERROR, - fsync: EIO_ERROR, - fasync: EIO_ERROR, - lock: EIO_ERROR, + .llseek = EIO_ERROR, + .read = EIO_ERROR, + .write = EIO_ERROR, + .readdir = EIO_ERROR, + .poll = EIO_ERROR, + .ioctl = EIO_ERROR, + .mmap = EIO_ERROR, + .open = EIO_ERROR, + .flush = EIO_ERROR, + .release = EIO_ERROR, + .fsync = EIO_ERROR, + .fasync = EIO_ERROR, + .lock = EIO_ERROR, }; struct inode_operations bad_inode_ops = { - create: EIO_ERROR, - lookup: EIO_ERROR, - link: EIO_ERROR, - unlink: EIO_ERROR, - symlink: EIO_ERROR, - mkdir: EIO_ERROR, - rmdir: EIO_ERROR, - mknod: EIO_ERROR, - rename: EIO_ERROR, - readlink: EIO_ERROR, - follow_link: bad_follow_link, - truncate: EIO_ERROR, - permission: EIO_ERROR, - getattr: EIO_ERROR, + .create = EIO_ERROR, + .lookup = EIO_ERROR, + .link = EIO_ERROR, + .unlink = EIO_ERROR, + .symlink = EIO_ERROR, + .mkdir = EIO_ERROR, + .rmdir = EIO_ERROR, + .mknod = EIO_ERROR, + .rename = EIO_ERROR, + .readlink = EIO_ERROR, + .follow_link = bad_follow_link, + .truncate = EIO_ERROR, + .permission = EIO_ERROR, + .getattr = EIO_ERROR, }; diff -Nru a/fs/binfmt_aout.c b/fs/binfmt_aout.c --- a/fs/binfmt_aout.c Fri Sep 20 08:20:43 2002 +++ b/fs/binfmt_aout.c Fri Sep 20 08:20:43 2002 @@ -37,11 +37,11 @@ extern void dump_thread(struct pt_regs *, struct user *); static struct linux_binfmt aout_format = { - module: THIS_MODULE, - load_binary: load_aout_binary, - load_shlib: load_aout_library, - core_dump: aout_core_dump, - min_coredump: PAGE_SIZE + .module = THIS_MODULE, + .load_binary = load_aout_binary, + .load_shlib = load_aout_library, + .core_dump = aout_core_dump, + .min_coredump = PAGE_SIZE }; static void set_brk(unsigned long start, unsigned long end) diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c Fri Sep 20 08:20:46 2002 +++ b/fs/binfmt_elf.c Fri Sep 20 08:20:46 2002 @@ -71,11 +71,11 @@ #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) static struct linux_binfmt elf_format = { - module: THIS_MODULE, - load_binary: load_elf_binary, - load_shlib: load_elf_library, - core_dump: elf_core_dump, - min_coredump: ELF_EXEC_PAGESIZE + .module = THIS_MODULE, + .load_binary = load_elf_binary, + .load_shlib = load_elf_library, + .core_dump = elf_core_dump, + .min_coredump = ELF_EXEC_PAGESIZE }; #define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE) @@ -146,7 +146,7 @@ if (k_platform) { size_t len = strlen(k_platform) + 1; -#if defined(__i386__) && defined(CONFIG_SMP) +#ifdef CONFIG_X86_HT /* * In some cases (e.g. Hyper-Threading), we want to avoid L1 * evictions by the processes running on the same package. One diff -Nru a/fs/binfmt_em86.c b/fs/binfmt_em86.c --- a/fs/binfmt_em86.c Fri Sep 20 08:20:47 2002 +++ b/fs/binfmt_em86.c Fri Sep 20 08:20:47 2002 @@ -96,8 +96,8 @@ } struct linux_binfmt em86_format = { - module: THIS_MODULE, - load_binary: load_em86, + .module = THIS_MODULE, + .load_binary = load_em86, }; static int __init init_em86_binfmt(void) diff -Nru a/fs/binfmt_misc.c b/fs/binfmt_misc.c --- a/fs/binfmt_misc.c Fri Sep 20 08:20:44 2002 +++ b/fs/binfmt_misc.c Fri Sep 20 08:20:44 2002 @@ -485,8 +485,8 @@ } static struct file_operations bm_entry_operations = { - read: bm_entry_read, - write: bm_entry_write, + .read = bm_entry_read, + .write = bm_entry_write, }; static struct file_system_type bm_fs_type; @@ -566,7 +566,7 @@ } static struct file_operations bm_register_operations = { - write: bm_register_write, + .write = bm_register_write, }; /* /status */ @@ -613,21 +613,21 @@ } static struct file_operations bm_status_operations = { - read: bm_status_read, - write: bm_status_write, + .read = bm_status_read, + .write = bm_status_write, }; /* Superblock handling */ static struct super_operations s_ops = { - statfs: simple_statfs, - drop_inode: generic_delete_inode, - clear_inode: bm_clear_inode, + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, + .clear_inode = bm_clear_inode, }; static int bm_fill_super(struct super_block * sb, void * data, int silent) { - struct qstr names[2] = {{name:"status"}, {name:"register"}}; + struct qstr names[2] = {{.name = "status"}, {.name = "register"}}; struct inode * inode; struct dentry * dentry[3]; int i; @@ -688,15 +688,15 @@ } static struct linux_binfmt misc_format = { - module: THIS_MODULE, - load_binary: load_misc_binary, + .module = THIS_MODULE, + .load_binary = load_misc_binary, }; static struct file_system_type bm_fs_type = { - owner: THIS_MODULE, - name: "binfmt_misc", - get_sb: bm_get_sb, - kill_sb: kill_litter_super, + .owner = THIS_MODULE, + .name = "binfmt_misc", + .get_sb = bm_get_sb, + .kill_sb = kill_litter_super, }; static int __init init_misc_binfmt(void) diff -Nru a/fs/binfmt_script.c b/fs/binfmt_script.c --- a/fs/binfmt_script.c Fri Sep 20 08:20:42 2002 +++ b/fs/binfmt_script.c Fri Sep 20 08:20:42 2002 @@ -95,8 +95,8 @@ } struct linux_binfmt script_format = { - module: THIS_MODULE, - load_binary: load_script, + .module = THIS_MODULE, + .load_binary = load_script, }; static int __init init_script_binfmt(void) diff -Nru a/fs/bio.c b/fs/bio.c --- a/fs/bio.c Fri Sep 20 08:20:47 2002 +++ b/fs/bio.c Fri Sep 20 08:20:47 2002 @@ -46,13 +46,11 @@ */ #define BV(x) { x, "biovec-" #x } -static struct biovec_pool bvec_array[BIOVEC_NR_POOLS] = { - BV(1), BV(4), BV(16), BV(64), BV(128), BV(256) -}; +static struct biovec_pool bvec_array[BIOVEC_NR_POOLS] = { + BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES), +}; #undef BV -#define BIO_MAX_PAGES (bvec_array[BIOVEC_NR_POOLS - 1].size) - static void *slab_pool_alloc(int gfp_mask, void *data) { return kmem_cache_alloc(data, gfp_mask); @@ -77,7 +75,7 @@ case 5 ... 16: *idx = 2; break; case 17 ... 64: *idx = 3; break; case 65 ... 128: *idx = 4; break; - case 129 ... 256: *idx = 5; break; + case 129 ... BIO_MAX_PAGES: *idx = 5; break; default: return NULL; } @@ -103,7 +101,7 @@ /* * cloned bio doesn't own the veclist */ - if (!(bio->bi_flags & (1 << BIO_CLONED))) + if (!bio_flagged(bio, BIO_CLONED)) mempool_free(bio->bi_io_vec, bp->pool); mempool_free(bio, bio_pool); @@ -112,7 +110,7 @@ inline void bio_init(struct bio *bio) { bio->bi_next = NULL; - bio->bi_flags = 0; + bio->bi_flags = 1 << BIO_UPTODATE; bio->bi_rw = 0; bio->bi_vcnt = 0; bio->bi_idx = 0; @@ -137,6 +135,7 @@ { struct bio *bio; struct bio_vec *bvl = NULL; + int pf_flags = current->flags; current->flags |= PF_NOWARN; bio = mempool_alloc(bio_pool, gfp_mask); @@ -153,7 +152,7 @@ mempool_free(bio, bio_pool); bio = NULL; out: - current->flags &= ~PF_NOWARN; + current->flags = pf_flags; return bio; } @@ -180,7 +179,7 @@ inline int bio_phys_segments(request_queue_t *q, struct bio *bio) { - if (unlikely(!(bio->bi_flags & (1 << BIO_SEG_VALID)))) + if (unlikely(!bio_flagged(bio, BIO_SEG_VALID))) blk_recount_segments(q, bio); return bio->bi_phys_segments; @@ -188,7 +187,7 @@ inline int bio_hw_segments(request_queue_t *q, struct bio *bio) { - if (unlikely(!(bio->bi_flags & (1 << BIO_SEG_VALID)))) + if (unlikely(!bio_flagged(bio, BIO_SEG_VALID))) blk_recount_segments(q, bio); return bio->bi_hw_segments; @@ -218,7 +217,7 @@ */ bio->bi_vcnt = bio_src->bi_vcnt; bio->bi_idx = bio_src->bi_idx; - if (bio_src->bi_flags & (1 << BIO_SEG_VALID)) { + if (bio_flagged(bio, BIO_SEG_VALID)) { bio->bi_phys_segments = bio_src->bi_phys_segments; bio->bi_hw_segments = bio_src->bi_hw_segments; bio->bi_flags |= (1 << BIO_SEG_VALID); @@ -322,12 +321,97 @@ return NULL; } -static void bio_end_io_kio(struct bio *bio) +/** + * bio_add_page - attempt to add page to bio + * @bio: destination bio + * @page: page to add + * @len: vec entry length + * @offset: vec entry offset + * + * Attempt to add a page to the bio_vec maplist. This can fail for a + * number of reasons, such as the bio being full or target block + * device limitations. + */ +int bio_add_page(struct bio *bio, struct page *page, unsigned int len, + unsigned int offset) +{ + request_queue_t *q = bdev_get_queue(bio->bi_bdev); + int fail_segments = 0, retried_segments = 0; + struct bio_vec *bvec; + + /* + * cloned bio must not modify vec list + */ + if (unlikely(bio_flagged(bio, BIO_CLONED))) + return 1; + + /* + * FIXME: change bi_max? + */ + BUG_ON(bio->bi_max > BIOVEC_NR_POOLS); + + if (bio->bi_vcnt >= bvec_array[bio->bi_max].nr_vecs) + return 1; + + if (((bio->bi_size + len) >> 9) > q->max_sectors) + return 1; + + /* + * we might loose a segment or two here, but rather that than + * make this too complex. + */ +retry_segments: + if (bio_phys_segments(q, bio) >= q->max_phys_segments + || bio_hw_segments(q, bio) >= q->max_hw_segments) + fail_segments = 1; + + if (fail_segments) { + if (retried_segments) + return 1; + + bio->bi_flags &= ~(1 << BIO_SEG_VALID); + retried_segments = 1; + goto retry_segments; + } + + /* + * setup the new entry, we might clear it again later if we + * cannot add the page + */ + bvec = &bio->bi_io_vec[bio->bi_vcnt]; + bvec->bv_page = page; + bvec->bv_len = len; + bvec->bv_offset = offset; + + /* + * if queue has other restrictions (eg varying max sector size + * depending on offset), it can specify a merge_bvec_fn in the + * queue to get further control + */ + if (q->merge_bvec_fn && q->merge_bvec_fn(q, bio, bvec)) { + bvec->bv_page = NULL; + bvec->bv_len = 0; + bvec->bv_offset = 0; + return 1; + } + + bio->bi_vcnt++; + bio->bi_phys_segments++; + bio->bi_hw_segments++; + bio->bi_size += len; + return 0; +} + +static int bio_end_io_kio(struct bio *bio, unsigned int bytes_done, int error) { struct kiobuf *kio = (struct kiobuf *) bio->bi_private; - end_kio_request(kio, test_bit(BIO_UPTODATE, &bio->bi_flags)); + if (bio->bi_size) + return 1; + + end_kio_request(kio, error); bio_put(bio); + return 0; } /** @@ -345,7 +429,6 @@ void ll_rw_kio(int rw, struct kiobuf *kio, struct block_device *bdev, sector_t sector) { int i, offset, size, err, map_i, total_nr_pages, nr_pages; - struct bio_vec *bvec; struct bio *bio; err = 0; @@ -373,7 +456,7 @@ map_i = 0; next_chunk: - nr_pages = BIO_MAX_SECTORS >> (PAGE_SHIFT - 9); + nr_pages = BIO_MAX_PAGES; if (nr_pages > total_nr_pages) nr_pages = total_nr_pages; @@ -393,8 +476,7 @@ bio->bi_end_io = bio_end_io_kio; bio->bi_private = kio; - bvec = bio->bi_io_vec; - for (i = 0; i < nr_pages; i++, bvec++, map_i++) { + for (i = 0; i < nr_pages; i++, map_i++) { int nbytes = PAGE_SIZE - offset; if (nbytes > size) @@ -402,15 +484,12 @@ BUG_ON(kio->maplist[map_i] == NULL); - if (bio->bi_size + nbytes > (BIO_MAX_SECTORS << 9)) - goto queue_io; - - bio->bi_vcnt++; - bio->bi_size += nbytes; - - bvec->bv_page = kio->maplist[map_i]; - bvec->bv_len = nbytes; - bvec->bv_offset = offset; + /* + * if we can't add this page to the bio, submit for i/o + * and alloc a new one if needed + */ + if (bio_add_page(bio, kio->maplist[map_i], nbytes, offset)) + break; /* * kiobuf only has an offset into the first page @@ -423,7 +502,6 @@ kio->offset += nbytes; } -queue_io: submit_bio(rw, bio); if (total_nr_pages) @@ -446,15 +524,33 @@ end_kio_request(kio, !err); } -void bio_endio(struct bio *bio, int uptodate) +/** + * bio_endio - end I/O on a bio + * @bio: bio + * @bytes_done: number of bytes completed + * @error: error, if any + * + * Description: + * bio_endio() will end I/O @bytes_done number of bytes. This may be just + * a partial part of the bio, or it may be the whole bio. bio_endio() is + * the preferred way to end I/O on a bio, it takes care of decrementing + * bi_size and clearing BIO_UPTODATE on error. @error is 0 on success, and + * and one of the established -Exxxx (-EIO, for instance) error values in + * case something went wrong. + **/ +int bio_endio(struct bio *bio, unsigned int bytes_done, int error) { - if (uptodate) - set_bit(BIO_UPTODATE, &bio->bi_flags); - else + if (error) clear_bit(BIO_UPTODATE, &bio->bi_flags); - if (bio->bi_end_io) - bio->bi_end_io(bio); + if (unlikely(bytes_done > bio->bi_size)) { + printk("%s: want %u bytes done, only %u left\n", __FUNCTION__, + bytes_done, bio->bi_size); + bytes_done = bio->bi_size; + } + + bio->bi_size -= bytes_done; + return bio->bi_end_io(bio, bytes_done, error); } static void __init biovec_init_pools(void) @@ -538,3 +634,4 @@ EXPORT_SYMBOL(bio_clone); EXPORT_SYMBOL(bio_phys_segments); EXPORT_SYMBOL(bio_hw_segments); +EXPORT_SYMBOL(bio_add_page); diff -Nru a/fs/block_dev.c b/fs/block_dev.c --- a/fs/block_dev.c Fri Sep 20 08:20:48 2002 +++ b/fs/block_dev.c Fri Sep 20 08:20:48 2002 @@ -198,9 +198,9 @@ } static struct file_system_type bd_type = { - name: "bdev", - get_sb: bd_get_sb, - kill_sb: kill_anon_super, + .name = "bdev", + .get_sb = bd_get_sb, + .kill_sb = kill_anon_super, }; static struct vfsmount *bd_mnt; diff -Nru a/fs/buffer.c b/fs/buffer.c --- a/fs/buffer.c Fri Sep 20 08:20:46 2002 +++ b/fs/buffer.c Fri Sep 20 08:20:46 2002 @@ -35,6 +35,7 @@ #include #include #include +#include #include static void invalidate_bh_lrus(void); @@ -936,9 +937,11 @@ head = NULL; offset = PAGE_SIZE; while ((offset -= size) >= 0) { + int pf_flags = current->flags; + current->flags |= PF_NOWARN; bh = alloc_buffer_head(); - current->flags &= ~PF_NOWARN; + current->flags = pf_flags; if (!bh) goto no_grow; @@ -1622,6 +1625,7 @@ __brelse(old_bh); } } +EXPORT_SYMBOL(unmap_underlying_metadata); /* * NOTE! All mapped/uptodate combinations are valid: @@ -2409,6 +2413,155 @@ } return err ? err : transferred; +} + +static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err) +{ + struct buffer_head *bh = bio->bi_private; + + if (bio->bi_size) + return 1; + + bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags)); + bio_put(bio); + return 0; +} + +int submit_bh(int rw, struct buffer_head * bh) +{ + struct bio *bio; + + BUG_ON(!buffer_locked(bh)); + BUG_ON(!buffer_mapped(bh)); + BUG_ON(!bh->b_end_io); + + if ((rw == READ || rw == READA) && buffer_uptodate(bh)) + buffer_error(); + if (rw == WRITE && !buffer_uptodate(bh)) + buffer_error(); + if (rw == READ && buffer_dirty(bh)) + buffer_error(); + + set_buffer_req(bh); + + /* + * from here on down, it's all bio -- do the initial mapping, + * submit_bio -> generic_make_request may further map this bio around + */ + bio = bio_alloc(GFP_NOIO, 1); + + bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); + bio->bi_bdev = bh->b_bdev; + bio->bi_io_vec[0].bv_page = bh->b_page; + bio->bi_io_vec[0].bv_len = bh->b_size; + bio->bi_io_vec[0].bv_offset = bh_offset(bh); + + bio->bi_vcnt = 1; + bio->bi_idx = 0; + bio->bi_size = bh->b_size; + + bio->bi_end_io = end_bio_bh_io_sync; + bio->bi_private = bh; + + return submit_bio(rw, bio); +} + +/** + * ll_rw_block: low-level access to block devices (DEPRECATED) + * @rw: whether to %READ or %WRITE or maybe %READA (readahead) + * @nr: number of &struct buffer_heads in the array + * @bhs: array of pointers to &struct buffer_head + * + * ll_rw_block() takes an array of pointers to &struct buffer_heads, + * and requests an I/O operation on them, either a %READ or a %WRITE. + * The third %READA option is described in the documentation for + * generic_make_request() which ll_rw_block() calls. + * + * This function drops any buffer that it cannot get a lock on (with the + * BH_Lock state bit), any buffer that appears to be clean when doing a + * write request, and any buffer that appears to be up-to-date when doing + * read request. Further it marks as clean buffers that are processed for + * writing (the buffer cache wont assume that they are actually clean until + * the buffer gets unlocked). + * + * ll_rw_block sets b_end_io to simple completion handler that marks + * the buffer up-to-date (if approriate), unlocks the buffer and wakes + * any waiters. + * + * All of the buffers must be for the same device, and must also be a + * multiple of the current approved size for the device. + */ +void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) +{ + unsigned int major; + int correct_size; + int i; + + if (!nr) + return; + + major = major(to_kdev_t(bhs[0]->b_bdev->bd_dev)); + + /* Determine correct block size for this device. */ + correct_size = bdev_hardsect_size(bhs[0]->b_bdev); + + /* Verify requested block sizes. */ + for (i = 0; i < nr; i++) { + struct buffer_head *bh = bhs[i]; + if (bh->b_size & (correct_size - 1)) { + printk(KERN_NOTICE "ll_rw_block: device %s: " + "only %d-char blocks implemented (%u)\n", + bdevname(bhs[0]->b_bdev), + correct_size, bh->b_size); + goto sorry; + } + } + + if ((rw & WRITE) && bdev_read_only(bhs[0]->b_bdev)) { + printk(KERN_NOTICE "Can't write to read-only device %s\n", + bdevname(bhs[0]->b_bdev)); + goto sorry; + } + + for (i = 0; i < nr; i++) { + struct buffer_head *bh = bhs[i]; + + /* Only one thread can actually submit the I/O. */ + if (test_set_buffer_locked(bh)) + continue; + + /* We have the buffer lock */ + atomic_inc(&bh->b_count); + bh->b_end_io = end_buffer_io_sync; + + switch(rw) { + case WRITE: + if (!test_clear_buffer_dirty(bh)) + /* Hmmph! Nothing to write */ + goto end_io; + break; + + case READA: + case READ: + if (buffer_uptodate(bh)) + /* Hmmph! Already have it */ + goto end_io; + break; + default: + BUG(); + end_io: + bh->b_end_io(bh, buffer_uptodate(bh)); + continue; + } + + submit_bh(rw, bh); + } + return; + +sorry: + /* Make sure we don't get infinite dirty retries.. */ + for (i = 0; i < nr; i++) + clear_buffer_dirty(bhs[i]); } /* diff -Nru a/fs/devices.c b/fs/devices.c --- a/fs/devices.c Fri Sep 20 08:20:46 2002 +++ b/fs/devices.c Fri Sep 20 08:20:46 2002 @@ -168,7 +168,7 @@ * depending on the special file... */ static struct file_operations def_chr_fops = { - open: chrdev_open, + .open = chrdev_open, }; /* @@ -199,7 +199,7 @@ } static struct file_operations bad_sock_fops = { - open: sock_no_open + .open = sock_no_open }; void init_special_inode(struct inode *inode, umode_t mode, int rdev) diff -Nru a/fs/direct-io.c b/fs/direct-io.c --- a/fs/direct-io.c Fri Sep 20 08:20:46 2002 +++ b/fs/direct-io.c Fri Sep 20 08:20:46 2002 @@ -151,17 +151,21 @@ * During I/O bi_private points at the dio. After I/O, bi_private is used to * implement a singly-linked list of completed BIOs, at dio->bio_list. */ -static void dio_bio_end_io(struct bio *bio) +static int dio_bio_end_io(struct bio *bio, unsigned int bytes_done, int error) { struct dio *dio = bio->bi_private; unsigned long flags; + if (bio->bi_size) + return 1; + spin_lock_irqsave(&dio->bio_list_lock, flags); bio->bi_private = dio->bio_list; dio->bio_list = bio; if (dio->waiter) wake_up_process(dio->waiter); spin_unlock_irqrestore(&dio->bio_list_lock, flags); + return 0; } static int diff -Nru a/fs/dquot.c b/fs/dquot.c --- a/fs/dquot.c Fri Sep 20 08:20:47 2002 +++ b/fs/dquot.c Fri Sep 20 08:20:47 2002 @@ -1211,13 +1211,13 @@ * Definitions of diskquota operations. */ struct dquot_operations dquot_operations = { - initialize: dquot_initialize, /* mandatory */ - drop: dquot_drop, /* mandatory */ - alloc_space: dquot_alloc_space, - alloc_inode: dquot_alloc_inode, - free_space: dquot_free_space, - free_inode: dquot_free_inode, - transfer: dquot_transfer + .initialize = dquot_initialize, /* mandatory */ + .drop = dquot_drop, /* mandatory */ + .alloc_space = dquot_alloc_space, + .alloc_inode = dquot_alloc_inode, + .free_space = dquot_free_space, + .free_inode = dquot_free_inode, + .transfer = dquot_transfer }; static inline void set_enable_flags(struct quota_info *dqopt, int type) @@ -1471,13 +1471,13 @@ } struct quotactl_ops vfs_quotactl_ops = { - quota_on: vfs_quota_on, - quota_off: vfs_quota_off, - quota_sync: vfs_quota_sync, - get_info: vfs_get_dqinfo, - set_info: vfs_set_dqinfo, - get_dqblk: vfs_get_dqblk, - set_dqblk: vfs_set_dqblk + .quota_on = vfs_quota_on, + .quota_off = vfs_quota_off, + .quota_sync = vfs_quota_sync, + .get_info = vfs_get_dqinfo, + .set_info = vfs_set_dqinfo, + .get_dqblk = vfs_get_dqblk, + .set_dqblk = vfs_set_dqblk }; static ctl_table fs_dqstats_table[] = { diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c --- a/fs/driverfs/inode.c Fri Sep 20 08:20:42 2002 +++ b/fs/driverfs/inode.c Fri Sep 20 08:20:42 2002 @@ -150,7 +150,6 @@ inode = driverfs_get_inode(dir->i_sb, mode, dev); if (inode) { d_instantiate(dentry, inode); - dget(dentry); error = 0; } return error; @@ -223,48 +222,10 @@ struct inode *inode = dentry->d_inode; down(&inode->i_sem); dentry->d_inode->i_nlink--; - dput(dentry); up(&inode->i_sem); - d_delete(dentry); - return 0; -} - -static void d_unhash(struct dentry *dentry) -{ - dget(dentry); - spin_lock(&dcache_lock); - switch (atomic_read(&dentry->d_count)) { - default: - spin_unlock(&dcache_lock); - shrink_dcache_parent(dentry); - spin_lock(&dcache_lock); - if (atomic_read(&dentry->d_count) != 2) - break; - case 2: - list_del_init(&dentry->d_hash); - } - spin_unlock(&dcache_lock); -} - -static int driverfs_rmdir(struct inode *dir, struct dentry *dentry) -{ - int error = -ENOTEMPTY; - struct inode * inode = dentry->d_inode; - - down(&inode->i_sem); - d_unhash(dentry); - if (driverfs_empty(dentry)) { - dentry->d_inode->i_nlink -= 2; - dput(dentry); - inode->i_flags |= S_DEAD; - dir->i_nlink--; - error = 0; - } - up(&inode->i_sem); - if (!error) - d_delete(dentry); + d_invalidate(dentry); dput(dentry); - return error; + return 0; } /** @@ -622,9 +583,6 @@ if (!entry || !parent) return -EINVAL; - /* make sure we're mounted */ - get_mount(); - if (!parent->dentry) { put_mount(); return -EINVAL; @@ -638,8 +596,6 @@ } else error = PTR_ERR(dentry); up(&parent->dentry->d_inode->i_sem); - if (error) - put_mount(); return error; } @@ -659,8 +615,6 @@ if (!parent) return -EINVAL; - get_mount(); - if (!parent->dentry) { put_mount(); return -EINVAL; @@ -672,8 +626,6 @@ else error = PTR_ERR(dentry); up(&parent->dentry->d_inode->i_sem); - if (error) - put_mount(); return error; } @@ -699,8 +651,6 @@ if (dentry->d_inode && (dentry->d_parent->d_inode == dir->dentry->d_inode)) { driverfs_unlink(dir->dentry->d_inode,dentry); - dput(dentry); - put_mount(); } } up(&dir->dentry->d_inode->i_sem); @@ -711,33 +661,39 @@ * @dir: directory to remove * * To make sure we don't orphan anyone, first remove - * all the children in the list, then do vfs_rmdir() to remove it - * and decrement the refcount.. + * all the children in the list, then do clean up the directory. */ void driverfs_remove_dir(struct driver_dir_entry * dir) { - struct list_head * node; + struct list_head * node, * next; struct dentry * dentry = dir->dentry; + struct dentry * parent; if (!dentry) goto done; - down(&dentry->d_parent->d_inode->i_sem); + parent = dget(dentry->d_parent); + down(&parent->d_inode->i_sem); down(&dentry->d_inode->i_sem); - node = dentry->d_subdirs.next; - while (node != &dentry->d_subdirs) { + list_for_each_safe(node,next,&dentry->d_subdirs) { struct dentry * d = list_entry(node,struct dentry,d_child); + /* make sure dentry is still there */ + if (d->d_inode) + driverfs_unlink(dentry->d_inode,d); + } - node = node->next; - driverfs_unlink(dentry->d_inode,d); - dput(d); - put_mount(); + d_invalidate(dentry); + if (driverfs_empty(dentry)) { + dentry->d_inode->i_nlink -= 2; + dentry->d_inode->i_flags |= S_DEAD; + parent->d_inode->i_nlink--; } up(&dentry->d_inode->i_sem); - driverfs_rmdir(dentry->d_parent->d_inode,dentry); - up(&dentry->d_parent->d_inode->i_sem); dput(dentry); + + up(&parent->d_inode->i_sem); + dput(parent); done: put_mount(); } diff -Nru a/fs/exec.c b/fs/exec.c --- a/fs/exec.c Fri Sep 20 08:20:44 2002 +++ b/fs/exec.c Fri Sep 20 08:20:44 2002 @@ -609,8 +609,6 @@ ptrace_unlink(leader); ptrace_unlink(current); - unhash_pid(current); - unhash_pid(leader); remove_parent(current); remove_parent(leader); /* @@ -631,8 +629,6 @@ current->ptrace = ptrace; __ptrace_link(current, parent); } - hash_pid(current); - hash_pid(leader); list_add_tail(¤t->tasks, &init_task.tasks); state = leader->state; diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c --- a/fs/ext2/inode.c Fri Sep 20 08:20:41 2002 +++ b/fs/ext2/inode.c Fri Sep 20 08:20:41 2002 @@ -627,13 +627,13 @@ } static int -ext2_writepages(struct address_space *mapping, int *nr_to_write) +ext2_writepages(struct address_space *mapping, struct writeback_control *wbc) { int ret; int err; ret = write_mapping_buffers(mapping); - err = mpage_writepages(mapping, nr_to_write, ext2_get_block); + err = mpage_writepages(mapping, wbc, ext2_get_block); if (!ret) ret = err; return ret; diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c --- a/fs/ext3/inode.c Fri Sep 20 08:20:47 2002 +++ b/fs/ext3/inode.c Fri Sep 20 08:20:47 2002 @@ -1475,13 +1475,13 @@ /* For writeback mode, we can use mpage_writepages() */ static int -ext3_writepages(struct address_space *mapping, int *nr_to_write) +ext3_writepages(struct address_space *mapping, struct writeback_control *wbc) { int ret; int err; ret = write_mapping_buffers(mapping); - err = mpage_writepages(mapping, nr_to_write, ext3_get_block); + err = mpage_writepages(mapping, wbc, ext3_get_block); if (!ret) ret = err; return ret; diff -Nru a/fs/fcntl.c b/fs/fcntl.c --- a/fs/fcntl.c Fri Sep 20 08:20:41 2002 +++ b/fs/fcntl.c Fri Sep 20 08:20:41 2002 @@ -480,7 +480,9 @@ void send_sigio(struct fown_struct *fown, int fd, int band) { - struct task_struct * p; + struct task_struct *p; + struct list_head *l; + struct pid *pidptr; int pid; read_lock(&fown->lock); @@ -493,14 +495,8 @@ send_sigio_to_task(p, fown, fd, band); goto out_unlock_task; } - for_each_process(p) { - int match = p->pid; - if (pid < 0) - match = -p->pgrp; - if (pid != match) - continue; - send_sigio_to_task(p, fown, fd, band); - } + for_each_task_pid(-pid, PIDTYPE_PGID, p, l, pidptr) + send_sigio_to_task(p, fown,fd,band); out_unlock_task: read_unlock(&tasklist_lock); out_unlock_fown: diff -Nru a/fs/fifo.c b/fs/fifo.c --- a/fs/fifo.c Fri Sep 20 08:20:44 2002 +++ b/fs/fifo.c Fri Sep 20 08:20:44 2002 @@ -154,5 +154,5 @@ * depending on the access mode of the file... */ struct file_operations def_fifo_fops = { - open: fifo_open, /* will set read or write pipe_fops */ + .open = fifo_open, /* will set read or write pipe_fops */ }; diff -Nru a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c --- a/fs/freevxfs/vxfs_super.c Fri Sep 20 08:20:47 2002 +++ b/fs/freevxfs/vxfs_super.c Fri Sep 20 08:20:47 2002 @@ -235,11 +235,11 @@ } static struct file_system_type vxfs_fs_type = { - owner: THIS_MODULE, - name: "vxfs", - get_sb: vxfs_get_sb, - kill_sb: kill_block_super, - fs_flags: FS_REQUIRES_DEV, + .owner = THIS_MODULE, + .name = "vxfs", + .get_sb = vxfs_get_sb, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, }; static int __init diff -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c --- a/fs/fs-writeback.c Fri Sep 20 08:20:46 2002 +++ b/fs/fs-writeback.c Fri Sep 20 08:20:46 2002 @@ -111,8 +111,7 @@ /* * Write a single inode's dirty pages and inode data out to disk. * If `sync' is set, wait on the writeout. - * If `nr_to_write' is not NULL, subtract the number of written pages - * from *nr_to_write. + * Subtract the number of written pages from nr_to_write. * * Normally it is not legal for a single process to lock more than one * page at a time, due to ab/ba deadlock problems. But writepages() @@ -127,7 +126,9 @@ * * Called under inode_lock. */ -static void __sync_single_inode(struct inode *inode, int wait, int *nr_to_write) +static void +__sync_single_inode(struct inode *inode, int wait, + struct writeback_control *wbc) { unsigned dirty; unsigned long orig_dirtied_when; @@ -144,7 +145,7 @@ mapping->dirtied_when = 0; /* assume it's whole-file writeback */ spin_unlock(&inode_lock); - do_writepages(mapping, nr_to_write); + do_writepages(mapping, wbc); /* Don't write the inode if only I_DIRTY_PAGES was set */ if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) @@ -181,7 +182,8 @@ * Write out an inode's dirty pages. Called under inode_lock. */ static void -__writeback_single_inode(struct inode *inode, int sync, int *nr_to_write) +__writeback_single_inode(struct inode *inode, int sync, + struct writeback_control *wbc) { if (current_is_pdflush() && (inode->i_state & I_LOCK)) return; @@ -193,7 +195,7 @@ iput(inode); spin_lock(&inode_lock); } - __sync_single_inode(inode, sync, nr_to_write); + __sync_single_inode(inode, sync, wbc); } /* @@ -226,8 +228,7 @@ * thrlttled threads: we don't want them all piling up on __wait_on_inode. */ static void -sync_sb_inodes(struct backing_dev_info *single_bdi, struct super_block *sb, - int sync_mode, int *nr_to_write, unsigned long *older_than_this) +sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) { struct list_head *tmp; struct list_head *head; @@ -241,7 +242,7 @@ struct backing_dev_info *bdi; int really_sync; - if (single_bdi && mapping->backing_dev_info != single_bdi) { + if (wbc->bdi && mapping->backing_dev_info != wbc->bdi) { if (sb != blockdev_superblock) break; /* inappropriate superblock */ list_move(&inode->i_list, &sb->s_dirty); @@ -252,23 +253,20 @@ if (time_after(mapping->dirtied_when, start)) break; - if (older_than_this && - time_after(mapping->dirtied_when, *older_than_this)) + if (wbc->older_than_this && time_after(mapping->dirtied_when, + *wbc->older_than_this)) goto out; bdi = mapping->backing_dev_info; if (current_is_pdflush() && !writeback_acquire(bdi)) break; - really_sync = (sync_mode == WB_SYNC_ALL); - if ((sync_mode == WB_SYNC_LAST) && (head->prev == head)) - really_sync = 1; - + really_sync = (wbc->sync_mode == WB_SYNC_ALL); BUG_ON(inode->i_state & I_FREEING); __iget(inode); list_move(&inode->i_list, &sb->s_dirty); - __writeback_single_inode(inode, really_sync, nr_to_write); - if (sync_mode == WB_SYNC_HOLD) { + __writeback_single_inode(inode, really_sync, wbc); + if (wbc->sync_mode == WB_SYNC_HOLD) { mapping->dirtied_when = jiffies; list_move(&inode->i_list, &sb->s_dirty); } @@ -277,7 +275,7 @@ spin_unlock(&inode_lock); iput(inode); spin_lock(&inode_lock); - if (nr_to_write && *nr_to_write <= 0) + if (wbc->nr_to_write <= 0) break; } out: @@ -288,16 +286,26 @@ } /* + * Start writeback of dirty pagecache data against all unlocked inodes. + * + * Note: + * We don't need to grab a reference to superblock here. If it has non-empty + * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed + * past sync_inodes_sb() until both the ->s_dirty and ->s_io lists are + * empty. Since __sync_single_inode() regains inode_lock before it finally moves + * inode from superblock lists we are OK. + * + * If `older_than_this' is non-zero then only flush inodes which have a + * flushtime older than *older_than_this. + * * If `bdi' is non-zero then we will scan the first inode against each * superblock until we find the matching ones. One group will be the dirty * inodes against a filesystem. Then when we hit the dummy blockdev superblock, * sync_sb_inodes will seekout the blockdev which matches `bdi'. Maybe not * super-efficient but we're about to do a ton of I/O... */ -static void -__writeback_unlocked_inodes(struct backing_dev_info *bdi, int *nr_to_write, - enum writeback_sync_modes sync_mode, - unsigned long *older_than_this) +void +writeback_inodes(struct writeback_control *wbc) { struct super_block *sb; @@ -307,11 +315,10 @@ for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) { if (!list_empty(&sb->s_dirty) || !list_empty(&sb->s_io)) { spin_unlock(&sb_lock); - sync_sb_inodes(bdi, sb, sync_mode, nr_to_write, - older_than_this); + sync_sb_inodes(sb, wbc); spin_lock(&sb_lock); } - if (nr_to_write && *nr_to_write <= 0) + if (wbc->nr_to_write <= 0) break; } spin_unlock(&sb_lock); @@ -319,43 +326,6 @@ } /* - * Start writeback of dirty pagecache data against all unlocked inodes. - * - * Note: - * We don't need to grab a reference to superblock here. If it has non-empty - * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed - * past sync_inodes_sb() until both the ->s_dirty and ->s_io lists are - * empty. Since __sync_single_inode() regains inode_lock before it finally moves - * inode from superblock lists we are OK. - * - * If `older_than_this' is non-zero then only flush inodes which have a - * flushtime older than *older_than_this. - * - * This is a "memory cleansing" operation, not a "data integrity" operation. - */ -void writeback_unlocked_inodes(int *nr_to_write, - enum writeback_sync_modes sync_mode, - unsigned long *older_than_this) -{ - __writeback_unlocked_inodes(NULL, nr_to_write, - sync_mode, older_than_this); -} -/* - * Perform writeback of dirty data against a particular queue. - * - * This is for writer throttling. We don't want processes to write back - * other process's data, espsecially when the other data belongs to a - * different spindle. - */ -void writeback_backing_dev(struct backing_dev_info *bdi, int *nr_to_write, - enum writeback_sync_modes sync_mode, - unsigned long *older_than_this) -{ - __writeback_unlocked_inodes(bdi, nr_to_write, - sync_mode, older_than_this); -} - -/* * writeback and wait upon the filesystem's dirty inodes. The caller will * do this in two passes - one to write, and one to wait. WB_SYNC_HOLD is * used to park the written inodes on sb->s_dirty for the wait pass. @@ -366,14 +336,17 @@ void sync_inodes_sb(struct super_block *sb, int wait) { struct page_state ps; - int nr_to_write; + struct writeback_control wbc = { + .bdi = NULL, + .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_HOLD, + .older_than_this = NULL, + .nr_to_write = 0, + }; get_page_state(&ps); - nr_to_write = ps.nr_dirty + ps.nr_dirty / 4; - + wbc.nr_to_write = ps.nr_dirty + ps.nr_dirty / 4; spin_lock(&inode_lock); - sync_sb_inodes(NULL, sb, wait ? WB_SYNC_ALL : WB_SYNC_HOLD, - &nr_to_write, NULL); + sync_sb_inodes(sb, &wbc); spin_unlock(&inode_lock); } @@ -466,8 +439,12 @@ void write_inode_now(struct inode *inode, int sync) { + struct writeback_control wbc = { + .nr_to_write = LONG_MAX, + }; + spin_lock(&inode_lock); - __writeback_single_inode(inode, sync, NULL); + __writeback_single_inode(inode, sync, &wbc); spin_unlock(&inode_lock); if (sync) wait_on_inode(inode); diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c --- a/fs/jfs/inode.c Fri Sep 20 08:20:41 2002 +++ b/fs/jfs/inode.c Fri Sep 20 08:20:41 2002 @@ -282,9 +282,10 @@ return block_write_full_page(page, jfs_get_block); } -static int jfs_writepages(struct address_space *mapping, int *nr_to_write) +static int jfs_writepages(struct address_space *mapping, + struct writeback_control *wbc) { - return mpage_writepages(mapping, nr_to_write, jfs_get_block); + return mpage_writepages(mapping, wbc, jfs_get_block); } static int jfs_readpage(struct file *file, struct page *page) diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c --- a/fs/jfs/jfs_logmgr.c Fri Sep 20 08:20:46 2002 +++ b/fs/jfs/jfs_logmgr.c Fri Sep 20 08:20:46 2002 @@ -1969,13 +1969,16 @@ * * executed at INTIODONE level */ -static void lbmIODone(struct bio *bio) +static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error) { struct lbuf *bp = bio->bi_private; struct lbuf *nextbp, *tail; struct jfs_log *log; unsigned long flags; + if (bio->bi_size) + return 1; + /* * get back jfs buffer bound to the i/o buffer */ @@ -2004,7 +2007,7 @@ /* wakeup I/O initiator */ LCACHE_WAKEUP(&bp->l_ioevent); - return; + return 0; } /* @@ -2029,7 +2032,7 @@ if (bp->l_flag & lbmDIRECT) { LCACHE_WAKEUP(&bp->l_ioevent); LCACHE_UNLOCK(flags); - return; + return 0; } tail = log->wqueue; @@ -2108,6 +2111,8 @@ LCACHE_UNLOCK(flags); /* unlock+enable */ } + + return 0; } int jfsIOWait(void *arg) diff -Nru a/fs/libfs.c b/fs/libfs.c --- a/fs/libfs.c Fri Sep 20 08:20:41 2002 +++ b/fs/libfs.c Fri Sep 20 08:20:41 2002 @@ -32,7 +32,7 @@ int dcache_dir_open(struct inode *inode, struct file *file) { - static struct qstr cursor_name = {len:1, name:"."}; + static struct qstr cursor_name = {.len = 1, .name = "."}; file->private_data = d_alloc(file->f_dentry, &cursor_name); @@ -151,15 +151,15 @@ } struct file_operations simple_dir_operations = { - open: dcache_dir_open, - release: dcache_dir_close, - llseek: dcache_dir_lseek, - read: generic_read_dir, - readdir: dcache_readdir, + .open = dcache_dir_open, + .release = dcache_dir_close, + .llseek = dcache_dir_lseek, + .read = generic_read_dir, + .readdir = dcache_readdir, }; struct inode_operations simple_dir_inode_operations = { - lookup: simple_lookup, + .lookup = simple_lookup, }; /* @@ -171,10 +171,10 @@ struct super_operations *ops, unsigned long magic) { struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); - static struct super_operations default_ops = {statfs: simple_statfs}; + static struct super_operations default_ops = {.statfs = simple_statfs}; struct dentry *dentry; struct inode *root; - struct qstr d_name = {name:name, len:strlen(name)}; + struct qstr d_name = {.name = name, .len = strlen(name)}; if (IS_ERR(s)) return s; diff -Nru a/fs/mpage.c b/fs/mpage.c --- a/fs/mpage.c Fri Sep 20 08:20:43 2002 +++ b/fs/mpage.c Fri Sep 20 08:20:43 2002 @@ -8,6 +8,8 @@ * * 15May2002 akpm@zip.com.au * Initial version + * 27Jun2002 axboe@suse.de + * use bio_add_page() to build bio's just the right size */ #include @@ -23,12 +25,6 @@ #include /* - * The largest-sized BIO which this code will assemble, in bytes. Set this - * to PAGE_CACHE_SIZE if your drivers are broken. - */ -#define MPAGE_BIO_MAX_SIZE BIO_MAX_SIZE - -/* * I/O completion handler for multipage BIOs. * * The mpage code never puts partial pages into a BIO (except for end-of-file). @@ -40,11 +36,14 @@ * status of that page is hard. See end_buffer_async_read() for the details. * There is no point in duplicating all that complexity. */ -static void mpage_end_io_read(struct bio *bio) +static int mpage_end_io_read(struct bio *bio, unsigned int bytes_done, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + if (bio->bi_size) + return 1; + do { struct page *page = bvec->bv_page; @@ -60,13 +59,17 @@ unlock_page(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); + return 0; } -static void mpage_end_io_write(struct bio *bio) +static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + if (bio->bi_size) + return 1; + do { struct page *page = bvec->bv_page; @@ -78,12 +81,11 @@ end_page_writeback(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); + return 0; } struct bio *mpage_bio_submit(int rw, struct bio *bio) { - bio->bi_vcnt = bio->bi_idx; - bio->bi_idx = 0; bio->bi_end_io = mpage_end_io_read; if (rw == WRITE) bio->bi_end_io = mpage_end_io_write; @@ -106,11 +108,7 @@ if (bio) { bio->bi_bdev = bdev; - bio->bi_vcnt = nr_vecs; - bio->bi_idx = 0; - bio->bi_size = 0; bio->bi_sector = first_sector; - bio->bi_io_vec[0].bv_page = NULL; } return bio; } @@ -169,7 +167,6 @@ const unsigned blkbits = inode->i_blkbits; const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits; const unsigned blocksize = 1 << blkbits; - struct bio_vec *bvec; sector_t block_in_file; sector_t last_block; sector_t blocks[MAX_BUF_PER_PAGE]; @@ -223,26 +220,22 @@ /* * This page will go to BIO. Do we need to send this BIO off first? */ - if (bio && (bio->bi_idx == bio->bi_vcnt || - *last_block_in_bio != blocks[0] - 1)) + if (bio && (*last_block_in_bio != blocks[0] - 1)) bio = mpage_bio_submit(READ, bio); +alloc_new: if (bio == NULL) { - unsigned nr_bvecs = MPAGE_BIO_MAX_SIZE / PAGE_CACHE_SIZE; - - if (nr_bvecs > nr_pages) - nr_bvecs = nr_pages; bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9), - nr_bvecs, GFP_KERNEL); + nr_pages, GFP_KERNEL); if (bio == NULL) goto confused; } - bvec = &bio->bi_io_vec[bio->bi_idx++]; - bvec->bv_page = page; - bvec->bv_len = (first_hole << blkbits); - bvec->bv_offset = 0; - bio->bi_size += bvec->bv_len; + if (bio_add_page(bio, page, first_hole << blkbits, 0)) { + bio = mpage_bio_submit(READ, bio); + goto alloc_new; + } + if (buffer_boundary(&bh) || (first_hole != blocks_per_page)) bio = mpage_bio_submit(READ, bio); else @@ -330,7 +323,6 @@ const unsigned blkbits = inode->i_blkbits; unsigned long end_index; const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits; - struct bio_vec *bvec; sector_t last_block; sector_t block_in_file; sector_t blocks[MAX_BUF_PER_PAGE]; @@ -432,15 +424,15 @@ /* * This page will go to BIO. Do we need to send this BIO off first? */ - if (bio && (bio->bi_idx == bio->bi_vcnt || - *last_block_in_bio != blocks[0] - 1)) + if (bio && *last_block_in_bio != blocks[0] - 1) bio = mpage_bio_submit(WRITE, bio); +alloc_new: if (bio == NULL) { - unsigned nr_bvecs = MPAGE_BIO_MAX_SIZE / PAGE_CACHE_SIZE; + const unsigned __nr_pages = 64; /* FIXME */ bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9), - nr_bvecs, GFP_NOFS|__GFP_HIGH); + __nr_pages, GFP_NOFS|__GFP_HIGH); if (bio == NULL) goto confused; } @@ -465,11 +457,11 @@ try_to_free_buffers(page); } - bvec = &bio->bi_io_vec[bio->bi_idx++]; - bvec->bv_page = page; - bvec->bv_len = (first_unmapped << blkbits); - bvec->bv_offset = 0; - bio->bi_size += bvec->bv_len; + if (bio_add_page(bio, page, first_unmapped << blkbits, 0)) { + bio = mpage_bio_submit(WRITE, bio); + goto alloc_new; + } + BUG_ON(PageWriteback(page)); SetPageWriteback(page); unlock_page(page); @@ -492,7 +484,7 @@ * address space and writepage() all of them. * * @mapping: address space structure to write - * @nr_to_write: subtract the number of written pages from *@nr_to_write + * @wbc: subtract the number of written pages from *@wbc->nr_to_write * @get_block: the filesystem's block mapper function. * If this is NULL then use a_ops->writepage. Otherwise, go * direct-to-BIO. @@ -528,7 +520,7 @@ */ int mpage_writepages(struct address_space *mapping, - int *nr_to_write, get_block_t get_block) + struct writeback_control *wbc, get_block_t get_block) { struct bio *bio = NULL; sector_t last_block_in_bio = 0; @@ -591,7 +583,7 @@ __set_page_dirty_nobuffers(page); ret = 0; } - if (ret || (nr_to_write && --(*nr_to_write) <= 0)) + if (ret || (--(wbc->nr_to_write) <= 0)) done = 1; } else { unlock_page(page); diff -Nru a/fs/namei.c b/fs/namei.c --- a/fs/namei.c Fri Sep 20 08:20:44 2002 +++ b/fs/namei.c Fri Sep 20 08:20:44 2002 @@ -2230,6 +2230,6 @@ } struct inode_operations page_symlink_inode_operations = { - readlink: page_readlink, - follow_link: page_follow_link, + .readlink = page_readlink, + .follow_link = page_follow_link, }; diff -Nru a/fs/namespace.c b/fs/namespace.c --- a/fs/namespace.c Fri Sep 20 08:20:47 2002 +++ b/fs/namespace.c Fri Sep 20 08:20:47 2002 @@ -239,10 +239,10 @@ } struct seq_operations mounts_op = { - start: m_start, - next: m_next, - stop: m_stop, - show: show_vfsmnt + .start = m_start, + .next = m_next, + .stop = m_stop, + .show = show_vfsmnt }; /* diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c --- a/fs/nfs/inode.c Fri Sep 20 08:20:47 2002 +++ b/fs/nfs/inode.c Fri Sep 20 08:20:47 2002 @@ -245,7 +245,7 @@ struct rpc_xprt *xprt = NULL; struct rpc_clnt *clnt = NULL; struct inode *root_inode = NULL; - unsigned int authflavor; + rpc_authflavor_t authflavor; struct rpc_timeout timeparms; struct nfs_fsinfo fsinfo; int tcp, version, maxlen; diff -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c --- a/fs/nfs/nfs2xdr.c Fri Sep 20 08:20:44 2002 +++ b/fs/nfs/nfs2xdr.c Fri Sep 20 08:20:44 2002 @@ -251,7 +251,7 @@ hdrlen = (u8 *) p - (u8 *) iov->iov_base; if (iov->iov_len < hdrlen) { printk(KERN_WARNING "NFS: READ reply header overflowed:" - "length %d > %d\n", hdrlen, iov->iov_len); + "length %d > %Zu\n", hdrlen, iov->iov_len); return -errno_NFSERR_IO; } else if (iov->iov_len != hdrlen) { dprintk("NFS: READ header is short. iovec will be shifted.\n"); @@ -404,7 +404,7 @@ hdrlen = (u8 *) p - (u8 *) iov->iov_base; if (iov->iov_len < hdrlen) { printk(KERN_WARNING "NFS: READDIR reply header overflowed:" - "length %d > %d\n", hdrlen, iov->iov_len); + "length %d > %Zu\n", hdrlen, iov->iov_len); return -errno_NFSERR_IO; } else if (iov->iov_len != hdrlen) { dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); diff -Nru a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c --- a/fs/nfs/nfs3xdr.c Fri Sep 20 08:20:48 2002 +++ b/fs/nfs/nfs3xdr.c Fri Sep 20 08:20:48 2002 @@ -525,7 +525,7 @@ hdrlen = (u8 *) p - (u8 *) iov->iov_base; if (iov->iov_len < hdrlen) { printk(KERN_WARNING "NFS: READDIR reply header overflowed:" - "length %d > %d\n", hdrlen, iov->iov_len); + "length %d > %Zu\n", hdrlen, iov->iov_len); return -errno_NFSERR_IO; } else if (iov->iov_len != hdrlen) { dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); @@ -808,7 +808,7 @@ hdrlen = (u8 *) p - (u8 *) iov->iov_base; if (iov->iov_len < hdrlen) { printk(KERN_WARNING "NFS: READ reply header overflowed:" - "length %d > %d\n", hdrlen, iov->iov_len); + "length %d > %Zu\n", hdrlen, iov->iov_len); return -errno_NFSERR_IO; } else if (iov->iov_len != hdrlen) { dprintk("NFS: READ header is short. iovec will be shifted.\n"); diff -Nru a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c --- a/fs/nfsd/nfscache.c Fri Sep 20 08:20:48 2002 +++ b/fs/nfsd/nfscache.c Fri Sep 20 08:20:48 2002 @@ -272,7 +272,7 @@ case RC_NOCACHE: break; case RC_REPLSTAT: - svc_putlong(&rqstp->rq_resbuf, rp->c_replstat); + svc_putu32(&rqstp->rq_resbuf, rp->c_replstat); rtn = RC_REPLY; break; case RC_REPLBUFF: diff -Nru a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c --- a/fs/nfsd/nfssvc.c Fri Sep 20 08:20:41 2002 +++ b/fs/nfsd/nfssvc.c Fri Sep 20 08:20:41 2002 @@ -302,7 +302,7 @@ } if (rqstp->rq_proc != 0) - svc_putlong(&rqstp->rq_resbuf, nfserr); + svc_putu32(&rqstp->rq_resbuf, nfserr); /* Encode result. * For NFSv2, additional info is never returned in case of an error. diff -Nru a/fs/pipe.c b/fs/pipe.c --- a/fs/pipe.c Fri Sep 20 08:20:41 2002 +++ b/fs/pipe.c Fri Sep 20 08:20:41 2002 @@ -444,69 +444,69 @@ * are also used in linux/fs/fifo.c to do operations on FIFOs. */ struct file_operations read_fifo_fops = { - llseek: no_llseek, - read: pipe_read, - write: bad_pipe_w, - poll: fifo_poll, - ioctl: pipe_ioctl, - open: pipe_read_open, - release: pipe_read_release, - fasync: pipe_read_fasync, + .llseek = no_llseek, + .read = pipe_read, + .write = bad_pipe_w, + .poll = fifo_poll, + .ioctl = pipe_ioctl, + .open = pipe_read_open, + .release = pipe_read_release, + .fasync = pipe_read_fasync, }; struct file_operations write_fifo_fops = { - llseek: no_llseek, - read: bad_pipe_r, - write: pipe_write, - poll: fifo_poll, - ioctl: pipe_ioctl, - open: pipe_write_open, - release: pipe_write_release, - fasync: pipe_write_fasync, + .llseek = no_llseek, + .read = bad_pipe_r, + .write = pipe_write, + .poll = fifo_poll, + .ioctl = pipe_ioctl, + .open = pipe_write_open, + .release = pipe_write_release, + .fasync = pipe_write_fasync, }; struct file_operations rdwr_fifo_fops = { - llseek: no_llseek, - read: pipe_read, - write: pipe_write, - poll: fifo_poll, - ioctl: pipe_ioctl, - open: pipe_rdwr_open, - release: pipe_rdwr_release, - fasync: pipe_rdwr_fasync, + .llseek = no_llseek, + .read = pipe_read, + .write = pipe_write, + .poll = fifo_poll, + .ioctl = pipe_ioctl, + .open = pipe_rdwr_open, + .release = pipe_rdwr_release, + .fasync = pipe_rdwr_fasync, }; struct file_operations read_pipe_fops = { - llseek: no_llseek, - read: pipe_read, - write: bad_pipe_w, - poll: pipe_poll, - ioctl: pipe_ioctl, - open: pipe_read_open, - release: pipe_read_release, - fasync: pipe_read_fasync, + .llseek = no_llseek, + .read = pipe_read, + .write = bad_pipe_w, + .poll = pipe_poll, + .ioctl = pipe_ioctl, + .open = pipe_read_open, + .release = pipe_read_release, + .fasync = pipe_read_fasync, }; struct file_operations write_pipe_fops = { - llseek: no_llseek, - read: bad_pipe_r, - write: pipe_write, - poll: pipe_poll, - ioctl: pipe_ioctl, - open: pipe_write_open, - release: pipe_write_release, - fasync: pipe_write_fasync, + .llseek = no_llseek, + .read = bad_pipe_r, + .write = pipe_write, + .poll = pipe_poll, + .ioctl = pipe_ioctl, + .open = pipe_write_open, + .release = pipe_write_release, + .fasync = pipe_write_fasync, }; struct file_operations rdwr_pipe_fops = { - llseek: no_llseek, - read: pipe_read, - write: pipe_write, - poll: pipe_poll, - ioctl: pipe_ioctl, - open: pipe_rdwr_open, - release: pipe_rdwr_release, - fasync: pipe_rdwr_fasync, + .llseek = no_llseek, + .read = pipe_read, + .write = pipe_write, + .poll = pipe_poll, + .ioctl = pipe_ioctl, + .open = pipe_rdwr_open, + .release = pipe_rdwr_release, + .fasync = pipe_rdwr_fasync, }; struct inode* pipe_new(struct inode* inode) @@ -541,7 +541,7 @@ return 1; } static struct dentry_operations pipefs_dentry_operations = { - d_delete: pipefs_delete_dentry, + .d_delete = pipefs_delete_dentry, }; static struct inode * get_pipe_inode(void) @@ -672,9 +672,9 @@ } static struct file_system_type pipe_fs_type = { - name: "pipefs", - get_sb: pipefs_get_sb, - kill_sb: kill_anon_super, + .name = "pipefs", + .get_sb = pipefs_get_sb, + .kill_sb = kill_anon_super, }; static int __init init_pipe_fs(void) diff -Nru a/fs/proc/array.c b/fs/proc/array.c --- a/fs/proc/array.c Fri Sep 20 08:20:47 2002 +++ b/fs/proc/array.c Fri Sep 20 08:20:47 2002 @@ -394,131 +394,40 @@ return res; } -static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size, int * pages, int * shared, int * dirty, int * total) +int proc_pid_statm(task_t *task, char *buffer) { - unsigned long end, pmd_end; - pte_t *pte; - - if (pmd_none(*pmd)) - return; - if (pmd_bad(*pmd)) { - pmd_ERROR(*pmd); - pmd_clear(pmd); - return; - } - preempt_disable(); - pte = pte_offset_map(pmd, address); - end = address + size; - pmd_end = (address + PMD_SIZE) & PMD_MASK; - if (end > pmd_end) - end = pmd_end; - do { - pte_t page = *pte; - struct page *ptpage; - unsigned long pfn; - - address += PAGE_SIZE; - pte++; - if (pte_none(page)) - continue; - ++*total; - if (!pte_present(page)) - continue; - pfn = pte_pfn(page); - if (!pfn_valid(pfn)) - continue; - ptpage = pfn_to_page(pfn); - if (PageReserved(ptpage)) - continue; - ++*pages; - if (pte_dirty(page)) - ++*dirty; - if (page_count(pte_page(page)) > 1) - ++*shared; - } while (address < end); - pte_unmap(pte - 1); - preempt_enable(); -} - -static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size, - int * pages, int * shared, int * dirty, int * total) -{ - pmd_t * pmd; - unsigned long end; - - if (pgd_none(*pgd)) - return; - if (pgd_bad(*pgd)) { - pgd_ERROR(*pgd); - pgd_clear(pgd); - return; - } - pmd = pmd_offset(pgd, address); - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - do { - statm_pte_range(pmd, address, end - address, pages, shared, dirty, total); - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address < end); -} - -static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end, - int * pages, int * shared, int * dirty, int * total) -{ - while (address < end) { - statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total); - address = (address + PGDIR_SIZE) & PGDIR_MASK; - pgd++; - } -} - -int proc_pid_statm(struct task_struct *task, char * buffer) -{ - int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + int size, resident, shared, text, lib, data, dirty; struct mm_struct *mm = get_task_mm(task); + struct vm_area_struct * vma; - if (mm) { - struct vm_area_struct * vma; - down_read(&mm->mmap_sem); - vma = mm->mmap; - while (vma) { - pgd_t *pgd = pgd_offset(mm, vma->vm_start); - int pages = 0, shared = 0, dirty = 0, total = 0; - if (is_vm_hugetlb_page(vma)) { - int num_pages = ((vma->vm_end - vma->vm_start)/PAGE_SIZE); + size = resident = shared = text = lib = data = dirty = 0; - resident += num_pages; - if (!(vma->vm_flags & VM_DONTCOPY)) - share += num_pages; - if (vma->vm_flags & VM_WRITE) - dt += num_pages; - drs += num_pages; - vma = vma->vm_next; - continue; - } - statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total); - resident += pages; - share += shared; - dt += dirty; - size += total; - if (vma->vm_flags & VM_EXECUTABLE) - trs += pages; /* text */ - else if (vma->vm_flags & VM_GROWSDOWN) - drs += pages; /* stack */ - else if (vma->vm_end > 0x60000000) - lrs += pages; /* library */ - else - drs += pages; - vma = vma->vm_next; + if (!mm) + goto out; + + down_read(&mm->mmap_sem); + resident = mm->rss; + for (vma = mm->mmap; vma; vma = vma->vm_next) { + int pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + + size += pages; + if (is_vm_hugetlb_page(vma)) { + if (!(vma->vm_flags & VM_DONTCOPY)) + shared += pages; + continue; } - up_read(&mm->mmap_sem); - mmput(mm); + if (vma->vm_flags & VM_SHARED || !list_empty(&vma->shared)) + shared += pages; + if (vma->vm_flags & VM_EXECUTABLE) + text += pages; + else + data += pages; } + up_read(&mm->mmap_sem); + mmput(mm); +out: return sprintf(buffer,"%d %d %d %d %d %d %d\n", - size, resident, share, trs, lrs, drs, dt); + size, resident, shared, text, lib, data, dirty); } /* diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c --- a/fs/proc/proc_misc.c Fri Sep 20 08:20:42 2002 +++ b/fs/proc/proc_misc.c Fri Sep 20 08:20:42 2002 @@ -171,6 +171,7 @@ "Dirty: %8lu kB\n" "Writeback: %8lu kB\n" "Mapped: %8lu kB\n" + "Slab: %8lu kB\n" "Committed_AS: %8u kB\n" "PageTables: %8lu kB\n" "ReverseMaps: %8lu\n", @@ -191,6 +192,7 @@ K(ps.nr_dirty), K(ps.nr_writeback), K(ps.nr_mapped), + K(ps.nr_slab), K(committed), K(ps.nr_page_table_pages), ps.nr_reverse_maps diff -Nru a/fs/quota_v1.c b/fs/quota_v1.c --- a/fs/quota_v1.c Fri Sep 20 08:20:47 2002 +++ b/fs/quota_v1.c Fri Sep 20 08:20:47 2002 @@ -210,18 +210,18 @@ } static struct quota_format_ops v1_format_ops = { - check_quota_file: v1_check_quota_file, - read_file_info: v1_read_file_info, - write_file_info: v1_write_file_info, - free_file_info: NULL, - read_dqblk: v1_read_dqblk, - commit_dqblk: v1_commit_dqblk, + .check_quota_file = v1_check_quota_file, + .read_file_info = v1_read_file_info, + .write_file_info = v1_write_file_info, + .free_file_info = NULL, + .read_dqblk = v1_read_dqblk, + .commit_dqblk = v1_commit_dqblk, }; static struct quota_format_type v1_quota_format = { - qf_fmt_id: QFMT_VFS_OLD, - qf_ops: &v1_format_ops, - qf_owner: THIS_MODULE + .qf_fmt_id = QFMT_VFS_OLD, + .qf_ops = &v1_format_ops, + .qf_owner = THIS_MODULE }; static int __init init_v1_quota_format(void) diff -Nru a/fs/quota_v2.c b/fs/quota_v2.c --- a/fs/quota_v2.c Fri Sep 20 08:20:44 2002 +++ b/fs/quota_v2.c Fri Sep 20 08:20:44 2002 @@ -662,18 +662,18 @@ } static struct quota_format_ops v2_format_ops = { - check_quota_file: v2_check_quota_file, - read_file_info: v2_read_file_info, - write_file_info: v2_write_file_info, - free_file_info: NULL, - read_dqblk: v2_read_dquot, - commit_dqblk: v2_commit_dquot, + .check_quota_file = v2_check_quota_file, + .read_file_info = v2_read_file_info, + .write_file_info = v2_write_file_info, + .free_file_info = NULL, + .read_dqblk = v2_read_dquot, + .commit_dqblk = v2_commit_dquot, }; static struct quota_format_type v2_quota_format = { - qf_fmt_id: QFMT_VFS_V0, - qf_ops: &v2_format_ops, - qf_owner: THIS_MODULE + .qf_fmt_id = QFMT_VFS_V0, + .qf_ops = &v2_format_ops, + .qf_owner = THIS_MODULE }; static int __init init_v2_quota_format(void) diff -Nru a/fs/read_write.c b/fs/read_write.c --- a/fs/read_write.c Fri Sep 20 08:20:47 2002 +++ b/fs/read_write.c Fri Sep 20 08:20:47 2002 @@ -16,10 +16,10 @@ #include struct file_operations generic_ro_fops = { - llseek: generic_file_llseek, - read: generic_file_read, - mmap: generic_file_mmap, - sendfile: generic_file_sendfile, + .llseek = generic_file_llseek, + .read = generic_file_read, + .mmap = generic_file_mmap, + .sendfile = generic_file_sendfile, }; loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) diff -Nru a/fs/smbfs/dir.c b/fs/smbfs/dir.c --- a/fs/smbfs/dir.c Fri Sep 20 08:20:45 2002 +++ b/fs/smbfs/dir.c Fri Sep 20 08:20:45 2002 @@ -33,22 +33,22 @@ struct file_operations smb_dir_operations = { - read: generic_read_dir, - readdir: smb_readdir, - ioctl: smb_ioctl, - open: smb_dir_open, + .read = generic_read_dir, + .readdir = smb_readdir, + .ioctl = smb_ioctl, + .open = smb_dir_open, }; struct inode_operations smb_dir_inode_operations = { - create: smb_create, - lookup: smb_lookup, - unlink: smb_unlink, - mkdir: smb_mkdir, - rmdir: smb_rmdir, - rename: smb_rename, - getattr: smb_getattr, - setattr: smb_notify_change, + .create = smb_create, + .lookup = smb_lookup, + .unlink = smb_unlink, + .mkdir = smb_mkdir, + .rmdir = smb_rmdir, + .rename = smb_rename, + .getattr = smb_getattr, + .setattr = smb_notify_change, }; /* @@ -257,16 +257,16 @@ static struct dentry_operations smbfs_dentry_operations = { - d_revalidate: smb_lookup_validate, - d_hash: smb_hash_dentry, - d_compare: smb_compare_dentry, - d_delete: smb_delete_dentry, + .d_revalidate = smb_lookup_validate, + .d_hash = smb_hash_dentry, + .d_compare = smb_compare_dentry, + .d_delete = smb_delete_dentry, }; static struct dentry_operations smbfs_dentry_operations_case = { - d_revalidate: smb_lookup_validate, - d_delete: smb_delete_dentry, + .d_revalidate = smb_lookup_validate, + .d_delete = smb_delete_dentry, }; diff -Nru a/fs/smbfs/file.c b/fs/smbfs/file.c --- a/fs/smbfs/file.c Fri Sep 20 08:20:47 2002 +++ b/fs/smbfs/file.c Fri Sep 20 08:20:47 2002 @@ -287,10 +287,10 @@ } struct address_space_operations smb_file_aops = { - readpage: smb_readpage, - writepage: smb_writepage, - prepare_write: smb_prepare_write, - commit_write: smb_commit_write + .readpage = smb_readpage, + .writepage = smb_writepage, + .prepare_write = smb_prepare_write, + .commit_write = smb_commit_write }; /* @@ -382,19 +382,19 @@ struct file_operations smb_file_operations = { - llseek: remote_llseek, - read: smb_file_read, - write: smb_file_write, - ioctl: smb_ioctl, - mmap: smb_file_mmap, - open: smb_file_open, - release: smb_file_release, - fsync: smb_fsync, + .llseek = remote_llseek, + .read = smb_file_read, + .write = smb_file_write, + .ioctl = smb_ioctl, + .mmap = smb_file_mmap, + .open = smb_file_open, + .release = smb_file_release, + .fsync = smb_fsync, }; struct inode_operations smb_file_inode_operations = { - permission: smb_file_permission, - getattr: smb_getattr, - setattr: smb_notify_change, + .permission = smb_file_permission, + .getattr = smb_getattr, + .setattr = smb_notify_change, }; diff -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c --- a/fs/smbfs/inode.c Fri Sep 20 08:20:42 2002 +++ b/fs/smbfs/inode.c Fri Sep 20 08:20:42 2002 @@ -92,13 +92,13 @@ static struct super_operations smb_sops = { - alloc_inode: smb_alloc_inode, - destroy_inode: smb_destroy_inode, - drop_inode: generic_delete_inode, - delete_inode: smb_delete_inode, - put_super: smb_put_super, - statfs: smb_statfs, - show_options: smb_show_options, + .alloc_inode = smb_alloc_inode, + .destroy_inode = smb_destroy_inode, + .drop_inode = generic_delete_inode, + .delete_inode = smb_delete_inode, + .put_super = smb_put_super, + .statfs = smb_statfs, + .show_options = smb_show_options, }; @@ -738,10 +738,10 @@ } static struct file_system_type smb_fs_type = { - owner: THIS_MODULE, - name: "smbfs", - get_sb: smb_get_sb, - kill_sb: kill_anon_super, + .owner = THIS_MODULE, + .name = "smbfs", + .get_sb = smb_get_sb, + .kill_sb = kill_anon_super, }; static int __init init_smb_fs(void) diff -Nru a/fs/smbfs/proc.c b/fs/smbfs/proc.c --- a/fs/smbfs/proc.c Fri Sep 20 08:20:42 2002 +++ b/fs/smbfs/proc.c Fri Sep 20 08:20:42 2002 @@ -1882,8 +1882,8 @@ __u16 count; char status[SMB_STATUS_SIZE]; static struct qstr mask = { - name: "*.*", - len: 3, + .name = "*.*", + .len = 3, }; unsigned char *last_status; struct smb_request *req; @@ -2159,8 +2159,8 @@ struct smb_request *req; unsigned char *name_buf; static struct qstr star = { - name: "*", - len: 1, + .name = "*", + .len = 1, }; lock_kernel(); @@ -2917,39 +2917,39 @@ /* < LANMAN2 */ static struct smb_ops smb_ops_core = { - read: smb_proc_read, - write: smb_proc_write, - readdir: smb_proc_readdir_short, - getattr: smb_proc_getattr_core, - truncate: smb_proc_trunc32, + .read = smb_proc_read, + .write = smb_proc_write, + .readdir = smb_proc_readdir_short, + .getattr = smb_proc_getattr_core, + .truncate = smb_proc_trunc32, }; /* LANMAN2, OS/2, others? */ static struct smb_ops smb_ops_os2 = { - read: smb_proc_read, - write: smb_proc_write, - readdir: smb_proc_readdir_long, - getattr: smb_proc_getattr_trans2_std, - truncate: smb_proc_trunc32, + .read = smb_proc_read, + .write = smb_proc_write, + .readdir = smb_proc_readdir_long, + .getattr = smb_proc_getattr_trans2_std, + .truncate = smb_proc_trunc32, }; /* Win95, and possibly some NetApp versions too */ static struct smb_ops smb_ops_win95 = { - read: smb_proc_read, /* does not support 12word readX */ - write: smb_proc_write, - readdir: smb_proc_readdir_long, - getattr: smb_proc_getattr_95, - truncate: smb_proc_trunc95, + .read = smb_proc_read, /* does not support 12word readX */ + .write = smb_proc_write, + .readdir = smb_proc_readdir_long, + .getattr = smb_proc_getattr_95, + .truncate = smb_proc_trunc95, }; /* Samba, NT4 and NT5 */ static struct smb_ops smb_ops_winNT = { - read: smb_proc_readX, - write: smb_proc_writeX, - readdir: smb_proc_readdir_long, - getattr: smb_proc_getattr_trans2_all, - truncate: smb_proc_trunc64, + .read = smb_proc_readX, + .write = smb_proc_writeX, + .readdir = smb_proc_readdir_long, + .getattr = smb_proc_getattr_trans2_all, + .truncate = smb_proc_trunc64, }; diff -Nru a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c --- a/fs/xfs/linux/xfs_aops.c Fri Sep 20 08:20:47 2002 +++ b/fs/xfs/linux/xfs_aops.c Fri Sep 20 08:20:47 2002 @@ -609,7 +609,7 @@ if (blocks) { size = (pbmap.pbm_bsize - pbmap.pbm_delta); - bh_result->b_size = min(size, blocks << inode->i_blkbits); + bh_result->b_size = min_t(ssize_t, size, blocks << inode->i_blkbits); } return 0; diff -Nru a/fs/xfs/pagebuf/page_buf.c b/fs/xfs/pagebuf/page_buf.c --- a/fs/xfs/pagebuf/page_buf.c Fri Sep 20 08:20:41 2002 +++ b/fs/xfs/pagebuf/page_buf.c Fri Sep 20 08:20:41 2002 @@ -1291,14 +1291,19 @@ /* * Helper routine for pagebuf_iorequest */ -STATIC void +STATIC int bio_end_io_pagebuf( - struct bio *bio) + struct bio *bio, + unsigned int bytes_done, + int error) { page_buf_t *pb = (page_buf_t *)bio->bi_private; unsigned int i, blocksize = pb->pb_target->pbr_blocksize; struct bio_vec *bvec = bio->bi_io_vec; + if (bio->bi_size) + return 1; + if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) pb->pb_error = EIO; @@ -1335,6 +1340,7 @@ } bio_put(bio); + return 0; } /* @@ -1447,7 +1453,6 @@ bio = bio_alloc(GFP_NOIO, nr_pages); BUG_ON(bio == NULL); - bio_init(bio); bio->bi_bdev = pb->pb_target->pbr_bdev; bio->bi_sector = sector; bio->bi_end_io = bio_end_io_pagebuf; @@ -1461,12 +1466,8 @@ if (nbytes > size) nbytes = size; - bio->bi_vcnt++; - bio->bi_size += nbytes; - - bvec->bv_page = pb->pb_pages[map_i]; - bvec->bv_len = nbytes; - bvec->bv_offset = offset; + if (bio_add_page(bio, pb->pb_pages[map_i], nbytes, offset)) + break; offset = 0; diff -Nru a/include/asm-alpha/mmzone.h b/include/asm-alpha/mmzone.h --- a/include/asm-alpha/mmzone.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-alpha/mmzone.h Fri Sep 20 08:20:47 2002 @@ -36,18 +36,14 @@ #ifdef CONFIG_ALPHA_WILDFIRE # define ALPHA_PA_TO_NID(pa) ((pa) >> 36) /* 16 nodes max due 43bit kseg */ -#define NODE_MAX_MEM_SIZE (64L * 1024L * 1024L * 1024L) /* 64 GB */ -#define MAX_NUMNODES WILDFIRE_MAX_QBB +# define NODE_MAX_MEM_SIZE (64L * 1024L * 1024L * 1024L) /* 64 GB */ #else # define ALPHA_PA_TO_NID(pa) (0) -#define NODE_MAX_MEM_SIZE (~0UL) -#define MAX_NUMNODES 1 +# define NODE_MAX_MEM_SIZE (~0UL) #endif #define PHYSADDR_TO_NID(pa) ALPHA_PA_TO_NID(pa) #define PLAT_NODE_DATA(n) (plat_node_data[(n)]) -#define PLAT_NODE_DATA_STARTNR(n) \ - (PLAT_NODE_DATA(n)->gendata.node_start_mapnr) #define PLAT_NODE_DATA_SIZE(n) (PLAT_NODE_DATA(n)->gendata.node_size) #if 1 diff -Nru a/include/asm-alpha/numnodes.h b/include/asm-alpha/numnodes.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-alpha/numnodes.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,12 @@ +#ifndef _ASM_MAX_NUMNODES_H +#define _ASM_MAX_NUMNODES_H + +/* + * Currently the Wildfire is the only discontigmem/NUMA capable Alpha core. + */ +#if defined(CONFIG_ALPHA_WILDFIRE) || defined(CONFIG_ALPHA_GENERIC) +# include +# define MAX_NUMNODES WILDFIRE_MAX_QBB +#endif + +#endif /* _ASM_MAX_NUMNODES_H */ diff -Nru a/include/asm-i386/arch_hooks.h b/include/asm-i386/arch_hooks.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/arch_hooks.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,25 @@ +#ifndef _ASM_ARCH_HOOKS_H +#define _ASM_ARCH_HOOKS_H + +/* + * linux/include/asm/arch_hooks.h + * + * define the architecture specific hooks + */ + +/* these aren't arch hooks, they are generic routines + * that can be used by the hooks */ +extern void init_ISA_irqs(void); +extern void apic_intr_init(void); +extern void smp_intr_init(void); +extern void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* these are the defined hooks */ +extern void intr_init_hook(void); +extern void pre_intr_init_hook(void); +extern void pre_setup_arch_hook(void); +extern void trap_init_hook(void); +extern void time_init_hook(void); +extern void mca_nmi_hook(void); + +#endif diff -Nru a/include/asm-i386/irq.h b/include/asm-i386/irq.h --- a/include/asm-i386/irq.h Fri Sep 20 08:20:42 2002 +++ b/include/asm-i386/irq.h Fri Sep 20 08:20:42 2002 @@ -12,7 +12,8 @@ #include #include -#include +/* include comes from machine specific directory */ +#include "irq_vectors.h" static __inline__ int irq_cannonicalize(int irq) { diff -Nru a/include/asm-i386/irq_vectors.h b/include/asm-i386/irq_vectors.h --- a/include/asm-i386/irq_vectors.h Fri Sep 20 08:20:43 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,64 +0,0 @@ -#ifndef _ASM_IRQ_VECTORS_H -#define _ASM_IRQ_VECTORS_H - -/* - * IDT vectors usable for external interrupt sources start - * at 0x20: - */ -#define FIRST_EXTERNAL_VECTOR 0x20 - -#define SYSCALL_VECTOR 0x80 - -/* - * Vectors 0x20-0x2f are used for ISA interrupts. - */ - -/* - * Special IRQ vectors used by the SMP architecture, 0xf0-0xff - * - * some of the following vectors are 'rare', they are merged - * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. - * TLB, reschedule and local APIC vectors are performance-critical. - * - * Vectors 0xf0-0xfa are free (reserved for future Linux use). - */ -#define SPURIOUS_APIC_VECTOR 0xff -#define ERROR_APIC_VECTOR 0xfe -#define INVALIDATE_TLB_VECTOR 0xfd -#define RESCHEDULE_VECTOR 0xfc -#define CALL_FUNCTION_VECTOR 0xfb - -#define THERMAL_APIC_VECTOR 0xf0 -/* - * Local APIC timer IRQ vector is on a different priority level, - * to work around the 'lost local interrupt if more than 2 IRQ - * sources per level' errata. - */ -#define LOCAL_TIMER_VECTOR 0xef - -/* - * First APIC vector available to drivers: (vectors 0x30-0xee) - * we start at 0x31 to spread out vectors evenly between priority - * levels. (0x80 is the syscall vector) - */ -#define FIRST_DEVICE_VECTOR 0x31 -#define FIRST_SYSTEM_VECTOR 0xef - -#define TIMER_IRQ 0 - -/* - * 16 8259A IRQ's, 208 potential APIC interrupt sources. - * Right now the APIC is mostly only used for SMP. - * 256 vectors is an architectural limit. (we can have - * more than 256 devices theoretically, but they will - * have to use shared interrupts) - * Since vectors 0x00-0x1f are used/reserved for the CPU, - * the usable vector space is 0x20-0xff (224 vectors) - */ -#ifdef CONFIG_X86_IO_APIC -#define NR_IRQS 224 -#else -#define NR_IRQS 16 -#endif - -#endif /* _ASM_IRQ_VECTORS_H */ diff -Nru a/include/asm-i386/max_numnodes.h b/include/asm-i386/max_numnodes.h --- a/include/asm-i386/max_numnodes.h Fri Sep 20 08:20:43 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,12 +0,0 @@ -#ifndef _ASM_MAX_NUMNODES_H -#define _ASM_MAX_NUMNODES_H - -#include - -#ifdef CONFIG_X86_NUMAQ -#include -#else -#define MAX_NUMNODES 1 -#endif /* CONFIG_X86_NUMAQ */ - -#endif /* _ASM_MAX_NUMNODES_H */ diff -Nru a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h --- a/include/asm-i386/mmzone.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-i386/mmzone.h Fri Sep 20 08:20:46 2002 @@ -6,12 +6,13 @@ #ifndef _ASM_MMZONE_H_ #define _ASM_MMZONE_H_ +#include + #ifdef CONFIG_DISCONTIGMEM #ifdef CONFIG_X86_NUMAQ #include #else -#define pa_to_nid(pa) (0) #define pfn_to_nid(pfn) (0) #ifdef CONFIG_NUMA #define _cpu_to_node(cpu) 0 @@ -44,7 +45,6 @@ #define alloc_bootmem_low_pages_node(ignore, x) \ __alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, 0) -#define node_startnr(nid) (node_data[nid]->node_start_mapnr) #define node_size(nid) (node_data[nid]->node_size) #define node_localnr(pfn, nid) ((pfn) - node_data[nid]->node_start_pfn) @@ -55,7 +55,7 @@ /* * Given a kernel address, find the home node of the underlying memory. */ -#define kvaddr_to_nid(kaddr) pa_to_nid(__pa(kaddr)) +#define kvaddr_to_nid(kaddr) pfn_to_nid(__pa(kaddr) >> PAGE_SHIFT) /* * Return a pointer to the node data for node n. @@ -64,6 +64,8 @@ #define node_mem_map(nid) (NODE_DATA(nid)->node_mem_map) #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) +#define node_end_pfn(nid) (NODE_DATA(nid)->node_start_pfn + \ + NODE_DATA(nid)->node_size) #define local_mapnr(kvaddr) \ ( (__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)) ) @@ -74,5 +76,13 @@ #define pfn_to_page(pfn) (node_mem_map(pfn_to_nid(pfn)) + node_localnr(pfn, pfn_to_nid(pfn))) #define page_to_pfn(page) ((page - page_zone(page)->zone_mem_map) + page_zone(page)->zone_start_pfn) #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) +/* + * pfn_valid should be made as fast as possible, and the current definition + * is valid for machines that are NUMA, but still contiguous, which is what + * is currently supported. A more generalised, but slower definition would + * be something like this - mbligh: + * ( pfn_to_pgdat(pfn) && (pfn < node_end_pfn(pfn_to_nid(pfn))) ) + */ +#define pfn_valid(pfn) (pfn < num_physpages) #endif /* CONFIG_DISCONTIGMEM */ #endif /* _ASM_MMZONE_H_ */ diff -Nru a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h --- a/include/asm-i386/mpspec.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-i386/mpspec.h Fri Sep 20 08:20:41 2002 @@ -226,6 +226,7 @@ extern void mp_register_ioapic (u8 id, u32 address, u32 irq_base); extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 global_irq); extern void mp_config_acpi_legacy_irqs (void); +extern void mp_config_ioapic_for_sci(int irq); extern void mp_parse_prt (void); #endif /*CONFIG_ACPI_BOOT*/ diff -Nru a/include/asm-i386/numaq.h b/include/asm-i386/numaq.h --- a/include/asm-i386/numaq.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-i386/numaq.h Fri Sep 20 08:20:46 2002 @@ -32,17 +32,18 @@ /* * for now assume that 64Gb is max amount of RAM for whole system - * 64Gb * 1024Mb/Gb = 65536 Mb - * 65536 Mb / 256Mb = 256 + * 64Gb / 4096bytes/page = 16777216 pages */ +#define MAX_NR_PAGES 16777216 #define MAX_ELEMENTS 256 -#define ELEMENT_REPRESENTS 8 /* 256 Mb */ +#define PAGES_PER_ELEMENT (16777216/256) +#define pfn_to_pgdat(pfn) NODE_DATA(pfn_to_nid(pfn)) +#define PHYSADDR_TO_NID(pa) pfn_to_nid(pa >> PAGE_SHIFT) #define MAX_NUMNODES 8 #ifdef CONFIG_NUMA #define _cpu_to_node(cpu) (cpu_to_logical_apicid(cpu) >> 4) #endif /* CONFIG_NUMA */ -extern int pa_to_nid(u64); extern int pfn_to_nid(unsigned long); extern void get_memcfg_numaq(void); #define get_memcfg_numa() get_memcfg_numaq() diff -Nru a/include/asm-i386/numnodes.h b/include/asm-i386/numnodes.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/numnodes.h Fri Sep 20 08:20:43 2002 @@ -0,0 +1,12 @@ +#ifndef _ASM_MAX_NUMNODES_H +#define _ASM_MAX_NUMNODES_H + +#include + +#ifdef CONFIG_X86_NUMAQ +#include +#else +#define MAX_NUMNODES 1 +#endif /* CONFIG_X86_NUMAQ */ + +#endif /* _ASM_MAX_NUMNODES_H */ diff -Nru a/include/asm-i386/page.h b/include/asm-i386/page.h --- a/include/asm-i386/page.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-i386/page.h Fri Sep 20 08:20:43 2002 @@ -145,10 +145,10 @@ #ifndef CONFIG_DISCONTIGMEM #define pfn_to_page(pfn) (mem_map + (pfn)) #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) +#define pfn_valid(pfn) ((pfn) < max_mapnr) #endif /* !CONFIG_DISCONTIGMEM */ #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) -#define pfn_valid(pfn) ((pfn) < max_mapnr) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ diff -Nru a/include/asm-mips64/mmzone.h b/include/asm-mips64/mmzone.h --- a/include/asm-mips64/mmzone.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-mips64/mmzone.h Fri Sep 20 08:20:41 2002 @@ -24,7 +24,6 @@ #define PHYSADDR_TO_NID(pa) NASID_TO_COMPACT_NODEID(NASID_GET(pa)) #define PLAT_NODE_DATA(n) (plat_node_data[n]) -#define PLAT_NODE_DATA_STARTNR(n) (PLAT_NODE_DATA(n)->gendata.node_start_mapnr) #define PLAT_NODE_DATA_SIZE(n) (PLAT_NODE_DATA(n)->gendata.node_size) #define PLAT_NODE_DATA_LOCALNR(p, n) \ (((p) >> PAGE_SHIFT) - PLAT_NODE_DATA(n)->gendata.node_start_pfn) diff -Nru a/include/asm-mips64/pgtable.h b/include/asm-mips64/pgtable.h --- a/include/asm-mips64/pgtable.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-mips64/pgtable.h Fri Sep 20 08:20:48 2002 @@ -373,10 +373,10 @@ #ifndef CONFIG_DISCONTIGMEM #define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT))) #else -#define mips64_pte_pagenr(x) \ - (PLAT_NODE_DATA_STARTNR(PHYSADDR_TO_NID(pte_val(x))) + \ - PLAT_NODE_DATA_LOCALNR(pte_val(x), PHYSADDR_TO_NID(pte_val(x)))) -#define pte_page(x) (mem_map+mips64_pte_pagenr(x)) + +#define pte_page(x) ( NODE_MEM_MAP(PHYSADDR_TO_NID(pte_val(x))) + + PLAT_NODE_DATA_LOCALNR(pte_val(x), PHYSADDR_TO_NID(pte_val(x))) ) + #endif /* diff -Nru a/include/asm-ppc/8xx_immap.h b/include/asm-ppc/8xx_immap.h --- a/include/asm-ppc/8xx_immap.h Fri Sep 20 08:20:45 2002 +++ b/include/asm-ppc/8xx_immap.h Fri Sep 20 08:20:45 2002 @@ -1,8 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ - -/* * MPC8xx Internal Memory Map * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * diff -Nru a/include/asm-ppc/a.out.h b/include/asm-ppc/a.out.h --- a/include/asm-ppc/a.out.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/a.out.h Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.a.out.h 1.5 05/17/01 18:14:24 cort - */ #ifndef __PPC_A_OUT_H__ #define __PPC_A_OUT_H__ diff -Nru a/include/asm-ppc/amigahw.h b/include/asm-ppc/amigahw.h --- a/include/asm-ppc/amigahw.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/amigahw.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.amigahw.h 1.5 05/17/01 18:14:24 cort - */ #ifdef __KERNEL__ #ifndef __ASMPPC_AMIGAHW_H #define __ASMPPC_AMIGAHW_H diff -Nru a/include/asm-ppc/amigaints.h b/include/asm-ppc/amigaints.h --- a/include/asm-ppc/amigaints.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/amigaints.h Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* ** amigaints.h -- Amiga Linux interrupt handling structs and prototypes ** ** Copyright 1992 by Greg Harp diff -Nru a/include/asm-ppc/amigappc.h b/include/asm-ppc/amigappc.h --- a/include/asm-ppc/amigappc.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/amigappc.h Fri Sep 20 08:20:43 2002 @@ -1,8 +1,5 @@ /* - * BK Id: SCCS/s.amigappc.h 1.5 05/17/01 18:14:24 cort - */ -/* -** asm-m68k/amigappc.h -- This header defines some values and pointers for +** asm-ppc/amigappc.h -- This header defines some values and pointers for ** the Phase 5 PowerUp card. ** ** Copyright 1997, 1998 by Phase5, Germany. diff -Nru a/include/asm-ppc/amigayle.h b/include/asm-ppc/amigayle.h --- a/include/asm-ppc/amigayle.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/amigayle.h Fri Sep 20 08:20:43 2002 @@ -1,4 +1 @@ -/* - * BK Id: SCCS/s.amigayle.h 1.5 05/17/01 18:14:24 cort - */ #include diff -Nru a/include/asm-ppc/amipcmcia.h b/include/asm-ppc/amipcmcia.h --- a/include/asm-ppc/amipcmcia.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/amipcmcia.h Fri Sep 20 08:20:47 2002 @@ -1,4 +1 @@ -/* - * BK Id: SCCS/s.amipcmcia.h 1.5 05/17/01 18:14:24 cort - */ #include diff -Nru a/include/asm-ppc/atomic.h b/include/asm-ppc/atomic.h --- a/include/asm-ppc/atomic.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/atomic.h Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * PowerPC atomic operations */ diff -Nru a/include/asm-ppc/backlight.h b/include/asm-ppc/backlight.h --- a/include/asm-ppc/backlight.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/backlight.h Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.backlight.h 1.5 05/17/01 18:14:24 cort - */ -/* * Routines for handling backlight control on PowerBooks * * For now, implementation resides in arch/ppc/kernel/pmac_support.c diff -Nru a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h --- a/include/asm-ppc/bitops.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/bitops.h Fri Sep 20 08:20:46 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * bitops.h: Bit string operations on the ppc */ diff -Nru a/include/asm-ppc/bootinfo.h b/include/asm-ppc/bootinfo.h --- a/include/asm-ppc/bootinfo.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/bootinfo.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Non-machine dependent bootinfo structure. Basic idea * borrowed from the m68k. * diff -Nru a/include/asm-ppc/bootx.h b/include/asm-ppc/bootx.h --- a/include/asm-ppc/bootx.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/bootx.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.bootx.h 1.5 05/17/01 18:14:24 cort - */ -/* * This file describes the structure passed from the BootX application * (for MacOS) when it is used to boot Linux. * diff -Nru a/include/asm-ppc/bseip.h b/include/asm-ppc/bseip.h --- a/include/asm-ppc/bseip.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/bseip.h Fri Sep 20 08:20:41 2002 @@ -1,8 +1,4 @@ /* - * BK Id: SCCS/s.bseip.h 1.10 08/17/01 15:23:17 paulus - */ - -/* * A collection of structures, addresses, and values associated with * the Bright Star Engineering ip-Engine board. Copied from the MBX stuff. * diff -Nru a/include/asm-ppc/btext.h b/include/asm-ppc/btext.h --- a/include/asm-ppc/btext.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/btext.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Definitions for using the procedures in btext.c. * * Benjamin Herrenschmidt diff -Nru a/include/asm-ppc/bugs.h b/include/asm-ppc/bugs.h --- a/include/asm-ppc/bugs.h Fri Sep 20 08:20:45 2002 +++ b/include/asm-ppc/bugs.h Fri Sep 20 08:20:45 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.bugs.h 1.5 05/17/01 18:14:24 cort - */ -/* * This file is included by 'init/main.c' */ diff -Nru a/include/asm-ppc/byteorder.h b/include/asm-ppc/byteorder.h --- a/include/asm-ppc/byteorder.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/byteorder.h Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef _PPC_BYTEORDER_H #define _PPC_BYTEORDER_H diff -Nru a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h --- a/include/asm-ppc/cache.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/cache.h Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * include/asm-ppc/cache.h */ #ifdef __KERNEL__ diff -Nru a/include/asm-ppc/cacheflush.h b/include/asm-ppc/cacheflush.h --- a/include/asm-ppc/cacheflush.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/cacheflush.h Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * include/asm-ppc/cacheflush.h * * This program is free software; you can redistribute it and/or diff -Nru a/include/asm-ppc/checksum.h b/include/asm-ppc/checksum.h --- a/include/asm-ppc/checksum.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/checksum.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.checksum.h 1.8 05/17/01 18:14:24 cort - */ #ifdef __KERNEL__ #ifndef _PPC_CHECKSUM_H #define _PPC_CHECKSUM_H diff -Nru a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h --- a/include/asm-ppc/commproc.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/commproc.h Fri Sep 20 08:20:47 2002 @@ -1,8 +1,4 @@ /* - * BK Id: SCCS/s.commproc.h 1.16 09/27/01 12:41:09 trini - */ - -/* * MPC8xx Communication Processor Module. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * diff -Nru a/include/asm-ppc/cpm_8260.h b/include/asm-ppc/cpm_8260.h --- a/include/asm-ppc/cpm_8260.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/cpm_8260.h Fri Sep 20 08:20:46 2002 @@ -1,8 +1,4 @@ /* - * BK Id: SCCS/s.cpm_8260.h 1.7 05/17/01 18:14:24 cort - */ - -/* * MPC8260 Communication Processor Module. * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) * diff -Nru a/include/asm-ppc/cputable.h b/include/asm-ppc/cputable.h --- a/include/asm-ppc/cputable.h Fri Sep 20 08:20:45 2002 +++ b/include/asm-ppc/cputable.h Fri Sep 20 08:20:45 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.cputable.h 1.3 08/19/01 22:31:46 paulus - */ -/* * include/asm-ppc/cputable.h * * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) diff -Nru a/include/asm-ppc/current.h b/include/asm-ppc/current.h --- a/include/asm-ppc/current.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/current.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.current.h 1.5 05/17/01 18:14:24 cort - */ #ifdef __KERNEL__ #ifndef _PPC_CURRENT_H #define _PPC_CURRENT_H diff -Nru a/include/asm-ppc/dbdma.h b/include/asm-ppc/dbdma.h --- a/include/asm-ppc/dbdma.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/dbdma.h Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Definitions for using the Apple Descriptor-Based DMA controller * in Power Macintosh computers. * diff -Nru a/include/asm-ppc/delay.h b/include/asm-ppc/delay.h --- a/include/asm-ppc/delay.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/delay.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef _PPC_DELAY_H #define _PPC_DELAY_H diff -Nru a/include/asm-ppc/div64.h b/include/asm-ppc/div64.h --- a/include/asm-ppc/div64.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/div64.h Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.div64.h 1.5 05/17/01 18:14:24 cort - */ #ifndef __PPC_DIV64 #define __PPC_DIV64 diff -Nru a/include/asm-ppc/dma.h b/include/asm-ppc/dma.h --- a/include/asm-ppc/dma.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/dma.h Fri Sep 20 08:20:47 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * linux/include/asm/dma.h: Defines for using and allocating dma channels. + * include/asm-ppc/dma.h: Defines for using and allocating dma channels. * Written by Hennus Bergman, 1992. * High DMA channel support & info by Hannu Savolainen * and John Boyd, Nov. 1992. diff -Nru a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h --- a/include/asm-ppc/elf.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/elf.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef __PPC_ELF_H #define __PPC_ELF_H diff -Nru a/include/asm-ppc/errno.h b/include/asm-ppc/errno.h --- a/include/asm-ppc/errno.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/errno.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.errno.h 1.7 05/17/01 18:14:24 cort - */ #ifndef _PPC_ERRNO_H #define _PPC_ERRNO_H diff -Nru a/include/asm-ppc/fcntl.h b/include/asm-ppc/fcntl.h --- a/include/asm-ppc/fcntl.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/fcntl.h Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.fcntl.h 1.8 09/19/01 23:06:01 paulus - */ #ifndef _PPC_FCNTL_H #define _PPC_FCNTL_H diff -Nru a/include/asm-ppc/floppy.h b/include/asm-ppc/floppy.h --- a/include/asm-ppc/floppy.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/floppy.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.floppy.h 1.5 05/17/01 18:14:24 cort - */ -/* * Architecture specific parts of the Floppy driver * * This file is subject to the terms and conditions of the GNU General Public diff -Nru a/include/asm-ppc/gg2.h b/include/asm-ppc/gg2.h --- a/include/asm-ppc/gg2.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/gg2.h Fri Sep 20 08:20:47 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * asm-ppc/gg2.h -- VLSI VAS96011/12 `Golden Gate 2' register definitions + * include/asm-ppc/gg2.h -- VLSI VAS96011/12 `Golden Gate 2' register definitions * * Copyright (C) 1997 Geert Uytterhoeven * diff -Nru a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h --- a/include/asm-ppc/hardirq.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/hardirq.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef __ASM_HARDIRQ_H #define __ASM_HARDIRQ_H diff -Nru a/include/asm-ppc/hdreg.h b/include/asm-ppc/hdreg.h --- a/include/asm-ppc/hdreg.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/hdreg.h Fri Sep 20 08:20:43 2002 @@ -1,8 +1,5 @@ /* - * BK Id: SCCS/s.hdreg.h 1.5 05/17/01 18:14:24 cort - */ -/* - * linux/include/asm-ppc/hdreg.h + * include/asm-ppc/hdreg.h * * Copyright (C) 1994-1996 Linus Torvalds & authors */ diff -Nru a/include/asm-ppc/heathrow.h b/include/asm-ppc/heathrow.h --- a/include/asm-ppc/heathrow.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/heathrow.h Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * heathrow.h: definitions for using the "Heathrow" I/O controller chip. * * Grabbed from Open Firmware definitions on a PowerBook G3 Series diff -Nru a/include/asm-ppc/highmem.h b/include/asm-ppc/highmem.h --- a/include/asm-ppc/highmem.h Fri Sep 20 08:20:45 2002 +++ b/include/asm-ppc/highmem.h Fri Sep 20 08:20:45 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * highmem.h: virtual kernel memory mappings for high memory * * PowerPC version, stolen from the i386 version. diff -Nru a/include/asm-ppc/hw_irq.h b/include/asm-ppc/hw_irq.h --- a/include/asm-ppc/hw_irq.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/hw_irq.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Copyright (C) 1999 Cort Dougan */ #ifdef __KERNEL__ diff -Nru a/include/asm-ppc/hydra.h b/include/asm-ppc/hydra.h --- a/include/asm-ppc/hydra.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/hydra.h Fri Sep 20 08:20:46 2002 @@ -1,8 +1,5 @@ /* - * BK Id: SCCS/s.hydra.h 1.5 05/17/01 18:14:24 cort - */ -/* - * asm-ppc/hydra.h -- Mac I/O `Hydra' definitions + * include/asm-ppc/hydra.h -- Mac I/O `Hydra' definitions * * Copyright (C) 1997 Geert Uytterhoeven * diff -Nru a/include/asm-ppc/i8259.h b/include/asm-ppc/i8259.h --- a/include/asm-ppc/i8259.h Fri Sep 20 08:20:42 2002 +++ b/include/asm-ppc/i8259.h Fri Sep 20 08:20:42 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - #ifndef _PPC_KERNEL_i8259_H #define _PPC_KERNEL_i8259_H diff -Nru a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h --- a/include/asm-ppc/ide.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/ide.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * linux/include/asm-ppc/ide.h * * Copyright (C) 1994-1996 Linus Torvalds & authors */ diff -Nru a/include/asm-ppc/immap_8260.h b/include/asm-ppc/immap_8260.h --- a/include/asm-ppc/immap_8260.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/immap_8260.h Fri Sep 20 08:20:46 2002 @@ -1,8 +1,4 @@ /* - * BK Id: SCCS/s.immap_8260.h 1.8 07/18/01 15:46:50 trini - */ - -/* * MPC8260 Internal Memory Map * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) * diff -Nru a/include/asm-ppc/io.h b/include/asm-ppc/io.h --- a/include/asm-ppc/io.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/io.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - #ifdef __KERNEL__ #ifndef _PPC_IO_H #define _PPC_IO_H diff -Nru a/include/asm-ppc/ioctl.h b/include/asm-ppc/ioctl.h --- a/include/asm-ppc/ioctl.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/ioctl.h Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.ioctl.h 1.5 05/17/01 18:14:24 cort - */ #ifndef _PPC_IOCTL_H #define _PPC_IOCTL_H diff -Nru a/include/asm-ppc/ioctls.h b/include/asm-ppc/ioctls.h --- a/include/asm-ppc/ioctls.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/ioctls.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.ioctls.h 1.7 05/17/01 18:14:24 cort - */ #ifndef _ASM_PPC_IOCTLS_H #define _ASM_PPC_IOCTLS_H diff -Nru a/include/asm-ppc/ipc.h b/include/asm-ppc/ipc.h --- a/include/asm-ppc/ipc.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/ipc.h Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.ipc.h 1.5 05/17/01 18:14:24 cort - */ #ifndef __PPC_IPC_H__ #define __PPC_IPC_H__ diff -Nru a/include/asm-ppc/ipcbuf.h b/include/asm-ppc/ipcbuf.h --- a/include/asm-ppc/ipcbuf.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/ipcbuf.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.ipcbuf.h 1.5 05/17/01 18:14:24 cort - */ #ifndef __PPC_IPCBUF_H__ #define __PPC_IPCBUF_H__ diff -Nru a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h --- a/include/asm-ppc/irq.h Fri Sep 20 08:20:42 2002 +++ b/include/asm-ppc/irq.h Fri Sep 20 08:20:42 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef _ASM_IRQ_H #define _ASM_IRQ_H diff -Nru a/include/asm-ppc/keylargo.h b/include/asm-ppc/keylargo.h --- a/include/asm-ppc/keylargo.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/keylargo.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * keylargo.h: definitions for using the "KeyLargo" I/O controller chip. * */ diff -Nru a/include/asm-ppc/kgdb.h b/include/asm-ppc/kgdb.h --- a/include/asm-ppc/kgdb.h Fri Sep 20 08:20:42 2002 +++ b/include/asm-ppc/kgdb.h Fri Sep 20 08:20:42 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * kgdb.h: Defines and declarations for serial line source level * remote debugging of the Linux kernel using gdb. * diff -Nru a/include/asm-ppc/kmap_types.h b/include/asm-ppc/kmap_types.h --- a/include/asm-ppc/kmap_types.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/kmap_types.h Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef _ASM_KMAP_TYPES_H #define _ASM_KMAP_TYPES_H diff -Nru a/include/asm-ppc/linux_logo.h b/include/asm-ppc/linux_logo.h --- a/include/asm-ppc/linux_logo.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/linux_logo.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.linux_logo.h 1.7 05/17/01 18:14:24 cort - */ -/* * include/asm-ppc/linux_logo.h: A linux logo to be displayed on boot * (pinched from the sparc port). * diff -Nru a/include/asm-ppc/m48t35.h b/include/asm-ppc/m48t35.h --- a/include/asm-ppc/m48t35.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/m48t35.h Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.m48t35.h 1.8 10/16/01 15:58:42 trini - */ -/* * Registers for the SGS-Thomson M48T35 Timekeeper RAM chip * and * Registers for the SGS-Thomson M48T37 Timekeeper RAM chip diff -Nru a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h --- a/include/asm-ppc/machdep.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/machdep.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef _PPC_MACHDEP_H #define _PPC_MACHDEP_H diff -Nru a/include/asm-ppc/mc146818rtc.h b/include/asm-ppc/mc146818rtc.h --- a/include/asm-ppc/mc146818rtc.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/mc146818rtc.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.mc146818rtc.h 1.5 05/17/01 18:14:25 cort - */ -/* * Machine dependent access functions for RTC registers. */ #ifdef __KERNEL__ diff -Nru a/include/asm-ppc/md.h b/include/asm-ppc/md.h --- a/include/asm-ppc/md.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/md.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.md.h 1.5 05/17/01 18:14:25 cort - */ -/* * md.h: High speed xor_block operation for RAID4/5 * */ diff -Nru a/include/asm-ppc/mediabay.h b/include/asm-ppc/mediabay.h --- a/include/asm-ppc/mediabay.h Fri Sep 20 08:20:42 2002 +++ b/include/asm-ppc/mediabay.h Fri Sep 20 08:20:42 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * mediabay.h: definitions for using the media bay * on PowerBook 3400 and similar computers. * diff -Nru a/include/asm-ppc/mk48t59.h b/include/asm-ppc/mk48t59.h --- a/include/asm-ppc/mk48t59.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/mk48t59.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.mk48t59.h 1.5 05/17/01 18:14:25 cort - */ -/* * Registers for the mk48t59 real-time-clock */ diff -Nru a/include/asm-ppc/mman.h b/include/asm-ppc/mman.h --- a/include/asm-ppc/mman.h Fri Sep 20 08:20:49 2002 +++ b/include/asm-ppc/mman.h Fri Sep 20 08:20:49 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.mman.h 1.7 05/17/01 18:14:25 cort - */ #ifndef __PPC_MMAN_H__ #define __PPC_MMAN_H__ diff -Nru a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h --- a/include/asm-ppc/mmu.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/mmu.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * PowerPC memory management structures */ diff -Nru a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h --- a/include/asm-ppc/mmu_context.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/mmu_context.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef __PPC_MMU_CONTEXT_H #define __PPC_MMU_CONTEXT_H diff -Nru a/include/asm-ppc/module.h b/include/asm-ppc/module.h --- a/include/asm-ppc/module.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/module.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.module.h 1.5 05/17/01 18:14:25 cort - */ #ifndef _ASM_PPC_MODULE_H #define _ASM_PPC_MODULE_H /* diff -Nru a/include/asm-ppc/mpc8260.h b/include/asm-ppc/mpc8260.h --- a/include/asm-ppc/mpc8260.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/mpc8260.h Fri Sep 20 08:20:41 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - /* This is the single file included by all MPC8260 build options. * Since there are many different boards and no standard configuration, * we have a unique include file for each. Rather than change every diff -Nru a/include/asm-ppc/mpc8xx.h b/include/asm-ppc/mpc8xx.h --- a/include/asm-ppc/mpc8xx.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/mpc8xx.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ - /* This is the single file included by all MPC8xx build options. * Since there are many different boards and no standard configuration, * we have a unique include file for each. Rather than change every diff -Nru a/include/asm-ppc/msgbuf.h b/include/asm-ppc/msgbuf.h --- a/include/asm-ppc/msgbuf.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/msgbuf.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.msgbuf.h 1.5 05/17/01 18:14:25 cort - */ #ifndef _PPC_MSGBUF_H #define _PPC_MSGBUF_H diff -Nru a/include/asm-ppc/namei.h b/include/asm-ppc/namei.h --- a/include/asm-ppc/namei.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/namei.h Fri Sep 20 08:20:47 2002 @@ -1,10 +1,8 @@ /* - * BK Id: SCCS/s.namei.h 1.5 05/17/01 18:14:25 cort - */ -/* linux/include/asm-ppc/namei.h - * Adapted from linux/include/asm-alpha/namei.h + * include/asm-ppc/namei.h + * Adapted from include/asm-alpha/namei.h * - * Included from linux/fs/namei.c + * Included from fs/namei.c */ #ifdef __KERNEL__ diff -Nru a/include/asm-ppc/nvram.h b/include/asm-ppc/nvram.h --- a/include/asm-ppc/nvram.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/nvram.h Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.nvram.h 1.5 05/17/01 18:14:25 cort - */ -/* * PreP compliant NVRAM access */ diff -Nru a/include/asm-ppc/ohare.h b/include/asm-ppc/ohare.h --- a/include/asm-ppc/ohare.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/ohare.h Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * ohare.h: definitions for using the "O'Hare" I/O controller chip. * * Copyright (C) 1997 Paul Mackerras. diff -Nru a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h --- a/include/asm-ppc/open_pic.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/open_pic.h Fri Sep 20 08:20:44 2002 @@ -1,8 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling + * include/asm-ppc/open_pic.h -- OpenPIC Interrupt Handling * * Copyright (C) 1997 Geert Uytterhoeven * diff -Nru a/include/asm-ppc/page.h b/include/asm-ppc/page.h --- a/include/asm-ppc/page.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/page.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef _PPC_PAGE_H #define _PPC_PAGE_H diff -Nru a/include/asm-ppc/param.h b/include/asm-ppc/param.h --- a/include/asm-ppc/param.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/param.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef _ASM_PPC_PARAM_H #define _ASM_PPC_PARAM_H diff -Nru a/include/asm-ppc/parport.h b/include/asm-ppc/parport.h --- a/include/asm-ppc/parport.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/parport.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.parport.h 1.5 05/17/01 18:14:25 cort - */ -/* * parport.h: platform-specific PC-style parport initialisation * * Copyright (C) 1999, 2000 Tim Waugh diff -Nru a/include/asm-ppc/pc_serial.h b/include/asm-ppc/pc_serial.h --- a/include/asm-ppc/pc_serial.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/pc_serial.h Fri Sep 20 08:20:43 2002 @@ -1,6 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - * * include/asm-ppc/pc_serial.h * * This is basically a copy of include/asm-i386/serial.h. diff -Nru a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h --- a/include/asm-ppc/pci-bridge.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/pci-bridge.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef _ASM_PCI_BRIDGE_H #define _ASM_PCI_BRIDGE_H diff -Nru a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h --- a/include/asm-ppc/pci.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/pci.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef __PPC_PCI_H #define __PPC_PCI_H #ifdef __KERNEL__ diff -Nru a/include/asm-ppc/pgalloc.h b/include/asm-ppc/pgalloc.h --- a/include/asm-ppc/pgalloc.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/pgalloc.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef _PPC_PGALLOC_H #define _PPC_PGALLOC_H diff -Nru a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h --- a/include/asm-ppc/pgtable.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/pgtable.h Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef _PPC_PGTABLE_H #define _PPC_PGTABLE_H diff -Nru a/include/asm-ppc/pnp.h b/include/asm-ppc/pnp.h --- a/include/asm-ppc/pnp.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/pnp.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.pnp.h 1.5 05/17/01 18:14:25 cort - */ #ifdef __KERNEL__ /* 11/02/95 */ /*----------------------------------------------------------------------------*/ diff -Nru a/include/asm-ppc/poll.h b/include/asm-ppc/poll.h --- a/include/asm-ppc/poll.h Fri Sep 20 08:20:45 2002 +++ b/include/asm-ppc/poll.h Fri Sep 20 08:20:45 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.poll.h 1.5 05/17/01 18:14:25 cort - */ #ifndef __PPC_POLL_H #define __PPC_POLL_H diff -Nru a/include/asm-ppc/posix_types.h b/include/asm-ppc/posix_types.h --- a/include/asm-ppc/posix_types.h Fri Sep 20 08:20:45 2002 +++ b/include/asm-ppc/posix_types.h Fri Sep 20 08:20:45 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef _PPC_POSIX_TYPES_H #define _PPC_POSIX_TYPES_H diff -Nru a/include/asm-ppc/ppc4xx_pic.h b/include/asm-ppc/ppc4xx_pic.h --- a/include/asm-ppc/ppc4xx_pic.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/ppc4xx_pic.h Fri Sep 20 08:20:44 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * * Copyright (c) 1999 Grant Erickson * diff -Nru a/include/asm-ppc/ppc_asm.h b/include/asm-ppc/ppc_asm.h --- a/include/asm-ppc/ppc_asm.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/ppc_asm.h Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * include/asm-ppc/ppc_asm.h * * Definitions used by various bits of low-level assembly code on PowerPC. diff -Nru a/include/asm-ppc/prep_nvram.h b/include/asm-ppc/prep_nvram.h --- a/include/asm-ppc/prep_nvram.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/prep_nvram.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.prep_nvram.h 1.7 05/17/01 18:14:25 cort - */ -/* * PreP compliant NVRAM access */ diff -Nru a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h --- a/include/asm-ppc/processor.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/processor.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef __ASM_PPC_PROCESSOR_H #define __ASM_PPC_PROCESSOR_H diff -Nru a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h --- a/include/asm-ppc/prom.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/prom.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Definitions for talking to the Open Firmware PROM on * Power Macintosh computers. * diff -Nru a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h --- a/include/asm-ppc/ptrace.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/ptrace.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef _PPC_PTRACE_H #define _PPC_PTRACE_H diff -Nru a/include/asm-ppc/raven.h b/include/asm-ppc/raven.h --- a/include/asm-ppc/raven.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/raven.h Fri Sep 20 08:20:46 2002 @@ -1,8 +1,5 @@ /* - * BK Id: SCCS/s.raven.h 1.7 05/17/01 18:14:25 cort - */ -/* - * asm-ppc/raven.h -- Raven MPIC chip. + * include/asm-ppc/raven.h -- Raven MPIC chip. * * Copyright (C) 1998 Johnnie Peters * diff -Nru a/include/asm-ppc/residual.h b/include/asm-ppc/residual.h --- a/include/asm-ppc/residual.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/residual.h Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.residual.h 1.8 08/09/01 09:11:24 trini - */ /* 7/18/95 */ /*----------------------------------------------------------------------------*/ /* Residual Data header definitions and prototypes */ diff -Nru a/include/asm-ppc/resource.h b/include/asm-ppc/resource.h --- a/include/asm-ppc/resource.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/resource.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.resource.h 1.5 05/17/01 18:14:25 cort - */ #ifndef _PPC_RESOURCE_H #define _PPC_RESOURCE_H diff -Nru a/include/asm-ppc/rwsem.h b/include/asm-ppc/rwsem.h --- a/include/asm-ppc/rwsem.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/rwsem.h Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * include/asm-ppc/rwsem.h: R/W semaphores for PPC using the stuff * in lib/rwsem.c. Adapted largely from include/asm-i386/rwsem.h * by Paul Mackerras . diff -Nru a/include/asm-ppc/scatterlist.h b/include/asm-ppc/scatterlist.h --- a/include/asm-ppc/scatterlist.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/scatterlist.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef _PPC_SCATTERLIST_H #define _PPC_SCATTERLIST_H diff -Nru a/include/asm-ppc/sections.h b/include/asm-ppc/sections.h --- a/include/asm-ppc/sections.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/sections.h Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.sections.h 1.11 09/08/01 15:47:43 paulus - */ #ifdef __KERNEL__ #ifndef _PPC_SECTIONS_H #define _PPC_SECTIONS_H diff -Nru a/include/asm-ppc/segment.h b/include/asm-ppc/segment.h --- a/include/asm-ppc/segment.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/segment.h Fri Sep 20 08:20:44 2002 @@ -1,4 +1 @@ -/* - * BK Id: SCCS/s.segment.h 1.7 05/17/01 18:14:25 cort - */ #include diff -Nru a/include/asm-ppc/semaphore.h b/include/asm-ppc/semaphore.h --- a/include/asm-ppc/semaphore.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/semaphore.h Fri Sep 20 08:20:46 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef _PPC_SEMAPHORE_H #define _PPC_SEMAPHORE_H diff -Nru a/include/asm-ppc/sembuf.h b/include/asm-ppc/sembuf.h --- a/include/asm-ppc/sembuf.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/sembuf.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.sembuf.h 1.5 05/17/01 18:14:25 cort - */ #ifndef _PPC_SEMBUF_H #define _PPC_SEMBUF_H diff -Nru a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h --- a/include/asm-ppc/serial.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/serial.h Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * include/asm-ppc/serial.h */ diff -Nru a/include/asm-ppc/setup.h b/include/asm-ppc/setup.h --- a/include/asm-ppc/setup.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/setup.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.setup.h 1.5 05/17/01 18:14:25 cort - */ #ifdef __KERNEL__ #ifndef _PPC_SETUP_H #define _PPC_SETUP_H diff -Nru a/include/asm-ppc/shmbuf.h b/include/asm-ppc/shmbuf.h --- a/include/asm-ppc/shmbuf.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/shmbuf.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.shmbuf.h 1.5 05/17/01 18:14:25 cort - */ #ifndef _PPC_SHMBUF_H #define _PPC_SHMBUF_H diff -Nru a/include/asm-ppc/shmparam.h b/include/asm-ppc/shmparam.h --- a/include/asm-ppc/shmparam.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/shmparam.h Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.shmparam.h 1.5 05/17/01 18:14:25 cort - */ #ifndef _PPC_SHMPARAM_H #define _PPC_SHMPARAM_H diff -Nru a/include/asm-ppc/sigcontext.h b/include/asm-ppc/sigcontext.h --- a/include/asm-ppc/sigcontext.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/sigcontext.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.sigcontext.h 1.5 05/17/01 18:14:25 cort - */ #ifndef _ASM_PPC_SIGCONTEXT_H #define _ASM_PPC_SIGCONTEXT_H diff -Nru a/include/asm-ppc/siginfo.h b/include/asm-ppc/siginfo.h --- a/include/asm-ppc/siginfo.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/siginfo.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.siginfo.h 1.5 05/17/01 18:14:25 cort - */ #ifndef _PPC_SIGINFO_H #define _PPC_SIGINFO_H diff -Nru a/include/asm-ppc/signal.h b/include/asm-ppc/signal.h --- a/include/asm-ppc/signal.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/signal.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.signal.h 1.5 05/17/01 18:14:25 cort - */ #ifndef _ASMPPC_SIGNAL_H #define _ASMPPC_SIGNAL_H diff -Nru a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h --- a/include/asm-ppc/smp.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/smp.h Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ /* smp.h: PPC specific SMP stuff. * * Original was a copy of sparc smp.h. Now heavily modified diff -Nru a/include/asm-ppc/socket.h b/include/asm-ppc/socket.h --- a/include/asm-ppc/socket.h Fri Sep 20 08:20:45 2002 +++ b/include/asm-ppc/socket.h Fri Sep 20 08:20:45 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.socket.h 1.6 05/17/01 18:14:25 cort - */ #ifndef _ASM_SOCKET_H #define _ASM_SOCKET_H diff -Nru a/include/asm-ppc/sockios.h b/include/asm-ppc/sockios.h --- a/include/asm-ppc/sockios.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/sockios.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.sockios.h 1.5 05/17/01 18:14:25 cort - */ #ifndef _ASM_PPC_SOCKIOS_H #define _ASM_PPC_SOCKIOS_H diff -Nru a/include/asm-ppc/softirq.h b/include/asm-ppc/softirq.h --- a/include/asm-ppc/softirq.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/softirq.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef __ASM_SOFTIRQ_H #define __ASM_SOFTIRQ_H diff -Nru a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h --- a/include/asm-ppc/spinlock.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/spinlock.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef __ASM_SPINLOCK_H #define __ASM_SPINLOCK_H diff -Nru a/include/asm-ppc/stat.h b/include/asm-ppc/stat.h --- a/include/asm-ppc/stat.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/stat.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.stat.h 1.5 05/17/01 18:14:26 cort - */ #ifndef _PPC_STAT_H #define _PPC_STAT_H diff -Nru a/include/asm-ppc/statfs.h b/include/asm-ppc/statfs.h --- a/include/asm-ppc/statfs.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/statfs.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.statfs.h 1.5 05/17/01 18:14:26 cort - */ #ifndef _PPC_STATFS_H #define _PPC_STATFS_H diff -Nru a/include/asm-ppc/string.h b/include/asm-ppc/string.h --- a/include/asm-ppc/string.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/string.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.string.h 1.5 05/17/01 18:14:26 cort - */ #ifndef _PPC_STRING_H_ #define _PPC_STRING_H_ diff -Nru a/include/asm-ppc/system.h b/include/asm-ppc/system.h --- a/include/asm-ppc/system.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc/system.h Fri Sep 20 08:20:45 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Copyright (C) 1999 Cort Dougan */ #ifndef __PPC_SYSTEM_H diff -Nru a/include/asm-ppc/termbits.h b/include/asm-ppc/termbits.h --- a/include/asm-ppc/termbits.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/termbits.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.termbits.h 1.5 05/17/01 18:14:26 cort - */ #ifndef _PPC_TERMBITS_H #define _PPC_TERMBITS_H diff -Nru a/include/asm-ppc/termios.h b/include/asm-ppc/termios.h --- a/include/asm-ppc/termios.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/termios.h Fri Sep 20 08:20:48 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.termios.h 1.8 05/17/01 18:14:26 cort - */ #ifndef _PPC_TERMIOS_H #define _PPC_TERMIOS_H diff -Nru a/include/asm-ppc/time.h b/include/asm-ppc/time.h --- a/include/asm-ppc/time.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/time.h Fri Sep 20 08:20:41 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * Common time prototypes and such for all ppc machines. * * Written by Cort Dougan (cort@fsmlabs.com) to merge diff -Nru a/include/asm-ppc/timex.h b/include/asm-ppc/timex.h --- a/include/asm-ppc/timex.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/timex.h Fri Sep 20 08:20:46 2002 @@ -1,8 +1,5 @@ /* - * BK Id: SCCS/s.timex.h 1.8 08/15/01 22:43:07 paulus - */ -/* - * linux/include/asm-ppc/timex.h + * include/asm-ppc/timex.h * * ppc architecture timex specifications */ diff -Nru a/include/asm-ppc/tlbflush.h b/include/asm-ppc/tlbflush.h --- a/include/asm-ppc/tlbflush.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/tlbflush.h Fri Sep 20 08:20:43 2002 @@ -1,7 +1,4 @@ /* - * BK Id: %F% %I% %G% %U% %#% - */ -/* * include/asm-ppc/tlbflush.h * * This program is free software; you can redistribute it and/or diff -Nru a/include/asm-ppc/traps.h b/include/asm-ppc/traps.h --- a/include/asm-ppc/traps.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/traps.h Fri Sep 20 08:20:47 2002 @@ -1,4 +1 @@ -/* - * BK Id: SCCS/s.traps.h 1.5 05/17/01 18:14:26 cort - */ #include diff -Nru a/include/asm-ppc/types.h b/include/asm-ppc/types.h --- a/include/asm-ppc/types.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/types.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.types.h 1.10 10/15/01 22:51:33 paulus - */ #ifndef _PPC_TYPES_H #define _PPC_TYPES_H diff -Nru a/include/asm-ppc/uaccess.h b/include/asm-ppc/uaccess.h --- a/include/asm-ppc/uaccess.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc/uaccess.h Fri Sep 20 08:20:41 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifdef __KERNEL__ #ifndef _PPC_UACCESS_H #define _PPC_UACCESS_H diff -Nru a/include/asm-ppc/ucontext.h b/include/asm-ppc/ucontext.h --- a/include/asm-ppc/ucontext.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/ucontext.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.ucontext.h 1.5 05/17/01 18:14:26 cort - */ #ifndef _ASMPPC_UCONTEXT_H #define _ASMPPC_UCONTEXT_H diff -Nru a/include/asm-ppc/unaligned.h b/include/asm-ppc/unaligned.h --- a/include/asm-ppc/unaligned.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/unaligned.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.unaligned.h 1.5 05/17/01 18:14:26 cort - */ #ifdef __KERNEL__ #ifndef __PPC_UNALIGNED_H #define __PPC_UNALIGNED_H diff -Nru a/include/asm-ppc/uninorth.h b/include/asm-ppc/uninorth.h --- a/include/asm-ppc/uninorth.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/uninorth.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.uninorth.h 1.13 10/23/01 08:09:35 trini - */ -/* * uninorth.h: definitions for using the "UniNorth" host bridge chip * from Apple. This chip is used on "Core99" machines * diff -Nru a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h --- a/include/asm-ppc/unistd.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc/unistd.h Fri Sep 20 08:20:43 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ #ifndef _ASM_PPC_UNISTD_H_ #define _ASM_PPC_UNISTD_H_ diff -Nru a/include/asm-ppc/user.h b/include/asm-ppc/user.h --- a/include/asm-ppc/user.h Fri Sep 20 08:20:47 2002 +++ b/include/asm-ppc/user.h Fri Sep 20 08:20:47 2002 @@ -1,6 +1,3 @@ -/* - * BK Id: SCCS/s.user.h 1.5 05/17/01 18:14:26 cort - */ #ifdef __KERNEL__ #ifndef _PPC_USER_H #define _PPC_USER_H diff -Nru a/include/asm-ppc/vga.h b/include/asm-ppc/vga.h --- a/include/asm-ppc/vga.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc/vga.h Fri Sep 20 08:20:48 2002 @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.vga.h 1.5 05/17/01 18:14:26 cort - */ -/* * Access to VGA videoram * * (c) 1998 Martin Mares diff -Nru a/include/asm-ppc/xor.h b/include/asm-ppc/xor.h --- a/include/asm-ppc/xor.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc/xor.h Fri Sep 20 08:20:46 2002 @@ -1,4 +1 @@ -/* - * BK Id: SCCS/s.xor.h 1.5 05/17/01 18:14:26 cort - */ #include diff -Nru a/include/asm-ppc64/hardirq.h b/include/asm-ppc64/hardirq.h --- a/include/asm-ppc64/hardirq.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-ppc64/hardirq.h Fri Sep 20 08:20:43 2002 @@ -112,4 +112,6 @@ print_backtrace(_get_SP()); \ } while (0) +#define dump_stack() show_stack() + #endif /* __ASM_HARDIRQ_H */ diff -Nru a/include/asm-ppc64/hw_irq.h b/include/asm-ppc64/hw_irq.h --- a/include/asm-ppc64/hw_irq.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc64/hw_irq.h Fri Sep 20 08:20:46 2002 @@ -16,6 +16,7 @@ #include int timer_interrupt(struct pt_regs *); +extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); #ifdef CONFIG_PPC_ISERIES diff -Nru a/include/asm-ppc64/iSeries/LparData.h b/include/asm-ppc64/iSeries/LparData.h --- a/include/asm-ppc64/iSeries/LparData.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc64/iSeries/LparData.h Fri Sep 20 08:20:41 2002 @@ -17,10 +17,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _PPC_TYPES_H -#include -#endif - #ifndef _LPARDATA_H #define _LPARDATA_H @@ -40,7 +36,6 @@ #include #include #include -#include extern struct LparMap xLparMap; extern struct HvReleaseData hvReleaseData; diff -Nru a/include/asm-ppc64/irq.h b/include/asm-ppc64/irq.h --- a/include/asm-ppc64/irq.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc64/irq.h Fri Sep 20 08:20:48 2002 @@ -51,5 +51,7 @@ return irq; } +#define NR_MASK_WORDS ((NR_IRQS + 63) / 64) + #endif /* _ASM_IRQ_H */ #endif /* __KERNEL__ */ diff -Nru a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h --- a/include/asm-ppc64/machdep.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc64/machdep.h Fri Sep 20 08:20:44 2002 @@ -1,6 +1,6 @@ #ifdef __KERNEL__ -#ifndef _PPC_MACHDEP_H -#define _PPC_MACHDEP_H +#ifndef _PPC64_MACHDEP_H +#define _PPC64_MACHDEP_H /* * This program is free software; you can redistribute it and/or @@ -14,7 +14,6 @@ struct pt_regs; struct pci_bus; -struct pci_dev; struct device_node; struct TceTable; struct rtc_time; @@ -70,30 +69,25 @@ void (*setup_residual)(struct seq_file *m, int cpu_id); /* Optional, may be NULL. */ void (*get_cpuinfo)(struct seq_file *m); - /* Optional, may be NULL. */ - unsigned int (*irq_cannonicalize)(unsigned int irq); + void (*init_IRQ)(void); void (*init_ras_IRQ)(void); int (*get_irq)(struct pt_regs *); - - /* A general init function, called by ppc_init in init/main.c. - May be NULL. */ + + /* Optional, may be NULL. */ void (*init)(void); void (*restart)(char *cmd); void (*power_off)(void); void (*halt)(void); - long (*time_init)(void); /* Optional, may be NULL */ int (*set_rtc_time)(struct rtc_time *); void (*get_rtc_time)(struct rtc_time *); void (*get_boot_time)(struct rtc_time *); - void (*calibrate_decr)(void); - void (*progress)(char *, unsigned short); + void (*calibrate_decr)(void); - unsigned char (*nvram_read_val)(int addr); - void (*nvram_write_val)(int addr, unsigned char val); + void (*progress)(char *, unsigned short); /* Debug interface. Low level I/O to some terminal device */ void (*udbg_putc)(unsigned char c); @@ -101,32 +95,21 @@ int (*udbg_getc_poll)(void); /* PCI interfaces */ - int (*pcibios_read_config)(struct device_node *dn, int where, int size, u32 *val); - int (*pcibios_write_config)(struct device_node *dn, int where, int size, u32 val); + int (*pcibios_read_config)(struct device_node *dn, int where, int size, + u32 *val); + int (*pcibios_write_config)(struct device_node *dn, int where, + int size, u32 val); /* Called after scanning the bus, before allocating * resources */ void (*pcibios_fixup)(void); - /* Called for each PCI bus in the system - * when it's probed - */ + /* Called for each PCI bus in the system + * when it's probed + */ void (*pcibios_fixup_bus)(struct pci_bus *); - /* Called when pci_enable_device() is called (initial=0) or - * when a device with no assigned resource is found (initial=1). - * Returns 0 to allow assignement/enabling of the device - */ - int (*pcibios_enable_device_hook)(struct pci_dev *, int initial); - - void* (*pci_dev_io_base)(unsigned char bus, unsigned char devfn, int physical); - void* (*pci_dev_mem_base)(unsigned char bus, unsigned char devfn); - int (*pci_dev_root_bridge)(unsigned char bus, unsigned char devfn); - - /* this is for modules, since _machine can be a define -- Cort */ - int ppc_machine; - #ifdef CONFIG_SMP /* functions for dealing with other cpus */ struct smp_ops_t smp_ops; @@ -136,7 +119,5 @@ extern struct machdep_calls ppc_md; extern char cmd_line[512]; -extern void setup_pci_ptrs(void); - -#endif /* _PPC_MACHDEP_H */ +#endif /* _PPC64_MACHDEP_H */ #endif /* __KERNEL__ */ diff -Nru a/include/asm-ppc64/mman.h b/include/asm-ppc64/mman.h --- a/include/asm-ppc64/mman.h Fri Sep 20 08:20:45 2002 +++ b/include/asm-ppc64/mman.h Fri Sep 20 08:20:45 2002 @@ -21,6 +21,7 @@ #define MAP_ANONYMOUS 0x20 /* don't use a file */ #define MAP_RENAME MAP_ANONYMOUS /* In SunOS terminology */ #define MAP_NORESERVE 0x40 /* don't reserve swap pages */ +#define MAP_LOCKED 0x80 #define MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define MAP_DENYWRITE 0x0800 /* ETXTBSY */ diff -Nru a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h --- a/include/asm-ppc64/mmzone.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc64/mmzone.h Fri Sep 20 08:20:48 2002 @@ -8,10 +8,11 @@ #define _ASM_MMZONE_H_ #include +#include #ifdef CONFIG_DISCONTIGMEM -extern struct pglist_data *node_data[]; +extern struct pglist_data node_data[]; /* * Following are specific to this numa platform. @@ -21,51 +22,54 @@ extern int numa_cpu_lookup_table[]; extern int numa_memory_lookup_table[]; -#define MAX_NUMNODES 16 #define MAX_MEMORY (1UL << 41) /* 256MB regions */ #define MEMORY_INCREMENT_SHIFT 28 #define MEMORY_INCREMENT (1UL << MEMORY_INCREMENT_SHIFT) -#undef DEBUG_NUMA +#define DEBUG_NUMA static inline int pa_to_nid(unsigned long pa) { - int nid; + int nid; - nid = numa_memory_lookup_table[pa >> MEMORY_INCREMENT_SHIFT]; + nid = numa_memory_lookup_table[pa >> MEMORY_INCREMENT_SHIFT]; #ifdef DEBUG_NUMA - /* the physical address passed in is not in the map for the system */ - if (nid == -1) { - printk("bad address: %lx\n", pa); - BUG(); - } + /* the physical address passed in is not in the map for the system */ + if (nid == -1) { + printk("bad address: %lx\n", pa); + BUG(); + } #endif - return nid; + return nid; } #define pfn_to_nid(pfn) pa_to_nid((pfn) << PAGE_SHIFT) -#define node_startnr(nid) (node_data[nid]->node_start_mapnr) -#define node_size(nid) (node_data[nid]->node_size) -#define node_localnr(pfn, nid) ((pfn) - node_data[nid]->node_start_pfn) +/* + * Return a pointer to the node data for node n. + */ +#define NODE_DATA(nid) (&node_data[nid]) + +#define node_size(nid) (NODE_DATA(nid)->node_size) +#define node_localnr(pfn, nid) ((pfn) - NODE_DATA(nid)->node_start_pfn) #ifdef CONFIG_NUMA static inline int __cpu_to_node(int cpu) { - int node; + int node; - node = numa_cpu_lookup_table[cpu]; + node = numa_cpu_lookup_table[cpu]; #ifdef DEBUG_NUMA - if (node == -1) - BUG(); + if (node == -1) + BUG(); #endif - return node; + return node; } #define numa_node_id() __cpu_to_node(smp_processor_id()) @@ -80,13 +84,9 @@ */ #define kvaddr_to_nid(kaddr) pa_to_nid(__pa(kaddr)) -/* - * Return a pointer to the node data for node n. - */ -#define NODE_DATA(nid) (node_data[nid]) - #define node_mem_map(nid) (NODE_DATA(nid)->node_mem_map) #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) +#define node_end_pfn(nid) (NODE_DATA(nid)->node_end_pfn) #define local_mapnr(kvaddr) \ ( (__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)) @@ -105,12 +105,15 @@ node_localnr(__tmp, pfn_to_nid(__tmp))); \ }) -#define discontigmem_page_to_pfn(p) \ +#define discontigmem_page_to_pfn(p) \ ({ \ struct page *__tmp = p; \ (((__tmp) - page_zone(__tmp)->zone_mem_map) + \ page_zone(__tmp)->zone_start_pfn); \ }) + +/* XXX fix for discontiguous physical memory */ +#define discontigmem_pfn_valid(pfn) ((pfn) < num_physpages) #endif /* CONFIG_DISCONTIGMEM */ #endif /* _ASM_MMZONE_H_ */ diff -Nru a/include/asm-ppc64/numnodes.h b/include/asm-ppc64/numnodes.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ppc64/numnodes.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,6 @@ +#ifndef _ASM_MAX_NUMNODES_H +#define _ASM_MAX_NUMNODES_H + +#define MAX_NUMNODES 16 + +#endif /* _ASM_MAX_NUMNODES_H */ diff -Nru a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h --- a/include/asm-ppc64/page.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc64/page.h Fri Sep 20 08:20:41 2002 @@ -207,13 +207,15 @@ #ifdef CONFIG_DISCONTIGMEM #define page_to_pfn(page) discontigmem_page_to_pfn(page) #define pfn_to_page(pfn) discontigmem_pfn_to_page(pfn) +#define pfn_valid(pfn) discontigmem_pfn_valid(pfn) #else #define pfn_to_page(pfn) (mem_map + (pfn)) #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) +#define pfn_valid(pfn) ((pfn) < max_mapnr) #endif + #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) -#define pfn_valid(pfn) ((pfn) < max_mapnr) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ diff -Nru a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h --- a/include/asm-ppc64/pci-bridge.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc64/pci-bridge.h Fri Sep 20 08:20:41 2002 @@ -57,10 +57,6 @@ unsigned long pci_io_offset; struct pci_ops *ops; - volatile unsigned long *cfg_addr; - volatile unsigned char *cfg_data; - volatile unsigned long *phb_regs; - volatile unsigned long *chip_regs; /* Currently, we limit ourselves to 1 IO range and 3 mem * ranges since the common pci_bus structure can't handle more @@ -68,29 +64,13 @@ struct resource io_resource; struct resource mem_resources[3]; int mem_resource_count; - int global_number; - int local_number; - int system_bus_number; + int global_number; + int local_number; unsigned long buid; unsigned long dma_window_base_cur; unsigned long dma_window_size; }; - -/* This version handles the new Uni-N host bridge, the iobase is now - * a per-device thing. I also added the memory base so PReP can - * be fixed to return 0xc0000000 (I didn't actually implement it) - * - * pci_dev_io_base() returns either a virtual (ioremap'ed) address or - * a physical address. In-kernel clients will use logical while the - * sys_pciconfig_iobase syscall returns a physical one to userland. - */ -void *pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical); -void *pci_dev_mem_base(unsigned char bus, unsigned char devfn); - -/* Returns the root-bridge number (Uni-N number) of a device */ -int pci_dev_root_bridge(unsigned char bus, unsigned char devfn); - /* * pci_device_loc returns the bus number and device/function number * for a device on a PCI bus, given its device_node struct. @@ -98,17 +78,6 @@ */ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, unsigned char *devfn_ptr); - -struct bridge_data { - volatile unsigned int *cfg_addr; - volatile unsigned char *cfg_data; - void *io_base; /* virtual */ - unsigned long io_base_phys; - int bus_number; - int max_bus; - struct bridge_data *next; - struct device_node *node; -}; #endif #endif /* __KERNEL__ */ diff -Nru a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h --- a/include/asm-ppc64/pgtable.h Fri Sep 20 08:20:48 2002 +++ b/include/asm-ppc64/pgtable.h Fri Sep 20 08:20:48 2002 @@ -35,12 +35,7 @@ #define PTRS_PER_PMD (1 << PMD_INDEX_SIZE) #define PTRS_PER_PGD (1 << PGD_INDEX_SIZE) -#if 0 -/* DRENG / PPPBBB This is a compiler bug!!! */ -#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) -#else -#define USER_PTRS_PER_PGD (1024) -#endif +#define USER_PTRS_PER_PGD (TASK_SIZE_USER64 / PGDIR_SIZE) #define FIRST_USER_PGD_NR 0 #define EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \ diff -Nru a/include/asm-ppc64/ppc_asm.h b/include/asm-ppc64/ppc_asm.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ppc64/ppc_asm.h Fri Sep 20 08:20:44 2002 @@ -0,0 +1,227 @@ +/* + * arch/ppc64/kernel/ppc_asm.h + * + * Definitions used by various bits of low-level assembly code on PowerPC. + * + * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * Macros for storing registers into and loading registers from + * exception frames. + */ +#define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) +#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) +#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) +#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) +#define REST_GPR(n, base) ld n,GPR0+8*(n)(base) +#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) +#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) +#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) +#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) + +#define SAVE_FPR(n, base) stfd n,THREAD_FPR0+8*(n)(base) +#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) +#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) +#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base) +#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base) +#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base) +#define REST_FPR(n, base) lfd n,THREAD_FPR0+8*(n)(base) +#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base) +#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base) +#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base) +#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) +#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) + +#define CHECKANYINT(ra,rb) \ + mfspr rb,SPRG3; /* Get Paca address */\ + ld ra,PACALPPACA+LPPACAANYINT(rb); /* Get pending interrupt flags */\ + cmpldi 0,ra,0; + +/* Macros to adjust thread priority for Iseries hardware multithreading */ +#define HMT_LOW or 1,1,1 +#define HMT_MEDIUM or 2,2,2 +#define HMT_HIGH or 3,3,3 + +/* Insert the high 32 bits of the MSR into what will be the new + MSR (via SRR1 and rfid) This preserves the MSR.SF and MSR.ISF + bits. */ + +#define FIX_SRR1(ra, rb) \ + mr rb,ra; \ + mfmsr ra; \ + rldimi ra,rb,0,32 + +#define CLR_TOP32(r) rlwinm (r),(r),0,0,31 /* clear top 32 bits */ + +/* + * LOADADDR( rn, name ) + * loads the address of 'name' into 'rn' + * + * LOADBASE( rn, name ) + * loads the address (less the low 16 bits) of 'name' into 'rn' + * suitable for base+disp addressing + */ +#define LOADADDR(rn,name) \ + lis rn,name##@highest; \ + ori rn,rn,name##@higher; \ + rldicr rn,rn,32,31; \ + oris rn,rn,name##@h; \ + ori rn,rn,name##@l + +#define LOADBASE(rn,name) \ + lis rn,name@highest; \ + ori rn,rn,name@higher; \ + rldicr rn,rn,32,31; \ + oris rn,rn,name@ha + + +#define SET_REG_TO_CONST(reg, value) \ + lis reg,(((value)>>48)&0xFFFF); \ + ori reg,reg,(((value)>>32)&0xFFFF); \ + rldicr reg,reg,32,31; \ + oris reg,reg,(((value)>>16)&0xFFFF); \ + ori reg,reg,((value)&0xFFFF); + +#define SET_REG_TO_LABEL(reg, label) \ + lis reg,(label)@highest; \ + ori reg,reg,(label)@higher; \ + rldicr reg,reg,32,31; \ + oris reg,reg,(label)@h; \ + ori reg,reg,(label)@l; + + +/* PPPBBB - DRENG If KERNELBASE is always 0xC0..., + * Then we can easily do this with one asm insn. -Peter + */ +#define tophys(rd,rs) \ + lis rd,((KERNELBASE>>48)&0xFFFF); \ + rldicr rd,rd,32,31; \ + sub rd,rs,rd + +#define tovirt(rd,rs) \ + lis rd,((KERNELBASE>>48)&0xFFFF); \ + rldicr rd,rd,32,31; \ + add rd,rs,rd + +/* Condition Register Bit Fields */ + +#define cr0 0 +#define cr1 1 +#define cr2 2 +#define cr3 3 +#define cr4 4 +#define cr5 5 +#define cr6 6 +#define cr7 7 + + +/* General Purpose Registers (GPRs) */ + +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + + +/* Floating Point Registers (FPRs) */ + +#define fr0 0 +#define fr1 1 +#define fr2 2 +#define fr3 3 +#define fr4 4 +#define fr5 5 +#define fr6 6 +#define fr7 7 +#define fr8 8 +#define fr9 9 +#define fr10 10 +#define fr11 11 +#define fr12 12 +#define fr13 13 +#define fr14 14 +#define fr15 15 +#define fr16 16 +#define fr17 17 +#define fr18 18 +#define fr19 19 +#define fr20 20 +#define fr21 21 +#define fr22 22 +#define fr23 23 +#define fr24 24 +#define fr25 25 +#define fr26 26 +#define fr27 27 +#define fr28 28 +#define fr29 29 +#define fr30 30 +#define fr31 31 + +#define vr0 0 +#define vr1 1 +#define vr2 2 +#define vr3 3 +#define vr4 4 +#define vr5 5 +#define vr6 6 +#define vr7 7 +#define vr8 8 +#define vr9 9 +#define vr10 10 +#define vr11 11 +#define vr12 12 +#define vr13 13 +#define vr14 14 +#define vr15 15 +#define vr16 16 +#define vr17 17 +#define vr18 18 +#define vr19 19 +#define vr20 20 +#define vr21 21 +#define vr22 22 +#define vr23 23 +#define vr24 24 +#define vr25 25 +#define vr26 26 +#define vr27 27 +#define vr28 28 +#define vr29 29 +#define vr30 30 +#define vr31 31 diff -Nru a/include/asm-ppc64/ppc_asm.tmpl b/include/asm-ppc64/ppc_asm.tmpl --- a/include/asm-ppc64/ppc_asm.tmpl Fri Sep 20 08:20:44 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,115 +0,0 @@ -/* Condition Register Bit Fields */ - -#define cr0 0 -#define cr1 1 -#define cr2 2 -#define cr3 3 -#define cr4 4 -#define cr5 5 -#define cr6 6 -#define cr7 7 - - -/* General Purpose Registers (GPRs) */ - -#define r0 0 -#define r1 1 -#define r2 2 -#define r3 3 -#define r4 4 -#define r5 5 -#define r6 6 -#define r7 7 -#define r8 8 -#define r9 9 -#define r10 10 -#define r11 11 -#define r12 12 -#define r13 13 -#define r14 14 -#define r15 15 -#define r16 16 -#define r17 17 -#define r18 18 -#define r19 19 -#define r20 20 -#define r21 21 -#define r22 22 -#define r23 23 -#define r24 24 -#define r25 25 -#define r26 26 -#define r27 27 -#define r28 28 -#define r29 29 -#define r30 30 -#define r31 31 - - -/* Floating Point Registers (FPRs) */ - -#define fr0 0 -#define fr1 1 -#define fr2 2 -#define fr3 3 -#define fr4 4 -#define fr5 5 -#define fr6 6 -#define fr7 7 -#define fr8 8 -#define fr9 9 -#define fr10 10 -#define fr11 11 -#define fr12 12 -#define fr13 13 -#define fr14 14 -#define fr15 15 -#define fr16 16 -#define fr17 17 -#define fr18 18 -#define fr19 19 -#define fr20 20 -#define fr21 21 -#define fr22 22 -#define fr23 23 -#define fr24 24 -#define fr25 25 -#define fr26 26 -#define fr27 27 -#define fr28 28 -#define fr29 29 -#define fr30 30 -#define fr31 31 - -#define vr0 0 -#define vr1 1 -#define vr2 2 -#define vr3 3 -#define vr4 4 -#define vr5 5 -#define vr6 6 -#define vr7 7 -#define vr8 8 -#define vr9 9 -#define vr10 10 -#define vr11 11 -#define vr12 12 -#define vr13 13 -#define vr14 14 -#define vr15 15 -#define vr16 16 -#define vr17 17 -#define vr18 18 -#define vr19 19 -#define vr20 20 -#define vr21 21 -#define vr22 22 -#define vr23 23 -#define vr24 24 -#define vr25 25 -#define vr26 26 -#define vr27 27 -#define vr28 28 -#define vr29 29 -#define vr30 30 -#define vr31 31 diff -Nru a/include/asm-ppc64/semaphore.h b/include/asm-ppc64/semaphore.h --- a/include/asm-ppc64/semaphore.h Fri Sep 20 08:20:46 2002 +++ b/include/asm-ppc64/semaphore.h Fri Sep 20 08:20:46 2002 @@ -3,7 +3,7 @@ /* * Remove spinlock-based RW semaphores; RW semaphore definitions are - * now in rwsem.h and we use the the generic lib/rwsem.c implementation. + * now in rwsem.h and we use the generic lib/rwsem.c implementation. * Rework semaphores to use atomic_dec_if_positive. * -- Paul Mackerras (paulus@samba.org) */ diff -Nru a/include/asm-ppc64/tlb.h b/include/asm-ppc64/tlb.h --- a/include/asm-ppc64/tlb.h Fri Sep 20 08:20:44 2002 +++ b/include/asm-ppc64/tlb.h Fri Sep 20 08:20:44 2002 @@ -20,6 +20,9 @@ struct free_pte_ctx; static inline void tlb_flush(struct free_pte_ctx *tlb); +/* Avoid pulling in another include just for this */ +#define check_pgt_cache() do { } while (0) + /* Get the generic bits... */ #include @@ -51,16 +54,17 @@ if (pte_val(*ptep) & _PAGE_HASHPTE) { pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0)); if (pte_val(pte) & _PAGE_HASHPTE) { - int local = 0; - - if (tlb->mm->cpu_vm_mask == (1 << cpu)) - local = 1; batch->pte[i] = pte; batch->addr[i] = address; i++; if (i == PPC64_TLB_BATCH_NR) { + int local = 0; + + if (tlb->mm->cpu_vm_mask == (1 << cpu)) + local = 1; + flush_hash_range(tlb->mm->context, i, local); i = 0; } diff -Nru a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h --- a/include/asm-ppc64/unistd.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-ppc64/unistd.h Fri Sep 20 08:20:41 2002 @@ -241,6 +241,9 @@ #define __NR_io_getevents 229 #define __NR_io_submit 230 #define __NR_io_cancel 231 +#define __NR_alloc_hugepages 232 +#define __NR_free_hugepages 233 +#define __NR_exit_group 234 #define __NR(n) #n diff -Nru a/include/asm-sparc/io.h b/include/asm-sparc/io.h --- a/include/asm-sparc/io.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-sparc/io.h Fri Sep 20 08:20:41 2002 @@ -25,38 +25,17 @@ /* * Memory mapped I/O to PCI + * + * Observe that ioremap returns void* cookie, but accessors, such + * as readb, take unsigned long as address, by API. This mismatch + * happened historically. The ioremap is much older than accessors, + * so at one time ioremap's cookie was used as address (*a = val). + * When accessors came about, they were designed to be compatible across + * buses, so that drivers can select proper ones like sunhme.c did. + * To make that easier, they use same aruments (ulong) for sbus, pci, isa. + * The offshot is, we must cast readb et. al. arguments with a #define. */ -static __inline__ u8 readb(unsigned long addr) -{ - return *(volatile u8 *)addr; -} -static __inline__ u16 readw(unsigned long addr) -{ - return flip_word(*(volatile u16 *)addr); -} - -static __inline__ u32 readl(unsigned long addr) -{ - return flip_dword(*(volatile u32 *)addr); -} - -static __inline__ void writeb(u8 b, unsigned long addr) -{ - *(volatile u8 *)addr = b; -} - -static __inline__ void writew(u16 b, unsigned long addr) -{ - *(volatile u16 *)addr = flip_word(b); -} - -static __inline__ void writel(u32 b, unsigned long addr) -{ - *(volatile u32 *)addr = flip_dword(b); -} - -/* Now the 'raw' versions. */ static __inline__ u8 __raw_readb(unsigned long addr) { return *(volatile u8 *)addr; @@ -87,6 +66,14 @@ *(volatile u32 *)addr = b; } +#define readb(addr) (*(volatile u8 *)(addr)) +#define readw(addr) flip_word(*(volatile u16 *)(addr)) +#define readl(addr) flip_dword(*(volatile u32 *)(addr)) + +#define writeb(b, a) (*(volatile u8 *)(a) = b) +#define writew(b, a) (*(volatile u16 *)(a) = flip_word(b)) +#define writel(b, a) (*(volatile u32 *)(a) = flip_dword(b)) + /* * I/O space operations * @@ -163,7 +150,6 @@ /* * The only reason for #define's is to hide casts to unsigned long. - * XXX Rewrite drivers without structures for registers. */ #define sbus_readb(a) _sbus_readb((unsigned long)(a)) #define sbus_readw(a) _sbus_readw((unsigned long)(a)) @@ -193,13 +179,11 @@ #define ioremap_nocache(X,Y) ioremap((X),(Y)) extern void iounmap(void *addr); -/* P3: talk davem into dropping "name" argument in favor of res->name */ /* * Bus number may be in res->flags... somewhere. */ extern unsigned long sbus_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); -/* XXX Partial deallocations? I think not! */ extern void sbus_iounmap(unsigned long vaddr, unsigned long size); @@ -215,7 +199,7 @@ #define RTC_ALWAYS_BCD 0 /* Nothing to do */ -/* P3: Only IDE DMA may need these. */ +/* P3: Only IDE DMA may need these. XXX Verify that it still does... */ #define dma_cache_inv(_start,_size) do { } while (0) #define dma_cache_wback(_start,_size) do { } while (0) diff -Nru a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h --- a/include/asm-sparc/unistd.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-sparc/unistd.h Fri Sep 20 08:20:41 2002 @@ -249,8 +249,8 @@ #define __NR_time 231 /* Linux Specific */ /* #define __NR_oldstat 232 Linux Specific */ #define __NR_stime 233 /* Linux Specific */ -/* #define __NR_oldfstat 234 Linux Specific */ -/* #define __NR_phys 235 Linux Specific */ +#define __NR_alloc_hugepages 234 /* Linux Specific */ +#define __NR_free_hugepages 235 /* Linux Specific */ #define __NR__llseek 236 /* Linux Specific */ #define __NR_mlock 237 #define __NR_munlock 238 diff -Nru a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h --- a/include/asm-sparc64/page.h Fri Sep 20 08:20:45 2002 +++ b/include/asm-sparc64/page.h Fri Sep 20 08:20:45 2002 @@ -3,6 +3,8 @@ #ifndef _SPARC64_PAGE_H #define _SPARC64_PAGE_H +#include + #define PAGE_SHIFT 13 #ifndef __ASSEMBLY__ /* I have my suspicions... -DaveM */ @@ -98,6 +100,14 @@ #define __iopgprot(x) (x) #endif /* (STRICT_MM_TYPECHECKS) */ + +#define HPAGE_SHIFT 22 + +#ifdef CONFIG_HUGETLB_PAGE +#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT) +#define HPAGE_MASK (~(HPAGE_SIZE - 1UL)) +#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) +#endif #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_32BIT) ? \ (0x0000000070000000UL) : (PAGE_OFFSET)) diff -Nru a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h --- a/include/asm-sparc64/system.h Fri Sep 20 08:20:41 2002 +++ b/include/asm-sparc64/system.h Fri Sep 20 08:20:41 2002 @@ -152,24 +152,6 @@ #define task_running(rq, p) \ ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock)) -#ifndef CONFIG_DEBUG_SPINLOCK -#define CHECK_LOCKS(PREV) do { } while(0) -#else /* CONFIG_DEBUG_SPINLOCK */ -#define CHECK_LOCKS(PREV) \ -if ((PREV)->thread.smp_lock_count) { \ - unsigned long rpc; \ - __asm__ __volatile__("mov %%i7, %0" : "=r" (rpc)); \ - printk(KERN_CRIT "(%s)[%d]: Sleeping with %d locks held!\n", \ - (PREV)->comm, (PREV)->pid, \ - (PREV)->thread.smp_lock_count); \ - printk(KERN_CRIT "(%s)[%d]: Last lock at %08x\n", \ - (PREV)->comm, (PREV)->pid, \ - (PREV)->thread.smp_lock_pc); \ - printk(KERN_CRIT "(%s)[%d]: Sched caller %016lx\n", \ - (PREV)->comm, (PREV)->pid, rpc); \ -} -#endif /* !(CONFIG_DEBUG_SPINLOCK) */ - /* See what happens when you design the chip correctly? * * We tell gcc we clobber all non-fixed-usage registers except @@ -180,8 +162,7 @@ * and 2 stores in this critical code path. -DaveM */ #define switch_to(prev, next, last) \ -do { CHECK_LOCKS(prev); \ - if (test_thread_flag(TIF_PERFCTR)) { \ +do { if (test_thread_flag(TIF_PERFCTR)) { \ unsigned long __tmp; \ read_pcr(__tmp); \ current_thread_info()->pcr_reg = __tmp; \ diff -Nru a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h --- a/include/asm-sparc64/unistd.h Fri Sep 20 08:20:43 2002 +++ b/include/asm-sparc64/unistd.h Fri Sep 20 08:20:43 2002 @@ -251,8 +251,8 @@ #endif /* #define __NR_oldstat 232 Linux Specific */ #define __NR_stime 233 /* Linux Specific */ -/* #define __NR_oldfstat 234 Linux Specific */ -/* #define __NR_phys 235 Linux Specific */ +#define __NR_alloc_hugepages 234 /* Linux Specific */ +#define __NR_free_hugepages 235 /* Linux Specific */ #define __NR__llseek 236 /* Linux Specific */ #define __NR_mlock 237 #define __NR_munlock 238 diff -Nru a/include/linux/acpi.h b/include/linux/acpi.h --- a/include/linux/acpi.h Fri Sep 20 08:20:41 2002 +++ b/include/linux/acpi.h Fri Sep 20 08:20:41 2002 @@ -106,6 +106,15 @@ u64 entry[1]; } __attribute__ ((packed)); +/* Fixed ACPI Description Table (FADT) */ + +struct acpi_table_fadt { + struct acpi_table_header header; + u32 facs_addr; + u32 dsdt_addr; + /* ... */ +} __attribute__ ((packed)); + /* Multiple APIC Description Table (MADT) */ struct acpi_table_madt { @@ -314,7 +323,7 @@ ACPI_DSDT, ACPI_ECDT, ACPI_ETDT, - ACPI_FACP, + ACPI_FADT, ACPI_FACS, ACPI_OEMX, ACPI_PSDT, @@ -340,6 +349,7 @@ int acpi_table_init (char *cmdline); int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler); +int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header); int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler); int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler); void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); @@ -391,9 +401,8 @@ #ifdef CONFIG_ACPI -int acpi_init(void); +int acpi_blacklisted(void); #endif /*CONFIG_ACPI*/ - #endif /*_LINUX_ACPI_H*/ diff -Nru a/include/linux/bio.h b/include/linux/bio.h --- a/include/linux/bio.h Fri Sep 20 08:20:47 2002 +++ b/include/linux/bio.h Fri Sep 20 08:20:47 2002 @@ -37,8 +37,9 @@ #define BIO_BUG_ON #endif -#define BIO_MAX_SECTORS 128 -#define BIO_MAX_SIZE (BIO_MAX_SECTORS << 9) +#define BIO_MAX_PAGES (256) +#define BIO_MAX_SIZE (BIO_MAX_PAGES << PAGE_CACHE_SHIFT) +#define BIO_MAX_SECTORS (BIO_MAX_SIZE >> 9) /* * was unsigned short, but we might as well be ready for > 64kB I/O pages @@ -50,7 +51,7 @@ }; struct bio; -typedef void (bio_end_io_t) (struct bio *); +typedef int (bio_end_io_t) (struct bio *, unsigned int, int); typedef void (bio_destructor_t) (struct bio *); /* @@ -101,6 +102,7 @@ #define BIO_EOF 2 /* out-out-bounds error */ #define BIO_SEG_VALID 3 /* nr_hw_seg valid */ #define BIO_CLONED 4 /* doesn't own data */ +#define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag))) /* * bio bi_rw flags @@ -123,7 +125,7 @@ #define bio_offset(bio) bio_iovec((bio))->bv_offset #define bio_sectors(bio) ((bio)->bi_size >> 9) #define bio_data(bio) (page_address(bio_page((bio))) + bio_offset((bio))) -#define bio_barrier(bio) ((bio)->bi_rw & (1 << BIO_BARRIER)) +#define bio_barrier(bio) ((bio)->bi_rw & (1 << BIO_RW_BARRIER)) /* * will die @@ -159,7 +161,7 @@ #define BIO_SEG_BOUNDARY(q, b1, b2) \ BIOVEC_SEG_BOUNDARY((q), __BVEC_END((b1)), __BVEC_START((b2))) -#define bio_io_error(bio) bio_endio((bio), 0) +#define bio_io_error(bio, bytes) bio_endio((bio), (bytes), -EIO) /* * drivers should not use the __ version unless they _really_ want to @@ -192,7 +194,7 @@ extern struct bio *bio_alloc(int, int); extern void bio_put(struct bio *); -extern void bio_endio(struct bio *, int); +extern int bio_endio(struct bio *, unsigned int, int); struct request_queue; extern inline int bio_phys_segments(struct request_queue *, struct bio *); extern inline int bio_hw_segments(struct request_queue *, struct bio *); @@ -202,6 +204,8 @@ extern struct bio *bio_copy(struct bio *, int, int); extern inline void bio_init(struct bio *); + +extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int); #ifdef CONFIG_HIGHMEM /* diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h --- a/include/linux/blkdev.h Fri Sep 20 08:20:43 2002 +++ b/include/linux/blkdev.h Fri Sep 20 08:20:43 2002 @@ -120,6 +120,9 @@ typedef int (prep_rq_fn) (request_queue_t *, struct request *); typedef void (unplug_fn) (void *q); +struct bio_vec; +typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *); + enum blk_queue_state { Queue_down, Queue_up, @@ -163,6 +166,7 @@ make_request_fn *make_request_fn; prep_rq_fn *prep_rq_fn; unplug_fn *unplug_fn; + merge_bvec_fn *merge_bvec_fn; struct backing_dev_info backing_dev_info; diff -Nru a/include/linux/buffer_head.h b/include/linux/buffer_head.h --- a/include/linux/buffer_head.h Fri Sep 20 08:20:41 2002 +++ b/include/linux/buffer_head.h Fri Sep 20 08:20:41 2002 @@ -167,6 +167,8 @@ struct buffer_head *alloc_buffer_head(void); void free_buffer_head(struct buffer_head * bh); void FASTCALL(unlock_buffer(struct buffer_head *bh)); +void ll_rw_block(int, int, struct buffer_head * bh[]); +int submit_bh(int, struct buffer_head *); extern int buffer_heads_over_limit; /* diff -Nru a/include/linux/cyclades.h b/include/linux/cyclades.h --- a/include/linux/cyclades.h Fri Sep 20 08:20:48 2002 +++ b/include/linux/cyclades.h Fri Sep 20 08:20:48 2002 @@ -503,6 +503,7 @@ #endif /* Per card data structure */ +struct resource; struct cyclades_card { unsigned long base_phys; unsigned long ctl_phys; @@ -514,10 +515,13 @@ int nports; /* Number of ports in the card */ int bus_index; /* address shift - 0 for ISA, 1 for PCI */ int intr_enabled; /* FW Interrupt flag - 0 disabled, 1 enabled */ + struct resource *resource; + unsigned long res_start; + unsigned long res_len; #ifdef __KERNEL__ spinlock_t card_lock; #else - uclong filler; + unsigned long filler; #endif }; diff -Nru a/include/linux/device.h b/include/linux/device.h --- a/include/linux/device.h Fri Sep 20 08:20:47 2002 +++ b/include/linux/device.h Fri Sep 20 08:20:47 2002 @@ -65,7 +65,8 @@ struct driver_dir_entry device_dir; struct driver_dir_entry driver_dir; - int (*match) (struct device * dev, struct device_driver * drv); + int (*match)(struct device * dev, struct device_driver * drv); + struct device * (*add) (struct device * parent, char * bus_id); }; @@ -281,6 +282,8 @@ void *driver_data; /* data private to the driver */ u32 class_num; /* class-enumerated value */ + void * class_data; /* class-specific data */ + void *platform_data; /* Platform specific data (e.g. ACPI, BIOS data relevant to device) */ @@ -377,6 +380,9 @@ /* drivers/base/sys.c */ extern int register_sys_device(struct device * dev); extern void unregister_sys_device(struct device * dev); + +/* drivers/base/platform.c */ +extern struct bus_type platform_bus; /* drivers/base/power.c */ extern int device_suspend(u32 state, u32 level); diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Fri Sep 20 08:20:44 2002 +++ b/include/linux/fs.h Fri Sep 20 08:20:44 2002 @@ -279,6 +279,7 @@ */ struct page; struct address_space; +struct writeback_control; struct address_space_operations { int (*writepage)(struct page *); @@ -286,10 +287,10 @@ int (*sync_page)(struct page *); /* Write back some dirty pages from this mapping. */ - int (*writepages)(struct address_space *, int *nr_to_write); + int (*writepages)(struct address_space *, struct writeback_control *); /* Perform a writeback as a memory-freeing operation. */ - int (*vm_writeback)(struct page *, int *nr_to_write); + int (*vm_writeback)(struct page *, struct writeback_control *); /* Set a page dirty */ int (*set_page_dirty)(struct page *page); @@ -1231,8 +1232,6 @@ extern struct file * get_empty_filp(void); extern void file_move(struct file *f, struct list_head *list); -extern void ll_rw_block(int, int, struct buffer_head * bh[]); -extern int submit_bh(int, struct buffer_head *); struct bio; extern int submit_bio(int, struct bio *); extern int bdev_read_only(struct block_device *); @@ -1261,7 +1260,8 @@ extern loff_t remote_llseek(struct file *file, loff_t offset, int origin); extern int generic_file_open(struct inode * inode, struct file * filp); -extern int generic_vm_writeback(struct page *page, int *nr_to_write); +extern int generic_vm_writeback(struct page *page, + struct writeback_control *wbc); extern struct file_operations generic_ro_fops; diff -Nru a/include/linux/gfp.h b/include/linux/gfp.h --- a/include/linux/gfp.h Fri Sep 20 08:20:43 2002 +++ b/include/linux/gfp.h Fri Sep 20 08:20:43 2002 @@ -39,18 +39,25 @@ * can allocate highmem pages, the *get*page*() variants return * virtual kernel addresses to the allocated page(s). */ -extern struct page * FASTCALL(_alloc_pages(unsigned int gfp_mask, unsigned int order)); extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, struct zonelist *zonelist)); extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order); +/* + * We get the zone list from the current node and the gfp_mask. + * This zone list contains a maximum of MAXNODES*MAX_NR_ZONES zones. + * + * For the normal case of non-DISCONTIGMEM systems the NODE_DATA() gets + * optimized to &contig_page_data at compile-time. + */ static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order) { - /* - * Gets optimized away by the compiler. - */ - if (order >= MAX_ORDER) + pg_data_t *pgdat = NODE_DATA(numa_node_id()); + unsigned int idx = (gfp_mask & GFP_ZONEMASK); + + if (unlikely(order >= MAX_ORDER)) return NULL; - return _alloc_pages(gfp_mask, order); + + return __alloc_pages(gfp_mask, order, pgdat->node_zonelists + idx); } #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) diff -Nru a/include/linux/hdlc.h b/include/linux/hdlc.h --- a/include/linux/hdlc.h Fri Sep 20 08:20:48 2002 +++ b/include/linux/hdlc.h Fri Sep 20 08:20:48 2002 @@ -12,14 +12,16 @@ #ifndef __HDLC_H #define __HDLC_H -#define CLOCK_DEFAULT 0 /* Default (current) setting */ +#define GENERIC_HDLC_VERSION 3 /* For synchronization with sethdlc utility */ + +#define CLOCK_DEFAULT 0 /* Default setting */ #define CLOCK_EXT 1 /* External TX and RX clock - DTE */ #define CLOCK_INT 2 /* Internal TX and RX clock - DCE */ #define CLOCK_TXINT 3 /* Internal TX and external RX clock */ #define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */ -#define ENCODING_DEFAULT 0 /* Default (current) setting */ +#define ENCODING_DEFAULT 0 /* Default setting */ #define ENCODING_NRZ 1 #define ENCODING_NRZI 2 #define ENCODING_FM_MARK 3 @@ -27,7 +29,7 @@ #define ENCODING_MANCHESTER 5 -#define PARITY_DEFAULT 0 /* Default (current) setting */ +#define PARITY_DEFAULT 0 /* Default setting */ #define PARITY_NONE 1 /* No parity */ #define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */ #define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */ @@ -36,13 +38,11 @@ #define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */ #define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */ -#define LMI_DEFAULT 0 /* Default (current) setting */ +#define LMI_DEFAULT 0 /* Default setting */ #define LMI_NONE 1 /* No LMI, all PVCs are static */ #define LMI_ANSI 2 /* ANSI Annex D */ #define LMI_CCITT 3 /* ITU-T Annex A */ -/* PPP doesn't need any info now - supply length = 0 to ioctl */ - #ifdef __KERNEL__ @@ -178,7 +178,7 @@ int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); int (*open)(struct hdlc_device_struct *hdlc); void (*stop)(struct hdlc_device_struct *hdlc); - void (*detach)(struct hdlc_device_struct *hdlc); + void (*proto_detach)(struct hdlc_device_struct *hdlc); void (*netif_rx)(struct sk_buff *skb); int proto; /* IF_PROTO_HDLC/CISCO/FR/etc. */ @@ -337,11 +337,11 @@ /* May be used by hardware driver to gain control over HDLC device */ -static __inline__ void hdlc_detach(hdlc_device *hdlc) +static __inline__ void hdlc_proto_detach(hdlc_device *hdlc) { - if (hdlc->detach) - hdlc->detach(hdlc); - hdlc->detach = NULL; + if (hdlc->proto_detach) + hdlc->proto_detach(hdlc); + hdlc->proto_detach = NULL; } diff -Nru a/include/linux/ide.h b/include/linux/ide.h --- a/include/linux/ide.h Fri Sep 20 08:20:44 2002 +++ b/include/linux/ide.h Fri Sep 20 08:20:44 2002 @@ -1753,6 +1753,7 @@ extern u8 ide_rate_filter(u8 mode, u8 speed); extern int ide_dma_enable(ide_drive_t *drive); extern char *ide_xfer_verbose(u8 xfer_rate); +extern void ide_toggle_bounce(ide_drive_t *drive, int on); extern spinlock_t ide_lock; diff -Nru a/include/linux/if_bridge.h b/include/linux/if_bridge.h --- a/include/linux/if_bridge.h Fri Sep 20 08:20:46 2002 +++ b/include/linux/if_bridge.h Fri Sep 20 08:20:46 2002 @@ -102,7 +102,8 @@ struct net_bridge_port; extern int (*br_ioctl_hook)(unsigned long arg); -extern void (*br_handle_frame_hook)(struct sk_buff *skb); +extern int (*br_handle_frame_hook)(struct sk_buff *skb); +extern int (*br_should_route_hook)(struct sk_buff **pskb); #endif diff -Nru a/include/linux/list.h b/include/linux/list.h --- a/include/linux/list.h Fri Sep 20 08:20:41 2002 +++ b/include/linux/list.h Fri Sep 20 08:20:41 2002 @@ -195,6 +195,10 @@ #define list_for_each(pos, head) \ for (pos = (head)->next, prefetch(pos->next); pos != (head); \ pos = pos->next, prefetch(pos->next)) + +#define list_for_each_noprefetch(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop counter. diff -Nru a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h --- a/include/linux/lockd/lockd.h Fri Sep 20 08:20:43 2002 +++ b/include/linux/lockd/lockd.h Fri Sep 20 08:20:43 2002 @@ -42,8 +42,8 @@ struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ char h_name[20]; /* remote hostname */ u32 h_version; /* interface version */ + rpc_authflavor_t h_authflavor; /* RPC authentication type */ unsigned short h_proto; /* transport proto */ - unsigned short h_authflavor; /* RPC authentication type */ unsigned short h_reclaiming : 1, h_server : 1, /* server side, not client side */ h_inuse : 1, diff -Nru a/include/linux/mm.h b/include/linux/mm.h --- a/include/linux/mm.h Fri Sep 20 08:20:41 2002 +++ b/include/linux/mm.h Fri Sep 20 08:20:41 2002 @@ -15,7 +15,10 @@ #include #include +#ifndef CONFIG_DISCONTIGMEM /* Don't use mapnrs, do it properly */ extern unsigned long max_mapnr; +#endif + extern unsigned long num_physpages; extern void * high_memory; extern int page_cluster; @@ -345,8 +348,10 @@ #define VM_FAULT_MINOR 1 #define VM_FAULT_MAJOR 2 -/* The array of struct pages */ +#ifndef CONFIG_DISCONTIGMEM +/* The array of struct pages - for discontigmem use pgdat->lmem_map */ extern struct page *mem_map; +#endif extern void show_free_areas(void); @@ -431,10 +436,7 @@ extern int remove_exclusive_swap_page(struct page *); /* mmap.c */ -extern void lock_vma_mappings(struct vm_area_struct *); -extern void unlock_vma_mappings(struct vm_area_struct *); extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *); -extern void __insert_vm_struct(struct mm_struct *, struct vm_area_struct *); extern void build_mmap_rb(struct mm_struct *); extern void exit_mmap(struct mm_struct *); @@ -504,6 +506,8 @@ extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr); extern struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr, struct vm_area_struct **pprev); +extern int split_vma(struct mm_struct * mm, struct vm_area_struct * vma, + unsigned long addr, int new_below); /* Look up the first VMA which intersects the interval start_addr..end_addr-1, NULL if none. Assume start_addr < end_addr. */ diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h --- a/include/linux/mmzone.h Fri Sep 20 08:20:41 2002 +++ b/include/linux/mmzone.h Fri Sep 20 08:20:41 2002 @@ -10,11 +10,14 @@ #include #include #include +#ifdef CONFIG_DISCONTIGMEM +#include +#endif +#ifndef MAX_NUMNODES +#define MAX_NUMNODES 1 +#endif -/* - * Free memory management - zoned buddy allocator. - */ - +/* Free memory management - zoned buddy allocator. */ #ifndef CONFIG_FORCE_MAX_ZONEORDER #define MAX_ORDER 11 #else @@ -112,7 +115,6 @@ struct page *zone_mem_map; /* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */ unsigned long zone_start_pfn; - unsigned long zone_start_mapnr; /* * rarely used fields: @@ -138,7 +140,7 @@ * footprint of this construct is very small. */ struct zonelist { - struct zone *zones[MAX_NR_ZONES+1]; // NULL delimited + struct zone *zones[MAX_NUMNODES * MAX_NR_ZONES + 1]; // NULL delimited }; #define GFP_ZONEMASK 0x0f @@ -163,7 +165,6 @@ unsigned long *valid_addr_bitmap; struct bootmem_data *bdata; unsigned long node_start_pfn; - unsigned long node_start_mapnr; unsigned long node_size; int node_id; struct pglist_data *pgdat_next; @@ -187,10 +188,12 @@ * prototypes for the discontig memory code. */ struct page; -void free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap, - unsigned long *zones_size, unsigned long paddr, unsigned long *zholes_size, - struct page *pmap); +extern void calculate_totalpages (pg_data_t *pgdat, unsigned long *zones_size, + unsigned long *zholes_size); +extern void free_area_init_core(pg_data_t *pgdat, unsigned long *zones_size, + unsigned long *zholes_size); void get_zone_counts(unsigned long *active, unsigned long *inactive); +extern void build_all_zonelists(void); extern pg_data_t contig_page_data; diff -Nru a/include/linux/mpage.h b/include/linux/mpage.h --- a/include/linux/mpage.h Fri Sep 20 08:20:44 2002 +++ b/include/linux/mpage.h Fri Sep 20 08:20:44 2002 @@ -10,14 +10,16 @@ * nested includes. Get it right in the .c file). */ +struct writeback_control; + int mpage_readpages(struct address_space *mapping, struct list_head *pages, unsigned nr_pages, get_block_t get_block); int mpage_readpage(struct page *page, get_block_t get_block); int mpage_writepages(struct address_space *mapping, - int *nr_to_write, get_block_t get_block); + struct writeback_control *wbc, get_block_t get_block); static inline int -generic_writepages(struct address_space *mapping, int *nr_to_write) +generic_writepages(struct address_space *mapping, struct writeback_control *wbc) { - return mpage_writepages(mapping, nr_to_write, NULL); + return mpage_writepages(mapping, wbc, NULL); } diff -Nru a/include/linux/nbd.h b/include/linux/nbd.h --- a/include/linux/nbd.h Fri Sep 20 08:20:47 2002 +++ b/include/linux/nbd.h Fri Sep 20 08:20:47 2002 @@ -59,7 +59,7 @@ blk_finished_io(nsect); req->bio = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, uptodate); + bio_endio(bio, nsect << 9, uptodate ? 0 : -EIO); } blk_put_request(req); spin_unlock_irqrestore(q->queue_lock, flags); diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h --- a/include/linux/netdevice.h Fri Sep 20 08:20:48 2002 +++ b/include/linux/netdevice.h Fri Sep 20 08:20:48 2002 @@ -691,6 +691,8 @@ NETIF_MSG_TX_DONE = 0x0400, NETIF_MSG_RX_STATUS = 0x0800, NETIF_MSG_PKTDATA = 0x1000, + NETIF_MSG_HW = 0x2000, + NETIF_MSG_WOL = 0x4000, }; #define netif_msg_drv(p) ((p)->msg_enable & NETIF_MSG_DRV) @@ -706,6 +708,8 @@ #define netif_msg_tx_done(p) ((p)->msg_enable & NETIF_MSG_TX_DONE) #define netif_msg_rx_status(p) ((p)->msg_enable & NETIF_MSG_RX_STATUS) #define netif_msg_pktdata(p) ((p)->msg_enable & NETIF_MSG_PKTDATA) +#define netif_msg_hw(p) ((p)->msg_enable & NETIF_MSG_HW) +#define netif_msg_wol(p) ((p)->msg_enable & NETIF_MSG_WOL) /* Schedule rx intr now? */ diff -Nru a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h --- a/include/linux/netfilter_bridge.h Fri Sep 20 08:20:46 2002 +++ b/include/linux/netfilter_bridge.h Fri Sep 20 08:20:46 2002 @@ -18,7 +18,18 @@ #define NF_BR_LOCAL_OUT 3 /* Packets about to hit the wire. */ #define NF_BR_POST_ROUTING 4 -#define NF_BR_NUMHOOKS 5 +/* Not really a hook, but used for the ebtables broute table */ +#define NF_BR_BROUTING 5 +#define NF_BR_NUMHOOKS 6 +enum nf_br_hook_priorities { + NF_BR_PRI_FIRST = INT_MIN, + NF_BR_PRI_FILTER_BRIDGED = -200, + NF_BR_PRI_FILTER_OTHER = 200, + NF_BR_PRI_NAT_DST_BRIDGED = -300, + NF_BR_PRI_NAT_DST_OTHER = 100, + NF_BR_PRI_NAT_SRC = 300, + NF_BR_PRI_LAST = INT_MAX, +}; #endif diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h --- a/include/linux/page-flags.h Fri Sep 20 08:20:47 2002 +++ b/include/linux/page-flags.h Fri Sep 20 08:20:47 2002 @@ -79,6 +79,7 @@ unsigned long nr_page_table_pages; unsigned long nr_reverse_maps; unsigned long nr_mapped; + unsigned long nr_slab; } ____cacheline_aligned_in_smp page_states[NR_CPUS]; extern void get_page_state(struct page_state *ret); diff -Nru a/include/linux/percpu.h b/include/linux/percpu.h --- a/include/linux/percpu.h Fri Sep 20 08:20:47 2002 +++ b/include/linux/percpu.h Fri Sep 20 08:20:47 2002 @@ -3,7 +3,8 @@ #include /* For preempt_disable() */ #include -#define get_cpu_var(var) ({ preempt_disable(); __get_cpu_var(var); }) +/* Must be an lvalue. */ +#define get_cpu_var(var) (*({ preempt_disable(); &__get_cpu_var(var); })) #define put_cpu_var(var) preempt_enable() #endif /* __LINUX_PERCPU_H */ diff -Nru a/include/linux/pid.h b/include/linux/pid.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/pid.h Fri Sep 20 08:20:49 2002 @@ -0,0 +1,63 @@ +#ifndef _LINUX_PID_H +#define _LINUX_PID_H + +enum pid_type +{ + PIDTYPE_PID, + PIDTYPE_PGID, + PIDTYPE_SID, + PIDTYPE_MAX +}; + +struct pid +{ + int nr; + atomic_t count; + struct task_struct *task; + struct list_head task_list; + struct list_head hash_chain; +}; + +struct pid_link +{ + struct list_head pid_chain; + struct pid *pidptr; + struct pid pid; +}; + +#define pid_task(elem, type) \ + list_entry(elem, struct task_struct, pids[type].pid_chain) + +/* + * attach_pid() must be called with the tasklist_lock write-held. + * + * It might unlock the tasklist_lock for allocation, so this + * function must be called after installing all other links of + * a new task. + */ +extern int FASTCALL(attach_pid(struct task_struct *, enum pid_type, int)); + +/* + * detach_pid() must be called with the tasklist_lock write-held. + */ +extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type)); + +/* + * look up a PID in the hash table. Must be called with the tasklist_lock + * held. + */ +extern struct pid *FASTCALL(find_pid(enum pid_type, int)); + +extern int alloc_pidmap(void); +extern void FASTCALL(free_pidmap(int)); + +#define for_each_task_pid(who, type, task, elem, pid) \ + if ((pid = find_pid(type, who))) \ + for (elem = pid->task_list.next, \ + prefetch(elem->next), \ + task = pid_task(elem, type); \ + elem != &pid->task_list; \ + elem = elem->next, prefetch(elem->next), \ + task = pid_task(elem, type)) + +#endif /* _LINUX_PID_H */ diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Fri Sep 20 08:20:41 2002 +++ b/include/linux/sched.h Fri Sep 20 08:20:41 2002 @@ -28,6 +28,7 @@ #include #include #include +#include struct exec_domain; @@ -266,6 +267,8 @@ atomic_inc(&__user->__count); \ __user; }) +extern struct user_struct *find_user(uid_t); + extern struct user_struct root_user; #define INIT_USER (&root_user) @@ -326,9 +329,8 @@ struct task_struct *group_leader; struct list_head thread_group; - /* PID hash table linkage. */ - struct task_struct *pidhash_next; - struct task_struct **pidhash_pprev; + /* PID/PID hash table linkage. */ + struct pid_link pids[PIDTYPE_MAX]; wait_queue_head_t wait_chldexit; /* for wait4() */ struct completion *vfork_done; /* for vfork() */ @@ -474,38 +476,7 @@ extern struct mm_struct init_mm; -/* PID hashing. (shouldnt this be dynamic?) */ -#define PIDHASH_SZ 8192 -extern struct task_struct *pidhash[PIDHASH_SZ]; - -#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) - -static inline void hash_pid(struct task_struct *p) -{ - struct task_struct **htable = &pidhash[pid_hashfn(p->pid)]; - - if((p->pidhash_next = *htable) != NULL) - (*htable)->pidhash_pprev = &p->pidhash_next; - *htable = p; - p->pidhash_pprev = htable; -} - -static inline void unhash_pid(struct task_struct *p) -{ - if(p->pidhash_next) - p->pidhash_next->pidhash_pprev = p->pidhash_pprev; - *p->pidhash_pprev = p->pidhash_next; -} - -static inline struct task_struct *find_task_by_pid(int pid) -{ - struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)]; - - for(p = *htable; p && p->pid != pid; p = p->pidhash_next) - ; - - return p; -} +extern struct task_struct *find_task_by_pid(int pid); /* per-UID process charging. */ extern struct user_struct * alloc_uid(uid_t); diff -Nru a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h --- a/include/linux/sunrpc/auth.h Fri Sep 20 08:20:46 2002 +++ b/include/linux/sunrpc/auth.h Fri Sep 20 08:20:46 2002 @@ -1,7 +1,7 @@ /* - * linux/include/linux/auth.h + * linux/include/linux/sunrpc/auth.h * - * Declarations for the RPC authentication machinery. + * Declarations for the RPC client authentication machinery. * * Copyright (C) 1996, Olaf Kirch */ @@ -67,7 +67,7 @@ * Client authentication ops */ struct rpc_authops { - unsigned int au_flavor; /* flavor (RPC_AUTH_*) */ + rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */ #ifdef RPC_DEBUG char * au_name; #endif @@ -94,7 +94,7 @@ int rpcauth_register(struct rpc_authops *); int rpcauth_unregister(struct rpc_authops *); -struct rpc_auth * rpcauth_create(unsigned int, struct rpc_clnt *); +struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); void rpcauth_destroy(struct rpc_auth *); struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); struct rpc_cred * rpcauth_bindcred(struct rpc_task *); diff -Nru a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h --- a/include/linux/sunrpc/clnt.h Fri Sep 20 08:20:47 2002 +++ b/include/linux/sunrpc/clnt.h Fri Sep 20 08:20:47 2002 @@ -111,7 +111,7 @@ struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, struct rpc_program *info, - u32 version, int authflavor); + u32 version, rpc_authflavor_t authflavor); int rpc_shutdown_client(struct rpc_clnt *); int rpc_destroy_client(struct rpc_clnt *); void rpc_release_client(struct rpc_clnt *); diff -Nru a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h --- a/include/linux/sunrpc/msg_prot.h Fri Sep 20 08:20:47 2002 +++ b/include/linux/sunrpc/msg_prot.h Fri Sep 20 08:20:47 2002 @@ -11,12 +11,16 @@ #define RPC_VERSION 2 -enum rpc_auth_flavor { +/* spec defines authentication flavor as an unsigned 32 bit integer */ +typedef u32 rpc_authflavor_t; + +enum rpc_auth_flavors { RPC_AUTH_NULL = 0, RPC_AUTH_UNIX = 1, RPC_AUTH_SHORT = 2, RPC_AUTH_DES = 3, RPC_AUTH_KRB = 4, + RPC_AUTH_MAXFLAVOR = 8, }; enum rpc_msg_type { diff -Nru a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h --- a/include/linux/sunrpc/svc.h Fri Sep 20 08:20:46 2002 +++ b/include/linux/sunrpc/svc.h Fri Sep 20 08:20:46 2002 @@ -82,8 +82,8 @@ struct iovec iov[RPCSVC_MAXIOV]; int nriov; }; -#define svc_getlong(argp, val) { (val) = *(argp)->buf++; (argp)->len--; } -#define svc_putlong(resp, val) { *(resp)->buf++ = (val); (resp)->len++; } +#define svc_getu32(argp, val) { (val) = *(argp)->buf++; (argp)->len--; } +#define svc_putu32(resp, val) { *(resp)->buf++ = (val); (resp)->len++; } /* * The context of a single thread, including the request currently being diff -Nru a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h --- a/include/linux/sunrpc/svcauth.h Fri Sep 20 08:20:44 2002 +++ b/include/linux/sunrpc/svcauth.h Fri Sep 20 08:20:44 2002 @@ -14,7 +14,7 @@ #include struct svc_cred { - u32 cr_flavor; + rpc_authflavor_t cr_flavor; uid_t cr_uid; gid_t cr_gid; gid_t cr_groups[NGROUPS]; @@ -23,8 +23,9 @@ struct svc_rqst; /* forward decl */ void svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp); -int svc_auth_register(u32 flavor, void (*)(struct svc_rqst *,u32 *,u32 *)); -void svc_auth_unregister(u32 flavor); +int svc_auth_register(rpc_authflavor_t flavor, + void (*)(struct svc_rqst *,u32 *,u32 *)); +void svc_auth_unregister(rpc_authflavor_t flavor); #if 0 /* @@ -39,7 +40,7 @@ u32 aup_gids[NGRPS]; }; -struct svc_authops * auth_getops(u32 flavor); +struct svc_authops * auth_getops(rpc_authflavor_t flavor); #endif diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h --- a/include/linux/sunrpc/xprt.h Fri Sep 20 08:20:47 2002 +++ b/include/linux/sunrpc/xprt.h Fri Sep 20 08:20:47 2002 @@ -44,6 +44,19 @@ #define RPC_MAX_UDP_TIMEOUT (60*HZ) #define RPC_MAX_TCP_TIMEOUT (600*HZ) +/* + * Wait duration for an RPC TCP connection to be established. Solaris + * NFS over TCP uses 60 seconds, for example, which is in line with how + * long a server takes to reboot. + */ +#define RPC_CONNECT_TIMEOUT (60*HZ) + +/* + * Delay an arbitrary number of seconds before attempting to reconnect + * after an error. + */ +#define RPC_REESTABLISH_TIMEOUT (15*HZ) + /* RPC call and reply header size as number of 32bit words (verifier * size computed separately) */ @@ -177,7 +190,7 @@ void xprt_receive(struct rpc_task *); int xprt_adjust_timeout(struct rpc_timeout *); void xprt_release(struct rpc_task *); -void xprt_reconnect(struct rpc_task *); +void xprt_connect(struct rpc_task *); int xprt_clear_backlog(struct rpc_xprt *); void xprt_sock_setbufsize(struct rpc_xprt *); diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h --- a/include/linux/sysctl.h Fri Sep 20 08:20:41 2002 +++ b/include/linux/sysctl.h Fri Sep 20 08:20:41 2002 @@ -128,7 +128,6 @@ KERN_TAINTED=53, /* int: various kernel tainted flags */ KERN_CADPID=54, /* int: PID of the process to notify on CAD */ KERN_PIDMAX=55, /* int: PID # limit */ - KERN_HUGETLB_PAGE_NUM=56, /* int: Number of available Huge Pages */ }; @@ -147,12 +146,12 @@ VM_PAGE_CLUSTER=10, /* int: set number of pages to swap together */ VM_DIRTY_BACKGROUND=11, /* dirty_background_ratio */ VM_DIRTY_ASYNC=12, /* dirty_async_ratio */ - VM_DIRTY_SYNC=13, /* dirty_sync_ratio */ - VM_DIRTY_WB_CS=14, /* dirty_writeback_centisecs */ - VM_DIRTY_EXPIRE_CS=15, /* dirty_expire_centisecs */ - VM_NR_PDFLUSH_THREADS=16, /* nr_pdflush_threads */ - VM_OVERCOMMIT_RATIO=17, /* percent of RAM to allow overcommit in */ - VM_PAGEBUF=18 /* struct: Control pagebuf parameters */ + VM_DIRTY_WB_CS=13, /* dirty_writeback_centisecs */ + VM_DIRTY_EXPIRE_CS=14, /* dirty_expire_centisecs */ + VM_NR_PDFLUSH_THREADS=15, /* nr_pdflush_threads */ + VM_OVERCOMMIT_RATIO=16, /* percent of RAM to allow overcommit in */ + VM_PAGEBUF=17, /* struct: Control pagebuf parameters */ + VM_HUGETLB_PAGES=18, /* int: Number of available Huge Pages */ }; diff -Nru a/include/linux/threads.h b/include/linux/threads.h --- a/include/linux/threads.h Fri Sep 20 08:20:41 2002 +++ b/include/linux/threads.h Fri Sep 20 08:20:41 2002 @@ -17,8 +17,13 @@ #define MIN_THREADS_LEFT_FOR_ROOT 4 /* - * This controls the maximum pid allocated to a process + * This controls the default maximum pid allocated to a process */ -#define DEFAULT_PID_MAX 0x8000 +#define PID_MAX_DEFAULT 0x8000 + +/* + * A maximum of 4 million PIDs should be enough for a while: + */ +#define PID_MAX_LIMIT (4*1024*1024) #endif diff -Nru a/include/linux/uio.h b/include/linux/uio.h --- a/include/linux/uio.h Fri Sep 20 08:20:41 2002 +++ b/include/linux/uio.h Fri Sep 20 08:20:41 2002 @@ -35,7 +35,11 @@ #endif /* - * Total number of bytes covered by an iovec + * Total number of bytes covered by an iovec. + * + * NOTE that it is not safe to use this function until all the iovec's + * segment lengths have been validated. Because the individual lengths can + * overflow a size_t when added together. */ static inline size_t iov_length(const struct iovec *iov, unsigned long nr_segs) { diff -Nru a/include/linux/wireless.h b/include/linux/wireless.h --- a/include/linux/wireless.h Fri Sep 20 08:20:47 2002 +++ b/include/linux/wireless.h Fri Sep 20 08:20:47 2002 @@ -1,7 +1,7 @@ /* * This file define a set of standard wireless extensions * - * Version : 14 25.1.02 + * Version : 15 12.7.02 * * Authors : Jean Tourrilhes - HPL - * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. @@ -80,7 +80,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 14 +#define WIRELESS_EXT 15 /* * Changes : @@ -153,17 +153,32 @@ * - Define additional specific event numbers * - Add "addr" and "param" fields in union iwreq_data * - AP scanning stuff (SIOCSIWSCAN and friends) + * + * V14 to V15 + * ---------- + * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg + * - Make struct iw_freq signed (both m & e), add explicit padding + * - Add IWEVCUSTOM for driver specific event/scanning token + * - Add IW_MAX_GET_SPY for driver returning a lot of addresses + * - Add IW_TXPOW_RANGE for range of Tx Powers + * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points + * - Add IW_MODE_MONITOR for passive monitor */ /**************************** CONSTANTS ****************************/ /* -------------------------- IOCTL LIST -------------------------- */ -/* Basic operations */ +/* Wireless Identification */ #define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ -#define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ -#define SIOCGIWNWID 0x8B03 /* get network id */ +/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. + * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... + * Don't put the name of your driver there, it's useless. */ + +/* Basic operations */ +#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ +#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ #define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ #define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ #define SIOCSIWMODE 0x8B06 /* set operation mode */ @@ -178,16 +193,18 @@ #define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ #define SIOCSIWSTATS 0x8B0E /* Unused */ #define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ +/* SIOCGIWSTATS is strictly used between user space and the kernel, and + * is never passed to the driver (i.e. the driver will never see it). */ -/* Mobile IP support */ +/* Mobile IP support (statistics per MAC address) */ #define SIOCSIWSPY 0x8B10 /* set spy addresses */ #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ /* Access Point manipulation */ #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ -#define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ -#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ +#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ +#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ #define SIOCGIWSCAN 0x8B19 /* get scanning results */ /* 802.11 specific support */ @@ -197,9 +214,7 @@ #define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit * within the 'iwreq' structure, so we need to use the 'data' member to - * point to a string in user space, like it is done for RANGE... - * The "flags" member indicate if the ESSID is active or not (promiscuous). - */ + * point to a string in user space, like it is done for RANGE... */ /* Other parameters useful in 802.11 and some other devices */ #define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ @@ -257,7 +272,10 @@ /* Most events use the same identifier as ioctl requests */ #define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ -#define IWEVQUAL 0x8C01 /* Quality part of statistics */ +#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ +#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ +#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ +#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ #define IWEVFIRST 0x8C00 @@ -273,7 +291,8 @@ #define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ #define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ #define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ -#define IW_PRIV_TYPE_FLOAT 0x5000 +#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ +#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ #define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */ @@ -297,9 +316,12 @@ /* Maximum tx powers in the range struct */ #define IW_MAX_TXPOWER 8 +/* Note : if you more than 8 TXPowers, just set the max and min or + * a few of them in the struct iw_range. */ /* Maximum of address that you may set with SPY */ -#define IW_MAX_SPY 8 +#define IW_MAX_SPY 8 /* set */ +#define IW_MAX_GET_SPY 64 /* get */ /* Maximum of address that you may get in the list of access points in range */ @@ -315,6 +337,7 @@ #define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ #define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ +#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ /* Maximum number of size of encoding token available * they are listed in the range structure */ @@ -350,8 +373,10 @@ #define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ /* Transmit Power flags available */ +#define IW_TXPOW_TYPE 0x00FF /* Type of value */ #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ +#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ /* Retry limits and lifetime flags available */ #define IW_RETRY_ON 0x0000 /* No details... */ @@ -376,6 +401,9 @@ /* Maximum size of returned data */ #define IW_SCAN_MAX_DATA 4096 /* In bytes */ +/* Max number of char in custom event - use multiple of them if needed */ +#define IW_CUSTOM_MAX 256 /* In bytes */ + /****************************** TYPES ******************************/ /* --------------------------- SUBTYPES --------------------------- */ @@ -411,9 +439,10 @@ */ struct iw_freq { - __u32 m; /* Mantissa */ - __u16 e; /* Exponent */ + __s32 m; /* Mantissa */ + __s16 e; /* Exponent */ __u8 i; /* List index (when in range struct) */ + __u8 pad; /* Unused - just for alignement */ }; /* diff -Nru a/include/linux/writeback.h b/include/linux/writeback.h --- a/include/linux/writeback.h Fri Sep 20 08:20:41 2002 +++ b/include/linux/writeback.h Fri Sep 20 08:20:41 2002 @@ -27,22 +27,29 @@ * fs/fs-writeback.c */ enum writeback_sync_modes { - WB_SYNC_NONE = 0, /* Don't wait on anything */ - WB_SYNC_LAST = 1, /* Wait on the last-written mapping */ - WB_SYNC_ALL = 2, /* Wait on every mapping */ - WB_SYNC_HOLD = 3, /* Hold the inode on sb_dirty for sys_sync() */ + WB_SYNC_NONE, /* Don't wait on anything */ + WB_SYNC_ALL, /* Wait on every mapping */ + WB_SYNC_HOLD, /* Hold the inode on sb_dirty for sys_sync() */ }; -void writeback_unlocked_inodes(int *nr_to_write, - enum writeback_sync_modes sync_mode, - unsigned long *older_than_this); +/* + * A control structure which tells the writeback code what to do + */ +struct writeback_control { + struct backing_dev_info *bdi; /* If !NULL, only write back this + queue */ + enum writeback_sync_modes sync_mode; + unsigned long *older_than_this; /* If !NULL, only write back inodes + older than this */ + long nr_to_write; /* Write this many pages, and decrement + this for each page written */ +}; + +void writeback_inodes(struct writeback_control *wbc); void wake_up_inode(struct inode *inode); void __wait_on_inode(struct inode * inode); void sync_inodes_sb(struct super_block *, int wait); void sync_inodes(int wait); -void writeback_backing_dev(struct backing_dev_info *bdi, int *nr_to_write, - enum writeback_sync_modes sync_mode, - unsigned long *older_than_this); /* writeback.h requires fs.h; it, too, is not included from here. */ static inline void wait_on_inode(struct inode *inode) @@ -57,7 +64,6 @@ /* These 5 are exported to sysctl. */ extern int dirty_background_ratio; extern int dirty_async_ratio; -extern int dirty_sync_ratio; extern int dirty_writeback_centisecs; extern int dirty_expire_centisecs; @@ -65,7 +71,7 @@ void balance_dirty_pages(struct address_space *mapping); void balance_dirty_pages_ratelimited(struct address_space *mapping); int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0); -int do_writepages(struct address_space *mapping, int *nr_to_write); +int do_writepages(struct address_space *mapping, struct writeback_control *wbc); /* pdflush.c */ extern int nr_pdflush_threads; /* Global so it can be exported to sysctl diff -Nru a/include/net/ax25.h b/include/net/ax25.h --- a/include/net/ax25.h Fri Sep 20 08:20:47 2002 +++ b/include/net/ax25.h Fri Sep 20 08:20:47 2002 @@ -3,11 +3,14 @@ * * Alan Cox (GW4PTS) 10/11/93 */ - #ifndef _AX25_H #define _AX25_H + #include #include +#include +#include +#include #define AX25_T1CLAMPLO 1 #define AX25_T1CLAMPHI (30 * HZ) @@ -66,6 +69,8 @@ #define AX25_UA 0x63 /* Unnumbered acknowledge */ #define AX25_FRMR 0x87 /* Frame reject */ #define AX25_UI 0x03 /* Unnumbered information */ +#define AX25_XID 0xaf /* Exchange information */ +#define AX25_TEST 0xe3 /* Test */ #define AX25_PF 0x10 /* Poll/final bit for standard AX.25 */ #define AX25_EPF 0x01 /* Poll/final bit for extended AX.25 */ @@ -147,10 +152,12 @@ typedef struct ax25_route { struct ax25_route *next; + atomic_t ref; ax25_address callsign; - struct net_device *dev; + struct net_device *dev; ax25_digi *digipeat; char ip_mode; + struct timer_list timer; } ax25_route; typedef struct { @@ -197,11 +204,12 @@ #define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo) /* af_ax25.c */ -extern ax25_cb *volatile ax25_list; +extern ax25_cb *ax25_list; +extern spinlock_t ax25_list_lock; extern void ax25_free_cb(ax25_cb *); extern void ax25_insert_socket(ax25_cb *); struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int); -struct sock *ax25_find_socket(ax25_address *, ax25_address *, int); +struct sock *ax25_get_socket(ax25_address *, ax25_address *, int); extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct net_device *); extern struct sock *ax25_addr_match(ax25_address *); extern void ax25_send_to_raw(struct sock *, struct sk_buff *, int); @@ -224,6 +232,7 @@ /* ax25_dev.c */ extern ax25_dev *ax25_dev_list; +extern spinlock_t ax25_dev_lock; extern ax25_dev *ax25_dev_ax25dev(struct net_device *); extern ax25_dev *ax25_addr_ax25dev(ax25_address *); extern void ax25_dev_device_up(struct net_device *); @@ -286,9 +295,15 @@ extern int ax25_rt_ioctl(unsigned int, void *); extern int ax25_rt_get_info(char *, char **, off_t, int); extern int ax25_rt_autobind(ax25_cb *, ax25_address *); -extern ax25_route *ax25_rt_find_route(ax25_address *, struct net_device *); +extern ax25_route *ax25_rt_find_route(ax25_route *, ax25_address *, + struct net_device *); extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *); extern void ax25_rt_free(void); + +static inline void ax25_put_route(ax25_route *ax25_rt) +{ + atomic_dec(&ax25_rt->ref); +} /* ax25_std_in.c */ extern int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int); diff -Nru a/include/net/irda/af_irda.h b/include/net/irda/af_irda.h --- a/include/net/irda/af_irda.h Fri Sep 20 08:20:47 2002 +++ b/include/net/irda/af_irda.h Fri Sep 20 08:20:47 2002 @@ -55,8 +55,8 @@ __u16 mask; /* Hint bits mask */ __u16 hints; /* Hint bits */ - __u32 ckey; /* IrLMP client handle */ - __u32 skey; /* IrLMP service handle */ + void *ckey; /* IrLMP client handle */ + void *skey; /* IrLMP service handle */ struct ias_object *ias_obj; /* Our service name + lsap in IAS */ struct iriap_cb *iriap; /* Used to query remote IAS */ diff -Nru a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h --- a/include/net/irda/ircomm_tty.h Fri Sep 20 08:20:44 2002 +++ b/include/net/irda/ircomm_tty.h Fri Sep 20 08:20:44 2002 @@ -86,8 +86,8 @@ struct iriap_cb *iriap; /* Instance used for querying remote IAS */ struct ias_object* obj; - int skey; - int ckey; + void *skey; + void *ckey; struct termios normal_termios; struct termios callout_termios; @@ -104,6 +104,14 @@ long pgrp; /* pgrp of opening process */ int open_count; int blocked_open; /* # of blocked opens */ + + /* Protect concurent access to : + * o self->open_count + * o self->ctrl_skb + * o self->tx_skb + * Maybe other things may gain to be protected as well... + * Jean II */ + spinlock_t spinlock; }; void ircomm_tty_start(struct tty_struct *tty); diff -Nru a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h --- a/include/net/irda/irlmp.h Fri Sep 20 08:20:41 2002 +++ b/include/net/irda/irlmp.h Fri Sep 20 08:20:41 2002 @@ -183,7 +183,6 @@ hashbin_t *services; hashbin_t *cachelog; /* Current discovery log */ - spinlock_t log_lock; /* discovery log spinlock */ int running; @@ -197,12 +196,12 @@ void irlmp_close_lsap( struct lsap_cb *self); __u16 irlmp_service_to_hint(int service); -__u32 irlmp_register_service(__u16 hints); -int irlmp_unregister_service(__u32 handle); -__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, +void *irlmp_register_service(__u16 hints); +int irlmp_unregister_service(void *handle); +void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, DISCOVERY_CALLBACK1 expir_clb, void *priv); -int irlmp_unregister_client(__u32 handle); -int irlmp_update_client(__u32 handle, __u16 hint_mask, +int irlmp_unregister_client(void *handle); +int irlmp_update_client(void *handle, __u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, DISCOVERY_CALLBACK1 expir_clb, void *priv); @@ -221,7 +220,7 @@ struct sk_buff *userdata); int irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata); -void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE); +void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE mode); void irlmp_discovery_request(int nslots); struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots); void irlmp_do_expiry(void); @@ -257,8 +256,6 @@ extern int sysctl_discovery; extern int sysctl_lap_keepalive_time; /* in ms, default is LM_IDLE_TIMEOUT */ extern struct irlmp_cb *irlmp; - -static inline hashbin_t *irlmp_get_cachelog(void) { return irlmp->cachelog; } /* Check if LAP queue is full. * Used by IrTTP for low control, see comments in irlap.h - Jean II */ diff -Nru a/include/net/irda/irqueue.h b/include/net/irda/irqueue.h --- a/include/net/irda/irqueue.h Fri Sep 20 08:20:47 2002 +++ b/include/net/irda/irqueue.h Fri Sep 20 08:20:47 2002 @@ -36,12 +36,12 @@ #define NAME_SIZE 32 /* - * Hash types + * Hash types (some flags can be xored) + * See comments in irqueue.c for which one to use... */ -#define HB_NOLOCK 0 -#define HB_GLOBAL 1 -#define HB_LOCAL 2 -#define HB_SORTED 4 +#define HB_NOLOCK 0 /* No concurent access prevention */ +#define HB_LOCK 1 /* Prevent concurent write with global lock */ +#define HB_SORTED 4 /* Not yet supported */ /* * Hash defines @@ -57,17 +57,12 @@ typedef void (*FREE_FUNC)(void *arg); -/* - * Hashbin - */ -#define GET_HASHBIN(x) ( x & HASHBIN_MASK ) - struct irda_queue { struct irda_queue *q_next; struct irda_queue *q_prev; char q_name[NAME_SIZE]; - __u32 q_hash; + long q_hash; /* Must be able to cast a (void *) */ }; typedef struct irda_queue irda_queue_t; @@ -75,8 +70,9 @@ __u32 magic; int hb_type; int hb_size; - spinlock_t hb_mutex[HASHBIN_SIZE] IRDA_ALIGN; - irda_queue_t *hb_queue[HASHBIN_SIZE] IRDA_ALIGN; + spinlock_t hb_spinlock; /* HB_LOCK - Can be used by the user */ + + irda_queue_t* hb_queue[HASHBIN_SIZE] IRDA_ALIGN; irda_queue_t* hb_current; } hashbin_t; @@ -84,18 +80,17 @@ hashbin_t *hashbin_new(int type); int hashbin_delete(hashbin_t* hashbin, FREE_FUNC func); int hashbin_clear(hashbin_t* hashbin, FREE_FUNC free_func); -void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, __u32 hashv, +void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv, char* name); -void* hashbin_find(hashbin_t* hashbin, __u32 hashv, char* name); -void* hashbin_remove(hashbin_t* hashbin, __u32 hashv, char* name); +void* hashbin_remove(hashbin_t* hashbin, long hashv, char* name); void* hashbin_remove_first(hashbin_t *hashbin); void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry); +void* hashbin_find(hashbin_t* hashbin, long hashv, char* name); +void* hashbin_lock_find(hashbin_t* hashbin, long hashv, char* name); +void* hashbin_find_next(hashbin_t* hashbin, long hashv, char* name, + void ** pnext); irda_queue_t *hashbin_get_first(hashbin_t *hashbin); irda_queue_t *hashbin_get_next(hashbin_t *hashbin); - -void enqueue_last(irda_queue_t **queue, irda_queue_t* element); -void enqueue_first(irda_queue_t **queue, irda_queue_t* element); -irda_queue_t *dequeue_first(irda_queue_t **queue); #define HASHBIN_GET_SIZE(hashbin) hashbin->hb_size diff -Nru a/include/net/irda/irtty.h b/include/net/irda/irtty.h --- a/include/net/irda/irtty.h Fri Sep 20 08:20:47 2002 +++ b/include/net/irda/irtty.h Fri Sep 20 08:20:47 2002 @@ -62,6 +62,9 @@ struct qos_info qos; /* QoS capabilities for this device */ dongle_t *dongle; /* Dongle driver */ + + spinlock_t lock; /* For serializing operations */ + __u32 new_speed; __u32 flags; /* Interface flags */ diff -Nru a/include/net/irda/smc-ircc.h b/include/net/irda/smc-ircc.h --- a/include/net/irda/smc-ircc.h Fri Sep 20 08:20:43 2002 +++ b/include/net/irda/smc-ircc.h Fri Sep 20 08:20:43 2002 @@ -165,7 +165,9 @@ struct irport_cb *irport; - spinlock_t lock; /* For serializing operations */ + /* Locking : half of our operations are done with irport, so we + * use the irport spinlock to make sure *everything* is properly + * synchronised - Jean II */ __u32 new_speed; __u32 flags; /* Interface flags */ diff -Nru a/include/net/irda/w83977af_ir.h b/include/net/irda/w83977af_ir.h --- a/include/net/irda/w83977af_ir.h Fri Sep 20 08:20:41 2002 +++ b/include/net/irda/w83977af_ir.h Fri Sep 20 08:20:41 2002 @@ -179,6 +179,11 @@ chipio_t io; /* IrDA controller information */ iobuff_t tx_buff; /* Transmit buffer */ iobuff_t rx_buff; /* Receive buffer */ + + /* Note : currently locking is *very* incomplete, but this + * will get you started. Check in nsc-ircc.c for a proper + * locking strategy. - Jean II */ + spinlock_t lock; /* For serializing operations */ __u32 flags; /* Interface flags */ __u32 new_speed; diff -Nru a/include/net/iw_handler.h b/include/net/iw_handler.h --- a/include/net/iw_handler.h Fri Sep 20 08:20:42 2002 +++ b/include/net/iw_handler.h Fri Sep 20 08:20:42 2002 @@ -1,7 +1,7 @@ /* * This file define the new driver API for Wireless Extensions * - * Version : 3 17.1.02 + * Version : 4 21.6.02 * * Authors : Jean Tourrilhes - HPL - * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. @@ -206,7 +206,7 @@ * will be needed... * I just plan to increment with each new version. */ -#define IW_HANDLER_VERSION 3 +#define IW_HANDLER_VERSION 4 /* * Changes : @@ -217,6 +217,9 @@ * - Add Wireless Event support : * o wireless_send_event() prototype * o iwe_stream_add_event/point() inline functions + * V3 to V4 + * -------- + * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes */ /**************************** CONSTANTS ****************************/ @@ -233,10 +236,10 @@ #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ #define IW_HEADER_TYPE_UINT 4 /* __u32 */ #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ -#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ -#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ -#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ -#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ +#define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */ +#define IW_HEADER_TYPE_POINT 8 /* struct iw_point */ +#define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */ +#define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */ /* Handling flags */ /* Most are not implemented. I just use them as a reminder of some diff -Nru a/include/net/llc_actn.h b/include/net/llc_actn.h --- a/include/net/llc_actn.h Fri Sep 20 08:20:42 2002 +++ b/include/net/llc_actn.h Fri Sep 20 08:20:42 2002 @@ -45,4 +45,5 @@ struct sk_buff *skb); extern int llc_station_ac_report_status(struct llc_station *station, struct sk_buff *skb); +extern void llc_station_ack_tmr_cb(unsigned long timeout_data); #endif /* LLC_ACTN_H */ diff -Nru a/include/net/llc_c_ac.h b/include/net/llc_c_ac.h --- a/include/net/llc_c_ac.h Fri Sep 20 08:20:48 2002 +++ b/include/net/llc_c_ac.h Fri Sep 20 08:20:48 2002 @@ -211,4 +211,9 @@ struct sk_buff *skb); extern int llc_conn_ac_send_i_rsp_as_ack(struct sock* sk, struct sk_buff *skb); extern int llc_conn_ac_send_i_as_ack(struct sock* sk, struct sk_buff *skb); + +extern void llc_conn_busy_tmr_cb(unsigned long timeout_data); +extern void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data); +extern void llc_conn_ack_tmr_cb(unsigned long timeout_data); +extern void llc_conn_rej_tmr_cb(unsigned long timeout_data); #endif /* LLC_C_AC_H */ diff -Nru a/include/net/llc_c_ev.h b/include/net/llc_c_ev.h --- a/include/net/llc_c_ev.h Fri Sep 20 08:20:42 2002 +++ b/include/net/llc_c_ev.h Fri Sep 20 08:20:42 2002 @@ -11,6 +11,9 @@ * * See the GNU General Public License for more details. */ + +#include + /* Connection component state transition event qualifiers */ /* Types of events (possible values in 'ev->type') */ #define LLC_CONN_EV_TYPE_SIMPLE 1 @@ -293,4 +296,10 @@ struct sk_buff *skb); extern int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk, struct sk_buff *skb); + +static __inline__ int llc_conn_space(struct sock *sk, struct sk_buff *skb) +{ + return atomic_read(&sk->rmem_alloc) + skb->truesize < + (unsigned)sk->rcvbuf; +} #endif /* LLC_C_EV_H */ diff -Nru a/include/net/llc_main.h b/include/net/llc_main.h --- a/include/net/llc_main.h Fri Sep 20 08:20:44 2002 +++ b/include/net/llc_main.h Fri Sep 20 08:20:44 2002 @@ -16,7 +16,7 @@ #define LLC_TYPE_1 1 #define LLC_TYPE_2 2 #define LLC_P_TIME 2 -#define LLC_ACK_TIME 3 +#define LLC_ACK_TIME 1 #define LLC_REJ_TIME 3 #define LLC_BUSY_TIME 3 #define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */ diff -Nru a/init/Makefile b/init/Makefile --- a/init/Makefile Fri Sep 20 08:20:44 2002 +++ b/init/Makefile Fri Sep 20 08:20:44 2002 @@ -2,8 +2,6 @@ # Makefile for the linux kernel. # -O_TARGET := init.o - obj-y := main.o version.o do_mounts.o include $(TOPDIR)/Rules.make diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Fri Sep 20 08:20:43 2002 +++ b/init/main.c Fri Sep 20 08:20:43 2002 @@ -66,6 +66,7 @@ extern void sysctl_init(void); extern void signals_init(void); extern void buffer_init(void); +extern void pidhash_init(void); extern void pte_chain_init(void); extern void radix_tree_init(void); extern void free_initmem(void); @@ -392,6 +393,7 @@ printk(linux_banner); setup_arch(&command_line); setup_per_cpu_areas(); + build_all_zonelists(); printk("Kernel command line: %s\n", saved_command_line); parse_options(command_line); trap_init(); @@ -432,6 +434,7 @@ #endif mem_init(); kmem_cache_sizes_init(); + pidhash_init(); pgtable_cache_init(); pte_chain_init(); fork_init(num_physpages); diff -Nru a/ipc/Makefile b/ipc/Makefile --- a/ipc/Makefile Fri Sep 20 08:20:43 2002 +++ b/ipc/Makefile Fri Sep 20 08:20:43 2002 @@ -1,13 +1,6 @@ # # Makefile for the linux ipc. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now in the main makefile... - -O_TARGET := ipc.o obj-y := util.o diff -Nru a/kernel/Makefile b/kernel/Makefile --- a/kernel/Makefile Fri Sep 20 08:20:43 2002 +++ b/kernel/Makefile Fri Sep 20 08:20:43 2002 @@ -1,13 +1,6 @@ # # Makefile for the linux kernel. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now in the main makefile... - -O_TARGET := kernel.o export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \ printk.o platform.o suspend.o dma.o @@ -15,7 +8,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ module.o exit.o itimer.o time.o softirq.o resource.o \ sysctl.o capability.o ptrace.o timer.o user.o \ - signal.o sys.o kmod.o context.o futex.o platform.o + signal.o sys.o kmod.o context.o futex.o platform.o pid.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o diff -Nru a/kernel/exit.c b/kernel/exit.c --- a/kernel/exit.c Fri Sep 20 08:20:44 2002 +++ b/kernel/exit.c Fri Sep 20 08:20:44 2002 @@ -33,7 +33,12 @@ { struct dentry *proc_dentry; nr_threads--; - unhash_pid(p); + detach_pid(p, PIDTYPE_PID); + if (thread_group_leader(p)) { + detach_pid(p, PIDTYPE_PGID); + detach_pid(p, PIDTYPE_SID); + } + REMOVE_LINKS(p); p->pid = 0; proc_dentry = p->proc_dentry; @@ -109,22 +114,18 @@ int session_of_pgrp(int pgrp) { struct task_struct *p; - int fallback; + struct list_head *l; + struct pid *pid; + int sid = -1; - fallback = -1; read_lock(&tasklist_lock); - for_each_process(p) { - if (p->session <= 0) - continue; - if (p->pgrp == pgrp) { - fallback = p->session; + for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) + if (p->session > 0) { + sid = p->session; break; } - if (p->pid == pgrp) - fallback = p->session; - } read_unlock(&tasklist_lock); - return fallback; + return sid; } /* @@ -135,21 +136,25 @@ * * "I ask you, have you ever known what it is to be an orphan?" */ -static int __will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task) +static int __will_become_orphaned_pgrp(int pgrp, task_t *ignored_task) { struct task_struct *p; - - for_each_process(p) { - if ((p == ignored_task) || (p->pgrp != pgrp) || - (p->state == TASK_ZOMBIE) || - (p->parent->pid == 1)) + struct list_head *l; + struct pid *pid; + int ret = 1; + + for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) { + if (p == ignored_task + || p->state == TASK_ZOMBIE + || p->real_parent->pid == 1) continue; - if ((p->parent->pgrp != pgrp) && - (p->parent->session == p->session)) { - return 0; + if (p->real_parent->pgrp != pgrp + && p->real_parent->session == p->session) { + ret = 0; + break; } } - return 1; /* (sighing) "Often!" */ + return ret; /* (sighing) "Often!" */ } static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task) @@ -171,11 +176,11 @@ static inline int __has_stopped_jobs(int pgrp) { int retval = 0; - struct task_struct * p; + struct task_struct *p; + struct list_head *l; + struct pid *pid; - for_each_process(p) { - if (p->pgrp != pgrp) - continue; + for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) { if (p->state != TASK_STOPPED) continue; retval = 1; @@ -221,7 +226,6 @@ /* Set the exit signal to SIGCHLD so we signal init on exit */ current->exit_signal = SIGCHLD; - current->ptrace = 0; if ((current->policy == SCHED_NORMAL) && (task_nice(current) < 0)) set_user_nice(current, 0); /* cpus_allowed? */ @@ -268,25 +272,6 @@ reparent_to_init(); } -static void reparent_thread(task_t *p, task_t *reaper, task_t *child_reaper) -{ - /* We dont want people slaying init */ - if (p->exit_signal != -1) - p->exit_signal = SIGCHLD; - p->self_exec_id++; - - /* Make sure we're not reparenting to ourselves */ - if (p == reaper) - p->real_parent = child_reaper; - else - p->real_parent = reaper; - if (p->parent == p->real_parent) - BUG(); - - if (p->pdeath_signal) - send_sig(p->pdeath_signal, p, 0); -} - static inline void close_files(struct files_struct * files) { int i, j; @@ -434,6 +419,66 @@ __exit_mm(tsk); } +static inline void choose_new_parent(task_t *p, task_t *reaper, task_t *child_reaper) +{ + /* Make sure we're not reparenting to ourselves. */ + if (p == reaper) + p->real_parent = child_reaper; + else + p->real_parent = reaper; + if (p->parent == p->real_parent) + BUG(); +} + +static inline void reparent_thread(task_t *p, task_t *father, int traced) +{ + /* We dont want people slaying init. */ + if (p->exit_signal != -1) + p->exit_signal = SIGCHLD; + p->self_exec_id++; + + if (p->pdeath_signal) + send_sig(p->pdeath_signal, p, 0); + + /* Move the child from its dying parent to the new one. */ + if (unlikely(traced)) { + /* Preserve ptrace links if someone else is tracing this child. */ + list_del_init(&p->ptrace_list); + if (p->parent != p->real_parent) + list_add(&p->ptrace_list, &p->real_parent->ptrace_children); + } else { + /* If this child is being traced, then we're the one tracing it + * anyway, so let go of it. + */ + p->ptrace = 0; + list_del_init(&p->sibling); + p->parent = p->real_parent; + list_add_tail(&p->sibling, &p->parent->children); + + /* If we'd notified the old parent about this child's death, + * also notify the new parent. + */ + if (p->state == TASK_ZOMBIE && p->exit_signal != -1) + do_notify_parent(p, p->exit_signal); + } + + /* + * process group orphan check + * Case ii: Our child is in a different pgrp + * than we are, and it was the only connection + * outside, so the child pgrp is now orphaned. + */ + if ((p->pgrp != father->pgrp) && + (p->session == father->session)) { + int pgrp = p->pgrp; + + if (__will_become_orphaned_pgrp(pgrp, 0) && __has_stopped_jobs(pgrp)) { + __kill_pg_info(SIGHUP, (void *)1, pgrp); + __kill_pg_info(SIGCONT, (void *)1, pgrp); + } + } +} + /* * When we die, we re-parent all our children. * Try to give them to another thread in our thread @@ -443,7 +488,7 @@ static inline void forget_original_parent(struct task_struct * father) { struct task_struct *p, *reaper = father; - struct list_head *_p; + struct list_head *_p, *_n; reaper = father->group_leader; if (reaper == father) @@ -457,60 +502,21 @@ * * Search them and reparent children. */ - list_for_each(_p, &father->children) { + list_for_each_safe(_p, _n, &father->children) { p = list_entry(_p,struct task_struct,sibling); - if (father == p->real_parent) - reparent_thread(p, reaper, child_reaper); - } - list_for_each(_p, &father->ptrace_children) { - p = list_entry(_p,struct task_struct,ptrace_list); - reparent_thread(p, reaper, child_reaper); - } -} - -static inline void zap_thread(task_t *p, task_t *father, int traced) -{ - /* If someone else is tracing this thread, preserve the ptrace links. */ - if (unlikely(traced)) { - task_t *trace_task = p->parent; - int ptrace_flag = p->ptrace; - BUG_ON (ptrace_flag == 0); - - __ptrace_unlink(p); - p->ptrace = ptrace_flag; - __ptrace_link(p, trace_task); - } else { - /* - * Otherwise, if we were tracing this thread, untrace it. - * If we were only tracing the thread (i.e. not its real - * parent), stop here. - */ - ptrace_unlink (p); - if (p->parent != father) { - BUG_ON(p->parent != p->real_parent); - return; + if (father == p->real_parent) { + choose_new_parent(p, reaper, child_reaper); + reparent_thread(p, father, 0); + } else { + ptrace_unlink (p); + if (p->state == TASK_ZOMBIE && p->exit_signal != -1) + do_notify_parent(p, p->exit_signal); } - list_del_init(&p->sibling); - p->parent = p->real_parent; - list_add_tail(&p->sibling, &p->parent->children); } - - if (p->state == TASK_ZOMBIE && p->exit_signal != -1) - do_notify_parent(p, p->exit_signal); - /* - * process group orphan check - * Case ii: Our child is in a different pgrp - * than we are, and it was the only connection - * outside, so the child pgrp is now orphaned. - */ - if ((p->pgrp != current->pgrp) && - (p->session == current->session)) { - int pgrp = p->pgrp; - - if (__will_become_orphaned_pgrp(pgrp, 0) && __has_stopped_jobs(pgrp)) { - __kill_pg_info(SIGHUP, (void *)1, pgrp); - __kill_pg_info(SIGCONT, (void *)1, pgrp); - } + list_for_each_safe(_p, _n, &father->ptrace_children) { + p = list_entry(_p,struct task_struct,ptrace_list); + choose_new_parent(p, reaper, child_reaper); + reparent_thread(p, father, 1); } } @@ -524,7 +530,18 @@ write_lock_irq(&tasklist_lock); + /* + * This does two things: + * + * A. Make init inherit all the child processes + * B. Check to see if any process groups have become orphaned + * as a result of our exiting, and if they have any stopped + * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) + */ + forget_original_parent(current); + BUG_ON(!list_empty(¤t->children)); + /* * Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped @@ -568,23 +585,8 @@ current->exit_signal = SIGCHLD; - /* - * This loop does two things: - * - * A. Make init inherit all the child processes - * B. Check to see if any process groups have become orphaned - * as a result of our exiting, and if they have any stopped - * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) - */ - if (current->exit_signal != -1) do_notify_parent(current, current->exit_signal); - - while (!list_empty(¤t->children)) - zap_thread(list_entry(current->children.next,struct task_struct,sibling), current, 0); - while (!list_empty(¤t->ptrace_children)) - zap_thread(list_entry(current->ptrace_children.next,struct task_struct,ptrace_list), current, 1); - BUG_ON(!list_empty(¤t->children)); current->state = TASK_ZOMBIE; /* diff -Nru a/kernel/fork.c b/kernel/fork.c --- a/kernel/fork.c Fri Sep 20 08:20:41 2002 +++ b/kernel/fork.c Fri Sep 20 08:20:41 2002 @@ -47,17 +47,6 @@ int max_threads; unsigned long total_forks; /* Handle normal Linux uptimes. */ -/* - * Protects next_safe, last_pid and pid_max: - */ -spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED; - -static int next_safe = DEFAULT_PID_MAX; -int pid_max = DEFAULT_PID_MAX; -int last_pid; - -struct task_struct *pidhash[PIDHASH_SZ]; - rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ /* @@ -75,16 +64,14 @@ } else { int cpu = smp_processor_id(); - tsk = task_cache[cpu]; + tsk = xchg(task_cache + cpu, tsk); if (tsk) { free_thread_info(tsk->thread_info); kmem_cache_free(task_struct_cachep,tsk); } - task_cache[cpu] = current; } } -/* Protects next_safe and last_pid. */ void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -140,71 +127,28 @@ struct task_struct *tsk; struct thread_info *ti; - ti = alloc_thread_info(); - if (!ti) - return NULL; - - tsk = kmem_cache_alloc(task_struct_cachep, GFP_KERNEL); + tsk = xchg(task_cache + smp_processor_id(), NULL); if (!tsk) { - free_thread_info(ti); - return NULL; - } + ti = alloc_thread_info(); + if (!ti) + return NULL; + + tsk = kmem_cache_alloc(task_struct_cachep, GFP_KERNEL); + if (!tsk) { + free_thread_info(ti); + return NULL; + } + } else + ti = tsk->thread_info; *ti = *orig->thread_info; *tsk = *orig; tsk->thread_info = ti; ti->task = tsk; atomic_set(&tsk->usage,1); - return tsk; } -static int get_pid(unsigned long flags) -{ - struct task_struct *g, *p; - int pid; - - if (flags & CLONE_IDLETASK) - return 0; - - spin_lock(&lastpid_lock); - if (++last_pid > pid_max) { - last_pid = 300; /* Skip daemons etc. */ - goto inside; - } - - if (last_pid >= next_safe) { -inside: - next_safe = pid_max; - read_lock(&tasklist_lock); - repeat: - do_each_thread(g, p) { - if (p->pid == last_pid || - p->pgrp == last_pid || - p->session == last_pid) { - if (++last_pid >= next_safe) { - if (last_pid >= pid_max) - last_pid = 300; - next_safe = pid_max; - } - goto repeat; - } - if (p->pid > last_pid && next_safe > p->pid) - next_safe = p->pid; - if (p->pgrp > last_pid && next_safe > p->pgrp) - next_safe = p->pgrp; - if (p->session > last_pid && next_safe > p->session) - next_safe = p->session; - } while_each_thread(g, p); - - read_unlock(&tasklist_lock); - } - pid = last_pid; - spin_unlock(&lastpid_lock); - - return pid; -} - static inline int dup_mmap(struct mm_struct * mm) { struct vm_area_struct * mpnt, *tmp, **pprev; @@ -724,7 +668,13 @@ p->state = TASK_UNINTERRUPTIBLE; copy_flags(clone_flags, p); - p->pid = get_pid(clone_flags); + if (clone_flags & CLONE_IDLETASK) + p->pid = 0; + else { + p->pid = alloc_pidmap(); + if (p->pid == -1) + goto bad_fork_cleanup; + } p->proc_dentry = NULL; INIT_LIST_HEAD(&p->run_list); @@ -887,7 +837,13 @@ SET_LINKS(p); if (p->ptrace & PT_PTRACED) __ptrace_link(p, current->parent); - hash_pid(p); + + attach_pid(p, PIDTYPE_PID, p->pid); + if (thread_group_leader(p)) { + attach_pid(p, PIDTYPE_PGID, p->pgrp); + attach_pid(p, PIDTYPE_SID, p->session); + } + nr_threads++; write_unlock_irq(&tasklist_lock); retval = 0; @@ -912,6 +868,8 @@ bad_fork_cleanup_security: security_ops->task_free_security(p); bad_fork_cleanup: + if (p->pid > 0) + free_pidmap(p->pid); put_exec_domain(p->thread_info->exec_domain); if (p->binfmt && p->binfmt->module) __MOD_DEC_USE_COUNT(p->binfmt->module); diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Fri Sep 20 08:20:41 2002 +++ b/kernel/ksyms.c Fri Sep 20 08:20:41 2002 @@ -53,6 +53,7 @@ #include #include #include +#include #include #if defined(CONFIG_PROC_FS) @@ -90,7 +91,6 @@ EXPORT_SYMBOL(exit_mm); /* internal kernel memory management */ -EXPORT_SYMBOL(_alloc_pages); EXPORT_SYMBOL(__alloc_pages); EXPORT_SYMBOL(alloc_pages_node); EXPORT_SYMBOL(__get_free_pages); @@ -115,9 +115,12 @@ EXPORT_SYMBOL(vmap); EXPORT_SYMBOL(vunmap); EXPORT_SYMBOL(vmalloc_to_page); -EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(remap_page_range); +#ifndef CONFIG_DISCONTIGMEM +EXPORT_SYMBOL(contig_page_data); +EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(max_mapnr); +#endif EXPORT_SYMBOL(high_memory); EXPORT_SYMBOL(vmtruncate); EXPORT_SYMBOL(find_vma); @@ -560,6 +563,7 @@ EXPORT_SYMBOL(make_bad_inode); EXPORT_SYMBOL(is_bad_inode); EXPORT_SYMBOL(event); +EXPORT_SYMBOL(__inode_dir_notify); #ifdef CONFIG_UID16 EXPORT_SYMBOL(overflowuid); @@ -602,7 +606,6 @@ EXPORT_SYMBOL(init_thread_union); EXPORT_SYMBOL(tasklist_lock); -EXPORT_SYMBOL(pidhash); #if defined(CONFIG_SMP) && defined(__GENERIC_PER_CPU) EXPORT_SYMBOL(__per_cpu_offset); #endif diff -Nru a/kernel/pid.c b/kernel/pid.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/kernel/pid.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,219 @@ +/* + * Generic pidhash and scalable, time-bounded PID allocator + * + * (C) 2002 William Irwin, IBM + * (C) 2002 Ingo Molnar, Red Hat + * + * pid-structures are backing objects for tasks sharing a given ID to chain + * against. There is very little to them aside from hashing them and + * parking tasks using given ID's on a list. + * + * The hash is always changed with the tasklist_lock write-acquired, + * and the hash is only accessed with the tasklist_lock at least + * read-acquired, so there's no additional SMP locking needed here. + * + * We have a list of bitmap pages, which bitmaps represent the PID space. + * Allocating and freeing PIDs is completely lockless. The worst-case + * allocation scenario when all but one out of 1 million PIDs possible are + * allocated already: the scanning of 32 list entries and at most PAGE_SIZE + * bytes. The typical fastpath is a single successful setbit. Freeing is O(1). + */ + +#include +#include +#include +#include + +#define PIDHASH_SIZE 4096 +#define pid_hashfn(nr) ((nr >> 8) ^ nr) & (PIDHASH_SIZE - 1) +static struct list_head pid_hash[PIDTYPE_MAX][PIDHASH_SIZE]; + +int pid_max = PID_MAX_DEFAULT; +int last_pid; + +#define RESERVED_PIDS 300 + +#define PIDMAP_ENTRIES (PID_MAX_LIMIT/PAGE_SIZE/8) +#define BITS_PER_PAGE (PAGE_SIZE*8) +#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) + +/* + * PID-map pages start out as NULL, they get allocated upon + * first use and are never deallocated. This way a low pid_max + * value does not cause lots of bitmaps to be allocated, but + * the scheme scales to up to 4 million PIDs, runtime. + */ +typedef struct pidmap { + atomic_t nr_free; + void *page; +} pidmap_t; + +static pidmap_t pidmap_array[PIDMAP_ENTRIES] = + { [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } }; + +static pidmap_t *map_limit = pidmap_array + PIDMAP_ENTRIES; + +inline void free_pidmap(int pid) +{ + pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE; + int offset = pid & BITS_PER_PAGE_MASK; + + clear_bit(offset, map->page); + atomic_inc(&map->nr_free); +} + +/* + * Here we search for the next map that has free bits left. + * Normally the next map has free PIDs. + */ +static inline pidmap_t *next_free_map(pidmap_t *map, int *max_steps) +{ + while (--*max_steps) { + if (++map == map_limit) + map = pidmap_array; + if (unlikely(!map->page)) { + unsigned long page = get_zeroed_page(GFP_KERNEL); + /* + * Free the page if someone raced with us + * installing it: + */ + if (cmpxchg(&map->page, NULL, (void *) page)) + free_page(page); + if (!map->page) + break; + } + if (atomic_read(&map->nr_free)) + return map; + } + return NULL; +} + +int alloc_pidmap(void) +{ + int pid, offset, max_steps = PIDMAP_ENTRIES + 1; + pidmap_t *map; + + pid = last_pid + 1; + if (pid >= pid_max) + pid = RESERVED_PIDS; + + offset = pid & BITS_PER_PAGE_MASK; + map = pidmap_array + pid / BITS_PER_PAGE; + + if (likely(map->page && !test_and_set_bit(offset, map->page))) { + /* + * There is a small window for last_pid updates to race, + * but in that case the next allocation will go into the + * slowpath and that fixes things up. + */ +return_pid: + atomic_dec(&map->nr_free); + last_pid = pid; + return pid; + } + + if (!offset || !atomic_read(&map->nr_free)) { +next_map: + map = next_free_map(map, &max_steps); + if (!map) + goto failure; + offset = 0; + } + /* + * Find the next zero bit: + */ +scan_more: + offset = find_next_zero_bit(map->page, BITS_PER_PAGE, offset); + if (offset == BITS_PER_PAGE) + goto next_map; + if (test_and_set_bit(offset, map->page)) + goto scan_more; + + /* we got the PID: */ + pid = (map - pidmap_array) * BITS_PER_PAGE + offset; + goto return_pid; + +failure: + return -1; +} + +inline struct pid *find_pid(enum pid_type type, int nr) +{ + struct list_head *elem, *bucket = &pid_hash[type][pid_hashfn(nr)]; + struct pid *pid; + + list_for_each_noprefetch(elem, bucket) { + pid = list_entry(elem, struct pid, hash_chain); + if (pid->nr == nr) + return pid; + } + return NULL; +} + +int attach_pid(task_t *task, enum pid_type type, int nr) +{ + struct pid *pid = find_pid(type, nr); + + if (pid) + atomic_inc(&pid->count); + else { + pid = &task->pids[type].pid; + pid->nr = nr; + atomic_set(&pid->count, 1); + INIT_LIST_HEAD(&pid->task_list); + pid->task = task; + get_task_struct(task); + list_add(&pid->hash_chain, &pid_hash[type][pid_hashfn(nr)]); + } + list_add(&task->pids[type].pid_chain, &pid->task_list); + task->pids[type].pidptr = pid; + + return 0; +} + +void detach_pid(task_t *task, enum pid_type type) +{ + struct pid_link *link = task->pids + type; + struct pid *pid = link->pidptr; + int nr; + + list_del(&link->pid_chain); + if (!atomic_dec_and_test(&pid->count)) + return; + + nr = pid->nr; + list_del(&pid->hash_chain); + put_task_struct(pid->task); + + for (type = 0; type < PIDTYPE_MAX; ++type) + if (find_pid(type, nr)) + return; + free_pidmap(nr); +} + +extern task_t *find_task_by_pid(int nr) +{ + struct pid *pid = find_pid(PIDTYPE_PID, nr); + + if (!pid) + return NULL; + return pid_task(pid->task_list.next, PIDTYPE_PID); +} + +void __init pidhash_init(void) +{ + int i, j; + + /* + * Allocate PID 0, and hash it via all PID types: + */ + pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL); + set_bit(0, pidmap_array->page); + atomic_dec(&pidmap_array->nr_free); + + for (i = 0; i < PIDTYPE_MAX; i++) { + for (j = 0; j < PIDHASH_SIZE; j++) + INIT_LIST_HEAD(&pid_hash[i][j]); + attach_pid(current, i, 0); + } +} diff -Nru a/kernel/printk.c b/kernel/printk.c --- a/kernel/printk.c Fri Sep 20 08:20:48 2002 +++ b/kernel/printk.c Fri Sep 20 08:20:48 2002 @@ -525,11 +525,11 @@ { unsigned long flags; unsigned long _con_start, _log_end; - unsigned long must_wake_klogd = 0; + unsigned long wake_klogd = 0; for ( ; ; ) { spin_lock_irqsave(&logbuf_lock, flags); - must_wake_klogd |= log_start - log_end; + wake_klogd |= log_start - log_end; if (con_start == log_end) break; /* Nothing to print */ _con_start = con_start; @@ -541,7 +541,7 @@ console_may_schedule = 0; up(&console_sem); spin_unlock_irqrestore(&logbuf_lock, flags); - if (must_wake_klogd && !oops_in_progress) + if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) wake_up_interruptible(&log_wait); } diff -Nru a/kernel/signal.c b/kernel/signal.c --- a/kernel/signal.c Fri Sep 20 08:20:44 2002 +++ b/kernel/signal.c Fri Sep 20 08:20:44 2002 @@ -71,6 +71,14 @@ | SIGPWR | load-balance | kill-all | | SIGRTMIN-SIGRTMAX | load-balance | kill-all | ---------------------------------------------------------- + + non-POSIX signal thread group behavior: + +---------------------------------------------------------- +| | userspace | kernel | +---------------------------------------------------------- +| SIGEMT | specific | kill-all+core | +---------------------------------------------------------- */ /* Some systems do not have a SIGSTKFLT and the kernel never @@ -82,12 +90,19 @@ #define M_SIGSTKFLT 0 #endif +#ifdef SIGEMT +#define M_SIGEMT M(SIGEMT) +#else +#define M_SIGEMT 0 +#endif + #define M(sig) (1UL << (sig)) #define SIG_USER_SPECIFIC_MASK (\ M(SIGILL) | M(SIGTRAP) | M(SIGABRT) | M(SIGBUS) | \ M(SIGFPE) | M(SIGSEGV) | M(SIGPIPE) | M(SIGXFSZ) | \ - M(SIGPROF) | M(SIGSYS) | M_SIGSTKFLT | M(SIGCONT) ) + M(SIGPROF) | M(SIGSYS) | M_SIGSTKFLT | M(SIGCONT) | \ + M_SIGEMT ) #define SIG_USER_LOAD_BALANCE_MASK (\ M(SIGHUP) | M(SIGINT) | M(SIGQUIT) | M(SIGUSR1) | \ @@ -105,7 +120,8 @@ M(SIGPIPE) | M(SIGALRM) | M(SIGTERM) | M(SIGXCPU) | \ M(SIGXFSZ) | M(SIGVTALRM) | M(SIGPROF) | M(SIGPOLL) | \ M(SIGSYS) | M_SIGSTKFLT | M(SIGPWR) | M(SIGCONT) | \ - M(SIGSTOP) | M(SIGTSTP) | M(SIGTTIN) | M(SIGTTOU) ) + M(SIGSTOP) | M(SIGTSTP) | M(SIGTTIN) | M(SIGTTOU) | \ + M_SIGEMT ) #define SIG_KERNEL_ONLY_MASK (\ M(SIGKILL) | M(SIGSTOP) ) @@ -113,7 +129,7 @@ #define SIG_KERNEL_COREDUMP_MASK (\ M(SIGQUIT) | M(SIGILL) | M(SIGTRAP) | M(SIGABRT) | \ M(SIGFPE) | M(SIGSEGV) | M(SIGBUS) | M(SIGSYS) | \ - M(SIGXCPU) | M(SIGXFSZ) ) + M(SIGXCPU) | M(SIGXFSZ) | M_SIGEMT ) #define T(sig, mask) \ ((1UL << (sig)) & mask) @@ -943,18 +959,18 @@ int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) { - int retval = -EINVAL; - if (pgrp > 0) { - struct task_struct *p; - - retval = -ESRCH; - for_each_process(p) { - if (p->pgrp == pgrp) { - int err = send_sig_info(sig, info, p); - if (retval) - retval = err; - } - } + struct task_struct *p; + struct list_head *l; + struct pid *pid; + int err, retval = -ESRCH; + + if (pgrp <= 0) + return -EINVAL; + + for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) { + err = send_sig_info(sig, info, p); + if (retval) + retval = err; } return retval; } @@ -977,28 +993,33 @@ * the connection is lost. */ + int -kill_sl_info(int sig, struct siginfo *info, pid_t sess) +kill_sl_info(int sig, struct siginfo *info, pid_t sid) { - int retval = -EINVAL; - if (sess > 0) { - struct task_struct *p; - - retval = -ESRCH; - read_lock(&tasklist_lock); - for_each_process(p) { - if (p->leader && p->session == sess) { - int err = send_sig_info(sig, info, p); - if (retval) - retval = err; - } - } - read_unlock(&tasklist_lock); + int err, retval = -EINVAL; + struct pid *pid; + struct list_head *l; + struct task_struct *p; + + if (sid <= 0) + goto out; + + retval = -ESRCH; + read_lock(&tasklist_lock); + for_each_task_pid(sid, PIDTYPE_SID, p, l, pid) { + if (!p->leader) + continue; + err = send_sig_info(sig, info, p); + if (retval) + retval = err; } + read_unlock(&tasklist_lock); +out: return retval; } -inline int +int kill_proc_info(int sig, struct siginfo *info, pid_t pid) { int error; diff -Nru a/kernel/suspend.c b/kernel/suspend.c --- a/kernel/suspend.c Fri Sep 20 08:20:43 2002 +++ b/kernel/suspend.c Fri Sep 20 08:20:43 2002 @@ -471,10 +471,12 @@ int nr_copy_pages = 0; int pfn; struct page *page; - + +#ifndef CONFIG_DISCONTIGMEM if (max_mapnr != num_physpages) panic("mapnr is not expected"); - for (pfn = 0; pfn < max_mapnr; pfn++) { +#endif + for (pfn = 0; pfn < num_physpages; pfn++) { page = pfn_to_page(pfn); if (PageHighMem(page)) panic("Swsusp not supported on highmem boxes. Send 1GB of RAM to and try again ;-)."); @@ -514,19 +516,20 @@ static void free_suspend_pagedir(unsigned long this_pagedir) { - struct page *page = mem_map; - int i; + struct page *page; + int pfn; unsigned long this_pagedir_end = this_pagedir + (PAGE_SIZE << pagedir_order); - for(i=0; i < num_physpages; i++, page++) { + for(pfn = 0; pfn < num_physpages; pfn++) { + page = pfn_to_page(pfn); if (!TestClearPageNosave(page)) continue; - if (ADDRESS(i) >= this_pagedir && ADDRESS(i) < this_pagedir_end) + if (ADDRESS(pfn) >= this_pagedir && ADDRESS(pfn) < this_pagedir_end) continue; /* old pagedir gets freed in one */ - free_page(ADDRESS(i)); + free_page(ADDRESS(pfn)); } free_pages(this_pagedir, pagedir_order); } diff -Nru a/kernel/sys.c b/kernel/sys.c --- a/kernel/sys.c Fri Sep 20 08:20:41 2002 +++ b/kernel/sys.c Fri Sep 20 08:20:41 2002 @@ -203,35 +203,34 @@ cond_syscall(sys_quotactl) cond_syscall(sys_acct) -static int proc_sel(struct task_struct *p, int which, int who) +static int set_one_prio(struct task_struct *p, int niceval, int error) { - if(p->pid) - { - switch (which) { - case PRIO_PROCESS: - if (!who && p == current) - return 1; - return(p->pid == who); - case PRIO_PGRP: - if (!who) - who = current->pgrp; - return(p->pgrp == who); - case PRIO_USER: - if (!who) - who = current->uid; - return(p->uid == who); - } + if (p->uid != current->euid && + p->uid != current->uid && !capable(CAP_SYS_NICE)) { + error = -EPERM; + goto out; } - return 0; + + if (error == -ESRCH) + error = 0; + if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) + error = -EACCES; + else + set_user_nice(p, niceval); +out: + return error; } asmlinkage long sys_setpriority(int which, int who, int niceval) { struct task_struct *g, *p; - int error; + struct user_struct *user; + struct pid *pid; + struct list_head *l; + int error = -EINVAL; if (which > 2 || which < 0) - return -EINVAL; + goto out; /* normalize: avoid signed division (rounding problems) */ error = -ESRCH; @@ -241,31 +240,38 @@ niceval = 19; read_lock(&tasklist_lock); - do_each_thread(g, p) { - int no_nice; - if (!proc_sel(p, which, who)) - continue; - if (p->uid != current->euid && - p->uid != current->uid && !capable(CAP_SYS_NICE)) { - error = -EPERM; - continue; - } - if (error == -ESRCH) - error = 0; - if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) { - error = -EACCES; - continue; - } - no_nice = security_ops->task_setnice(p, niceval); - if (no_nice) { - error = no_nice; - continue; - } - set_user_nice(p, niceval); - } while_each_thread(g, p); - + switch (which) { + case PRIO_PROCESS: + if (!who) + who = current->pid; + p = find_task_by_pid(who); + if (p) + error = set_one_prio(p, niceval, error); + break; + case PRIO_PGRP: + if (!who) + who = current->pgrp; + for_each_task_pid(who, PIDTYPE_PGID, p, l, pid) + error = set_one_prio(p, niceval, error); + break; + case PRIO_USER: + if (!who) + user = current->user; + else + user = find_user(who); + + if (!user) + goto out_unlock; + + do_each_thread(g, p) + if (p->uid == who) + error = set_one_prio(p, niceval, error); + while_each_thread(g, p); + break; + } +out_unlock: read_unlock(&tasklist_lock); - +out: return error; } @@ -278,20 +284,54 @@ asmlinkage long sys_getpriority(int which, int who) { struct task_struct *g, *p; - long retval = -ESRCH; + struct list_head *l; + struct pid *pid; + struct user_struct *user; + long niceval, retval = -ESRCH; if (which > 2 || which < 0) return -EINVAL; read_lock(&tasklist_lock); - do_each_thread(g, p) { - long niceval; - if (!proc_sel(p, which, who)) - continue; - niceval = 20 - task_nice(p); - if (niceval > retval) - retval = niceval; - } while_each_thread(g, p); + switch (which) { + case PRIO_PROCESS: + if (!who) + who = current->pid; + p = find_task_by_pid(who); + if (p) { + niceval = 20 - task_nice(p); + if (niceval > retval) + retval = niceval; + } + break; + case PRIO_PGRP: + if (!who) + who = current->pgrp; + for_each_task_pid(who, PIDTYPE_PGID, p, l, pid) { + niceval = 20 - task_nice(p); + if (niceval > retval) + retval = niceval; + } + break; + case PRIO_USER: + if (!who) + user = current->user; + else + user = find_user(who); + + if (!user) + goto out_unlock; + + do_each_thread(g, p) + if (p->uid == who) { + niceval = 20 - task_nice(p); + if (niceval > retval) + retval = niceval; + } + while_each_thread(g, p); + break; + } +out_unlock: read_unlock(&tasklist_lock); return retval; @@ -849,7 +889,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) { - struct task_struct * p; + struct task_struct *p; int err = -EINVAL; if (!pid) @@ -862,12 +902,15 @@ /* From this point forward we keep holding onto the tasklist lock * so that our parent does not change from under us. -DaveM */ - read_lock(&tasklist_lock); + write_lock_irq(&tasklist_lock); err = -ESRCH; p = find_task_by_pid(pid); if (!p) goto out; + err = -EINVAL; + if (!thread_group_leader(p)) + goto out; if (p->parent == current || p->real_parent == current) { err = -EPERM; @@ -882,25 +925,26 @@ if (p->leader) goto out; if (pgid != pid) { - struct task_struct *g, *tmp; - do_each_thread(g, tmp) { - if (tmp->pgrp == pgid && - tmp->session == current->session) + struct task_struct *p; + struct pid *pid; + struct list_head *l; + + for_each_task_pid(pgid, PIDTYPE_PGID, p, l, pid) + if (p->session == current->session) goto ok_pgid; - } while_each_thread(g, tmp); goto out; } ok_pgid: - err = security_ops->task_setpgid(p, pgid); - if (err) - goto out; - - p->pgrp = pgid; + if (p->pgrp != pgid) { + detach_pid(p, PIDTYPE_PGID); + p->pgrp = pgid; + attach_pid(p, PIDTYPE_PGID, pgid); + } err = 0; out: /* All paths lead to here, thus we are safe. -DaveM */ - read_unlock(&tasklist_lock); + write_unlock_irq(&tasklist_lock); return err; } @@ -956,22 +1000,34 @@ asmlinkage long sys_setsid(void) { - struct task_struct *g, *p; + struct pid *pid; int err = -EPERM; - read_lock(&tasklist_lock); - do_each_thread(g, p) - if (p->pgrp == current->pid) - goto out; - while_each_thread(g, p); + if (!thread_group_leader(current)) + return -EINVAL; + + write_lock_irq(&tasklist_lock); + + pid = find_pid(PIDTYPE_PGID, current->pid); + if (pid) + goto out; current->leader = 1; - current->session = current->pgrp = current->pid; + if (current->session != current->pid) { + detach_pid(current, PIDTYPE_SID); + current->session = current->pid; + attach_pid(current, PIDTYPE_SID, current->pid); + } + if (current->pgrp != current->pid) { + detach_pid(current, PIDTYPE_PGID); + current->pgrp = current->pid; + attach_pid(current, PIDTYPE_PGID, current->pid); + } current->tty = NULL; current->tty_old_pgrp = 0; err = current->pgrp; out: - read_unlock(&tasklist_lock); + write_unlock_irq(&tasklist_lock); return err; } diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c --- a/kernel/sysctl.c Fri Sep 20 08:20:41 2002 +++ b/kernel/sysctl.c Fri Sep 20 08:20:41 2002 @@ -99,8 +99,8 @@ #endif #ifdef CONFIG_HUGETLB_PAGE -extern int htlbpage_max; -extern int set_hugetlb_mem_size(int); +extern int htlbpage_max; +extern int set_hugetlb_mem_size(int); #endif static int parse_table(int *, int, void *, size_t *, void *, size_t, @@ -263,10 +263,6 @@ #endif {KERN_PIDMAX, "pid_max", &pid_max, sizeof (int), 0600, NULL, &proc_dointvec}, -#ifdef CONFIG_HUGETLB_PAGE - {KERN_HUGETLB_PAGE_NUM, "numhugepages", &htlbpage_max, sizeof(int), 0644, NULL, - &proc_dointvec}, -#endif {0} }; @@ -292,9 +288,6 @@ {VM_DIRTY_ASYNC, "dirty_async_ratio", &dirty_async_ratio, sizeof(dirty_async_ratio), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &zero, &one_hundred }, - {VM_DIRTY_SYNC, "dirty_sync_ratio", &dirty_sync_ratio, - sizeof(dirty_sync_ratio), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, &zero, &one_hundred }, {VM_DIRTY_WB_CS, "dirty_writeback_centisecs", &dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, @@ -317,6 +310,10 @@ { VM_NR_PDFLUSH_THREADS, "nr_pdflush_threads", &nr_pdflush_threads, sizeof nr_pdflush_threads, 0444 /* read-only*/, NULL, &proc_dointvec}, +#ifdef CONFIG_HUGETLB_PAGE + {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, NULL, + &proc_dointvec}, +#endif {0} }; diff -Nru a/kernel/user.c b/kernel/user.c --- a/kernel/user.c Fri Sep 20 08:20:44 2002 +++ b/kernel/user.c Fri Sep 20 08:20:44 2002 @@ -64,6 +64,11 @@ return NULL; } +struct user_struct *find_user(uid_t uid) +{ + return uid_hash_find(uid, uidhashentry(uid)); +} + void free_uid(struct user_struct *up) { if (up && atomic_dec_and_lock(&up->__count, &uidhash_lock)) { diff -Nru a/mm/Makefile b/mm/Makefile --- a/mm/Makefile Fri Sep 20 08:20:47 2002 +++ b/mm/Makefile Fri Sep 20 08:20:47 2002 @@ -1,13 +1,6 @@ # # Makefile for the linux memory manager. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now in the main makefile... - -O_TARGET := mm.o export-objs := shmem.o filemap.o mempool.o page_alloc.o \ page-writeback.o @@ -16,6 +9,6 @@ vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \ page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \ shmem.o highmem.o mempool.o msync.o mincore.o readahead.o \ - pdflush.o page-writeback.o rmap.o + pdflush.o page-writeback.o rmap.o madvise.o include $(TOPDIR)/Rules.make diff -Nru a/mm/filemap.c b/mm/filemap.c --- a/mm/filemap.c Fri Sep 20 08:20:44 2002 +++ b/mm/filemap.c Fri Sep 20 08:20:44 2002 @@ -487,9 +487,13 @@ int filemap_fdatawrite(struct address_space *mapping) { int ret; + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = mapping->nrpages * 2, + }; current->flags |= PF_SYNC; - ret = do_writepages(mapping, NULL); + ret = do_writepages(mapping, &wbc); current->flags &= ~PF_SYNC; return ret; } @@ -1130,10 +1134,26 @@ struct file *filp = iocb->ki_filp; ssize_t retval; unsigned long seg; - size_t count = iov_length(iov, nr_segs); + size_t count; - if ((ssize_t) count < 0) - return -EINVAL; + count = 0; + for (seg = 0; seg < nr_segs; seg++) { + const struct iovec *iv = &iov[seg]; + + /* + * If any segment has a negative length, or the cumulative + * length ever wraps negative then return -EINVAL. + */ + count += iv->iov_len; + if (unlikely((ssize_t)(count|iv->iov_len) < 0)) + return -EINVAL; + if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len)) + continue; + if (seg == 0) + return -EFAULT; + nr_segs = seg; + break; + } /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ if (filp->f_flags & O_DIRECT) { @@ -1162,11 +1182,6 @@ goto out; } - for (seg = 0; seg < nr_segs; seg++) { - if (!access_ok(VERIFY_WRITE,iov[seg].iov_base,iov[seg].iov_len)) - return -EFAULT; - } - retval = 0; if (count) { for (seg = 0; seg < nr_segs; seg++) { @@ -1482,337 +1497,7 @@ return 0; } -static inline void setup_read_behavior(struct vm_area_struct * vma, - int behavior) -{ - VM_ClearReadHint(vma); - switch(behavior) { - case MADV_SEQUENTIAL: - vma->vm_flags |= VM_SEQ_READ; - break; - case MADV_RANDOM: - vma->vm_flags |= VM_RAND_READ; - break; - default: - break; - } - return; -} - -static long madvise_fixup_start(struct vm_area_struct * vma, - unsigned long end, int behavior) -{ - struct vm_area_struct * n; - struct mm_struct * mm = vma->vm_mm; - - n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!n) - return -EAGAIN; - *n = *vma; - n->vm_end = end; - setup_read_behavior(n, behavior); - n->vm_raend = 0; - if (n->vm_file) - get_file(n->vm_file); - if (n->vm_ops && n->vm_ops->open) - n->vm_ops->open(n); - vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT; - lock_vma_mappings(vma); - spin_lock(&mm->page_table_lock); - vma->vm_start = end; - __insert_vm_struct(mm, n); - spin_unlock(&mm->page_table_lock); - unlock_vma_mappings(vma); - return 0; -} - -static long madvise_fixup_end(struct vm_area_struct * vma, - unsigned long start, int behavior) -{ - struct vm_area_struct * n; - struct mm_struct * mm = vma->vm_mm; - - n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!n) - return -EAGAIN; - *n = *vma; - n->vm_start = start; - n->vm_pgoff += (n->vm_start - vma->vm_start) >> PAGE_SHIFT; - setup_read_behavior(n, behavior); - n->vm_raend = 0; - if (n->vm_file) - get_file(n->vm_file); - if (n->vm_ops && n->vm_ops->open) - n->vm_ops->open(n); - lock_vma_mappings(vma); - spin_lock(&mm->page_table_lock); - vma->vm_end = start; - __insert_vm_struct(mm, n); - spin_unlock(&mm->page_table_lock); - unlock_vma_mappings(vma); - return 0; -} - -static long madvise_fixup_middle(struct vm_area_struct * vma, - unsigned long start, unsigned long end, int behavior) -{ - struct vm_area_struct * left, * right; - struct mm_struct * mm = vma->vm_mm; - - left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!left) - return -EAGAIN; - right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!right) { - kmem_cache_free(vm_area_cachep, left); - return -EAGAIN; - } - *left = *vma; - *right = *vma; - left->vm_end = start; - right->vm_start = end; - right->vm_pgoff += (right->vm_start - left->vm_start) >> PAGE_SHIFT; - left->vm_raend = 0; - right->vm_raend = 0; - if (vma->vm_file) - atomic_add(2, &vma->vm_file->f_count); - - if (vma->vm_ops && vma->vm_ops->open) { - vma->vm_ops->open(left); - vma->vm_ops->open(right); - } - vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT; - vma->vm_raend = 0; - lock_vma_mappings(vma); - spin_lock(&mm->page_table_lock); - vma->vm_start = start; - vma->vm_end = end; - setup_read_behavior(vma, behavior); - __insert_vm_struct(mm, left); - __insert_vm_struct(mm, right); - spin_unlock(&mm->page_table_lock); - unlock_vma_mappings(vma); - return 0; -} - -/* - * We can potentially split a vm area into separate - * areas, each area with its own behavior. - */ -static long madvise_behavior(struct vm_area_struct * vma, - unsigned long start, unsigned long end, int behavior) -{ - int error = 0; - - /* This caps the number of vma's this process can own */ - if (vma->vm_mm->map_count > MAX_MAP_COUNT) - return -ENOMEM; - - if (start == vma->vm_start) { - if (end == vma->vm_end) { - setup_read_behavior(vma, behavior); - vma->vm_raend = 0; - } else - error = madvise_fixup_start(vma, end, behavior); - } else { - if (end == vma->vm_end) - error = madvise_fixup_end(vma, start, behavior); - else - error = madvise_fixup_middle(vma, start, end, behavior); - } - - return error; -} - -/* - * Schedule all required I/O operations, then run the disk queue - * to make sure they are started. Do not wait for completion. - */ -static long madvise_willneed(struct vm_area_struct * vma, - unsigned long start, unsigned long end) -{ - long error = -EBADF; - struct file * file; - unsigned long size, rlim_rss; - - /* Doesn't work if there's no mapped file. */ - if (!vma->vm_file) - return error; - file = vma->vm_file; - size = (file->f_dentry->d_inode->i_size + PAGE_CACHE_SIZE - 1) >> - PAGE_CACHE_SHIFT; - - start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - if (end > vma->vm_end) - end = vma->vm_end; - end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - - /* Make sure this doesn't exceed the process's max rss. */ - error = -EIO; - rlim_rss = current->rlim ? current->rlim[RLIMIT_RSS].rlim_cur : - LONG_MAX; /* default: see resource.h */ - if ((vma->vm_mm->rss + (end - start)) > rlim_rss) - return error; - - do_page_cache_readahead(file, start, end - start); - return 0; -} - -/* - * Application no longer needs these pages. If the pages are dirty, - * it's OK to just throw them away. The app will be more careful about - * data it wants to keep. Be sure to free swap resources too. The - * zap_page_range call sets things up for refill_inactive to actually free - * these pages later if no one else has touched them in the meantime, - * although we could add these pages to a global reuse list for - * refill_inactive to pick up before reclaiming other pages. - * - * NB: This interface discards data rather than pushes it out to swap, - * as some implementations do. This has performance implications for - * applications like large transactional databases which want to discard - * pages in anonymous maps after committing to backing store the data - * that was kept in them. There is no reason to write this data out to - * the swap area if the application is discarding it. - * - * An interface that causes the system to free clean pages and flush - * dirty pages is already available as msync(MS_INVALIDATE). - */ -static long madvise_dontneed(struct vm_area_struct * vma, - unsigned long start, unsigned long end) -{ - if (vma->vm_flags & VM_LOCKED) - return -EINVAL; - - zap_page_range(vma, start, end - start); - return 0; -} - -static long madvise_vma(struct vm_area_struct * vma, unsigned long start, - unsigned long end, int behavior) -{ - long error = -EBADF; - - switch (behavior) { - case MADV_NORMAL: - case MADV_SEQUENTIAL: - case MADV_RANDOM: - error = madvise_behavior(vma, start, end, behavior); - break; - - case MADV_WILLNEED: - error = madvise_willneed(vma, start, end); - break; - - case MADV_DONTNEED: - error = madvise_dontneed(vma, start, end); - break; - - default: - error = -EINVAL; - break; - } - - return error; -} - -/* - * The madvise(2) system call. - * - * Applications can use madvise() to advise the kernel how it should - * handle paging I/O in this VM area. The idea is to help the kernel - * use appropriate read-ahead and caching techniques. The information - * provided is advisory only, and can be safely disregarded by the - * kernel without affecting the correct operation of the application. - * - * behavior values: - * MADV_NORMAL - the default behavior is to read clusters. This - * results in some read-ahead and read-behind. - * MADV_RANDOM - the system should read the minimum amount of data - * on any access, since it is unlikely that the appli- - * cation will need more than what it asks for. - * MADV_SEQUENTIAL - pages in the given range will probably be accessed - * once, so they can be aggressively read ahead, and - * can be freed soon after they are accessed. - * MADV_WILLNEED - the application is notifying the system to read - * some pages ahead. - * MADV_DONTNEED - the application is finished with the given range, - * so the kernel can free resources associated with it. - * - * return values: - * zero - success - * -EINVAL - start + len < 0, start is not page-aligned, - * "behavior" is not a valid value, or application - * is attempting to release locked or shared pages. - * -ENOMEM - addresses in the specified range are not currently - * mapped, or are outside the AS of the process. - * -EIO - an I/O error occurred while paging in data. - * -EBADF - map exists, but area maps something that isn't a file. - * -EAGAIN - a kernel resource was temporarily unavailable. - */ -asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior) -{ - unsigned long end; - struct vm_area_struct * vma; - int unmapped_error = 0; - int error = -EINVAL; - - down_write(¤t->mm->mmap_sem); - - if (start & ~PAGE_MASK) - goto out; - len = (len + ~PAGE_MASK) & PAGE_MASK; - end = start + len; - if (end < start) - goto out; - - error = 0; - if (end == start) - goto out; - - /* - * If the interval [start,end) covers some unmapped address - * ranges, just ignore them, but return -ENOMEM at the end. - */ - vma = find_vma(current->mm, start); - for (;;) { - /* Still start < end. */ - error = -ENOMEM; - if (!vma) - goto out; - - /* Here start < vma->vm_end. */ - if (start < vma->vm_start) { - unmapped_error = -ENOMEM; - start = vma->vm_start; - } - - /* Here vma->vm_start <= start < vma->vm_end. */ - if (end <= vma->vm_end) { - if (start < end) { - error = madvise_vma(vma, start, end, - behavior); - if (error) - goto out; - } - error = unmapped_error; - goto out; - } - - /* Here vma->vm_start <= start < vma->vm_end < end. */ - error = madvise_vma(vma, start, vma->vm_end, behavior); - if (error) - goto out; - start = vma->vm_end; - vma = vma->vm_next; - } - -out: - up_write(¤t->mm->mmap_sem); - return error; -} - -static inline -struct page *__read_cache_page(struct address_space *mapping, +static inline struct page *__read_cache_page(struct address_space *mapping, unsigned long index, int (*filler)(void *,struct page*), void *data) @@ -1956,6 +1641,63 @@ return left; } +static inline int +__filemap_copy_from_user_iovec(char *vaddr, + const struct iovec *iov, size_t base, unsigned bytes) +{ + int left = 0; + + while (bytes) { + char *buf = iov->iov_base + base; + int copy = min(bytes, iov->iov_len - base); + base = 0; + if ((left = __copy_from_user(vaddr, buf, copy))) + break; + bytes -= copy; + vaddr += copy; + iov++; + } + return left; +} + +static inline int +filemap_copy_from_user_iovec(struct page *page, unsigned long offset, + const struct iovec *iov, size_t base, unsigned bytes) +{ + char *kaddr; + int left; + + kaddr = kmap_atomic(page, KM_USER0); + left = __filemap_copy_from_user_iovec(kaddr + offset, iov, base, bytes); + kunmap_atomic(kaddr, KM_USER0); + if (left != 0) { + kaddr = kmap(page); + left = __filemap_copy_from_user_iovec(kaddr + offset, iov, base, bytes); + kunmap(page); + } + return left; +} + +static inline void +filemap_set_next_iovec(const struct iovec **iovp, size_t *basep, unsigned bytes) +{ + const struct iovec *iov = *iovp; + size_t base = *basep; + + while (bytes) { + int copy = min(bytes, iov->iov_len - base); + bytes -= copy; + base += copy; + if (iov->iov_len == base) { + iov++; + base = 0; + } + } + *iovp = iov; + *basep = base; +} + + /* * Write to a file through the page cache. * @@ -1971,8 +1713,8 @@ { struct address_space * mapping = file->f_dentry->d_inode->i_mapping; struct address_space_operations *a_ops = mapping->a_ops; - const size_t ocount = iov_length(iov, nr_segs); - size_t count = ocount; + size_t ocount; /* original count */ + size_t count; /* after file limit checks */ struct inode *inode = mapping->host; unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; long status = 0; @@ -1984,19 +1726,30 @@ unsigned bytes; time_t time_now; struct pagevec lru_pvec; - struct iovec *cur_iov; - unsigned iov_bytes; /* Cumulative count to the end of the - current iovec */ + const struct iovec *cur_iov = iov; /* current iovec */ + unsigned iov_base = 0; /* offset in the current iovec */ unsigned long seg; char *buf; - if (unlikely((ssize_t)count < 0)) - return -EINVAL; - + ocount = 0; for (seg = 0; seg < nr_segs; seg++) { - if (!access_ok(VERIFY_READ,iov[seg].iov_base,iov[seg].iov_len)) + const struct iovec *iv = &iov[seg]; + + /* + * If any segment has a negative length, or the cumulative + * length ever wraps negative then return -EINVAL. + */ + ocount += iv->iov_len; + if (unlikely((ssize_t)(ocount|iv->iov_len) < 0)) + return -EINVAL; + if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len)) + continue; + if (seg == 0) return -EFAULT; + nr_segs = seg; + break; } + count = ocount; pos = *ppos; if (unlikely(pos < 0)) @@ -2118,9 +1871,7 @@ goto out_status; } - cur_iov = (struct iovec *)iov; - iov_bytes = cur_iov->iov_len; - buf = cur_iov->iov_base; + buf = iov->iov_base; do { unsigned long index; unsigned long offset; @@ -2131,8 +1882,6 @@ bytes = PAGE_CACHE_SIZE - offset; if (bytes > count) bytes = count; - if (bytes + written > iov_bytes) - bytes = iov_bytes - written; /* * Bring in the user page that we will copy from _first_. @@ -2160,7 +1909,12 @@ vmtruncate(inode, inode->i_size); break; } - page_fault = filemap_copy_from_user(page, offset, buf, bytes); + if (likely(nr_segs == 1)) + page_fault = filemap_copy_from_user(page, offset, + buf, bytes); + else + page_fault = filemap_copy_from_user_iovec(page, offset, + cur_iov, iov_base, bytes); flush_dcache_page(page); status = a_ops->commit_write(file, page, offset, offset+bytes); if (unlikely(page_fault)) { @@ -2174,11 +1928,9 @@ count -= status; pos += status; buf += status; - if (written == iov_bytes && count) { - cur_iov++; - iov_bytes += cur_iov->iov_len; - buf = cur_iov->iov_base; - } + if (unlikely(nr_segs > 1)) + filemap_set_next_iovec(&cur_iov, + &iov_base, status); } } if (!PageReferenced(page)) diff -Nru a/mm/highmem.c b/mm/highmem.c --- a/mm/highmem.c Fri Sep 20 08:20:47 2002 +++ b/mm/highmem.c Fri Sep 20 08:20:47 2002 @@ -291,7 +291,7 @@ } } -static inline void bounce_end_io(struct bio *bio, mempool_t *pool) +static void bounce_end_io(struct bio *bio, mempool_t *pool) { struct bio *bio_orig = bio->bi_private; struct bio_vec *bvec, *org_vec; @@ -314,18 +314,26 @@ } out_eio: - bio_orig->bi_end_io(bio_orig); + bio_endio(bio_orig, bio_orig->bi_size, 0); bio_put(bio); } -static void bounce_end_io_write(struct bio *bio) +static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done,int err) { + if (bio->bi_size) + return 1; + bounce_end_io(bio, page_pool); + return 0; } -static void bounce_end_io_write_isa(struct bio *bio) +static int bounce_end_io_write_isa(struct bio *bio, unsigned int bytes_done, int err) { + if (bio->bi_size) + return 1; + bounce_end_io(bio, isa_page_pool); + return 0; } static inline void __bounce_end_io_read(struct bio *bio, mempool_t *pool) @@ -338,14 +346,22 @@ bounce_end_io(bio, pool); } -static void bounce_end_io_read(struct bio *bio) +static int bounce_end_io_read(struct bio *bio, unsigned int bytes_done, int err) { + if (bio->bi_size) + return 1; + __bounce_end_io_read(bio, page_pool); + return 0; } -static void bounce_end_io_read_isa(struct bio *bio) +static int bounce_end_io_read_isa(struct bio *bio, unsigned int bytes_done, int err) { - return __bounce_end_io_read(bio, isa_page_pool); + if (bio->bi_size) + return 1; + + __bounce_end_io_read(bio, isa_page_pool); + return 0; } void blk_queue_bounce(request_queue_t *q, struct bio **bio_orig) diff -Nru a/mm/madvise.c b/mm/madvise.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/mm/madvise.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,238 @@ +/* + * linux/mm/madvise.c + * + * Copyright (C) 1999 Linus Torvalds + * Copyright (C) 2002 Christoph Hellwig + */ + +#include +#include + + +/* + * We can potentially split a vm area into separate + * areas, each area with its own behavior. + */ +static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, + unsigned long end, int behavior) +{ + struct mm_struct * mm = vma->vm_mm; + int error; + + if (start != vma->vm_start) { + error = split_vma(mm, vma, start, 1); + if (error) + return -EAGAIN; + } + + if (end != vma->vm_end) { + error = split_vma(mm, vma, end, 0); + if (error) + return -EAGAIN; + } + + spin_lock(&mm->page_table_lock); + vma->vm_raend = 0; + VM_ClearReadHint(vma); + + switch (behavior) { + case MADV_SEQUENTIAL: + vma->vm_flags |= VM_SEQ_READ; + break; + case MADV_RANDOM: + vma->vm_flags |= VM_RAND_READ; + break; + default: + break; + } + spin_unlock(&mm->page_table_lock); + + return 0; +} + +/* + * Schedule all required I/O operations, then run the disk queue + * to make sure they are started. Do not wait for completion. + */ +static long madvise_willneed(struct vm_area_struct * vma, + unsigned long start, unsigned long end) +{ + long error = -EBADF; + struct file * file; + unsigned long size, rlim_rss; + + /* Doesn't work if there's no mapped file. */ + if (!vma->vm_file) + return error; + file = vma->vm_file; + size = (file->f_dentry->d_inode->i_size + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT; + + start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + if (end > vma->vm_end) + end = vma->vm_end; + end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + + /* Make sure this doesn't exceed the process's max rss. */ + error = -EIO; + rlim_rss = current->rlim ? current->rlim[RLIMIT_RSS].rlim_cur : + LONG_MAX; /* default: see resource.h */ + if ((vma->vm_mm->rss + (end - start)) > rlim_rss) + return error; + + do_page_cache_readahead(file, start, end - start); + return 0; +} + +/* + * Application no longer needs these pages. If the pages are dirty, + * it's OK to just throw them away. The app will be more careful about + * data it wants to keep. Be sure to free swap resources too. The + * zap_page_range call sets things up for refill_inactive to actually free + * these pages later if no one else has touched them in the meantime, + * although we could add these pages to a global reuse list for + * refill_inactive to pick up before reclaiming other pages. + * + * NB: This interface discards data rather than pushes it out to swap, + * as some implementations do. This has performance implications for + * applications like large transactional databases which want to discard + * pages in anonymous maps after committing to backing store the data + * that was kept in them. There is no reason to write this data out to + * the swap area if the application is discarding it. + * + * An interface that causes the system to free clean pages and flush + * dirty pages is already available as msync(MS_INVALIDATE). + */ +static long madvise_dontneed(struct vm_area_struct * vma, + unsigned long start, unsigned long end) +{ + if (vma->vm_flags & VM_LOCKED) + return -EINVAL; + + zap_page_range(vma, start, end - start); + return 0; +} + +static long madvise_vma(struct vm_area_struct * vma, unsigned long start, + unsigned long end, int behavior) +{ + long error = -EBADF; + + switch (behavior) { + case MADV_NORMAL: + case MADV_SEQUENTIAL: + case MADV_RANDOM: + error = madvise_behavior(vma, start, end, behavior); + break; + + case MADV_WILLNEED: + error = madvise_willneed(vma, start, end); + break; + + case MADV_DONTNEED: + error = madvise_dontneed(vma, start, end); + break; + + default: + error = -EINVAL; + break; + } + + return error; +} + +/* + * The madvise(2) system call. + * + * Applications can use madvise() to advise the kernel how it should + * handle paging I/O in this VM area. The idea is to help the kernel + * use appropriate read-ahead and caching techniques. The information + * provided is advisory only, and can be safely disregarded by the + * kernel without affecting the correct operation of the application. + * + * behavior values: + * MADV_NORMAL - the default behavior is to read clusters. This + * results in some read-ahead and read-behind. + * MADV_RANDOM - the system should read the minimum amount of data + * on any access, since it is unlikely that the appli- + * cation will need more than what it asks for. + * MADV_SEQUENTIAL - pages in the given range will probably be accessed + * once, so they can be aggressively read ahead, and + * can be freed soon after they are accessed. + * MADV_WILLNEED - the application is notifying the system to read + * some pages ahead. + * MADV_DONTNEED - the application is finished with the given range, + * so the kernel can free resources associated with it. + * + * return values: + * zero - success + * -EINVAL - start + len < 0, start is not page-aligned, + * "behavior" is not a valid value, or application + * is attempting to release locked or shared pages. + * -ENOMEM - addresses in the specified range are not currently + * mapped, or are outside the AS of the process. + * -EIO - an I/O error occurred while paging in data. + * -EBADF - map exists, but area maps something that isn't a file. + * -EAGAIN - a kernel resource was temporarily unavailable. + */ +asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior) +{ + unsigned long end; + struct vm_area_struct * vma; + int unmapped_error = 0; + int error = -EINVAL; + + down_write(¤t->mm->mmap_sem); + + if (start & ~PAGE_MASK) + goto out; + len = (len + ~PAGE_MASK) & PAGE_MASK; + end = start + len; + if (end < start) + goto out; + + error = 0; + if (end == start) + goto out; + + /* + * If the interval [start,end) covers some unmapped address + * ranges, just ignore them, but return -ENOMEM at the end. + */ + vma = find_vma(current->mm, start); + for (;;) { + /* Still start < end. */ + error = -ENOMEM; + if (!vma) + goto out; + + /* Here start < vma->vm_end. */ + if (start < vma->vm_start) { + unmapped_error = -ENOMEM; + start = vma->vm_start; + } + + /* Here vma->vm_start <= start < vma->vm_end. */ + if (end <= vma->vm_end) { + if (start < end) { + error = madvise_vma(vma, start, end, + behavior); + if (error) + goto out; + } + error = unmapped_error; + goto out; + } + + /* Here vma->vm_start <= start < vma->vm_end < end. */ + error = madvise_vma(vma, start, vma->vm_end, behavior); + if (error) + goto out; + start = vma->vm_end; + vma = vma->vm_next; + } + +out: + up_write(¤t->mm->mmap_sem); + return error; +} diff -Nru a/mm/memory.c b/mm/memory.c --- a/mm/memory.c Fri Sep 20 08:20:46 2002 +++ b/mm/memory.c Fri Sep 20 08:20:46 2002 @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -53,7 +52,12 @@ #include +#ifndef CONFIG_DISCONTIGMEM +/* use the per-pgdat data instead for discontigmem - mbligh */ unsigned long max_mapnr; +struct page *mem_map; +#endif + unsigned long num_physpages; void * high_memory; struct page *highmem_start_page; @@ -71,8 +75,6 @@ } copy_user_highpage(to, from, address); } - -struct page *mem_map; /* * Note: this doesn't free the actual pages themselves. That diff -Nru a/mm/mempool.c b/mm/mempool.c --- a/mm/mempool.c Fri Sep 20 08:20:47 2002 +++ b/mm/mempool.c Fri Sep 20 08:20:47 2002 @@ -187,11 +187,12 @@ int curr_nr; DECLARE_WAITQUEUE(wait, current); int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO); + int pf_flags = current->flags; repeat_alloc: current->flags |= PF_NOWARN; element = pool->alloc(gfp_nowait, pool->pool_data); - current->flags &= ~PF_NOWARN; + current->flags = pf_flags; if (likely(element != NULL)) return element; diff -Nru a/mm/mlock.c b/mm/mlock.c --- a/mm/mlock.c Fri Sep 20 08:20:41 2002 +++ b/mm/mlock.c Fri Sep 20 08:20:41 2002 @@ -2,147 +2,49 @@ * linux/mm/mlock.c * * (C) Copyright 1995 Linus Torvalds + * (C) Copyright 2002 Christoph Hellwig */ -#include -#include -#include -#include -#include - -#include -#include - -static inline int mlock_fixup_all(struct vm_area_struct * vma, int newflags) -{ - spin_lock(&vma->vm_mm->page_table_lock); - vma->vm_flags = newflags; - spin_unlock(&vma->vm_mm->page_table_lock); - return 0; -} - -static inline int mlock_fixup_start(struct vm_area_struct * vma, - unsigned long end, int newflags) -{ - struct vm_area_struct * n; - - n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!n) - return -EAGAIN; - *n = *vma; - n->vm_end = end; - n->vm_flags = newflags; - n->vm_raend = 0; - if (n->vm_file) - get_file(n->vm_file); - if (n->vm_ops && n->vm_ops->open) - n->vm_ops->open(n); - vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT; - lock_vma_mappings(vma); - spin_lock(&vma->vm_mm->page_table_lock); - vma->vm_start = end; - __insert_vm_struct(current->mm, n); - spin_unlock(&vma->vm_mm->page_table_lock); - unlock_vma_mappings(vma); - return 0; -} - -static inline int mlock_fixup_end(struct vm_area_struct * vma, - unsigned long start, int newflags) -{ - struct vm_area_struct * n; - - n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!n) - return -EAGAIN; - *n = *vma; - n->vm_start = start; - n->vm_pgoff += (n->vm_start - vma->vm_start) >> PAGE_SHIFT; - n->vm_flags = newflags; - n->vm_raend = 0; - if (n->vm_file) - get_file(n->vm_file); - if (n->vm_ops && n->vm_ops->open) - n->vm_ops->open(n); - lock_vma_mappings(vma); - spin_lock(&vma->vm_mm->page_table_lock); - vma->vm_end = start; - __insert_vm_struct(current->mm, n); - spin_unlock(&vma->vm_mm->page_table_lock); - unlock_vma_mappings(vma); - return 0; -} -static inline int mlock_fixup_middle(struct vm_area_struct * vma, - unsigned long start, unsigned long end, int newflags) -{ - struct vm_area_struct * left, * right; +#include +#include - left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!left) - return -EAGAIN; - right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!right) { - kmem_cache_free(vm_area_cachep, left); - return -EAGAIN; - } - *left = *vma; - *right = *vma; - left->vm_end = start; - right->vm_start = end; - right->vm_pgoff += (right->vm_start - left->vm_start) >> PAGE_SHIFT; - vma->vm_flags = newflags; - left->vm_raend = 0; - right->vm_raend = 0; - if (vma->vm_file) - atomic_add(2, &vma->vm_file->f_count); - - if (vma->vm_ops && vma->vm_ops->open) { - vma->vm_ops->open(left); - vma->vm_ops->open(right); - } - vma->vm_raend = 0; - vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT; - lock_vma_mappings(vma); - spin_lock(&vma->vm_mm->page_table_lock); - vma->vm_start = start; - vma->vm_end = end; - vma->vm_flags = newflags; - __insert_vm_struct(current->mm, left); - __insert_vm_struct(current->mm, right); - spin_unlock(&vma->vm_mm->page_table_lock); - unlock_vma_mappings(vma); - return 0; -} static int mlock_fixup(struct vm_area_struct * vma, unsigned long start, unsigned long end, unsigned int newflags) { - int pages, retval; + struct mm_struct * mm = vma->vm_mm; + int pages, error; if (newflags == vma->vm_flags) return 0; - if (start == vma->vm_start) { - if (end == vma->vm_end) - retval = mlock_fixup_all(vma, newflags); - else - retval = mlock_fixup_start(vma, end, newflags); - } else { - if (end == vma->vm_end) - retval = mlock_fixup_end(vma, start, newflags); - else - retval = mlock_fixup_middle(vma, start, end, newflags); + if (start != vma->vm_start) { + error = split_vma(mm, vma, start, 1); + if (error) + return -EAGAIN; } - if (!retval) { - /* keep track of amount of locked VM */ - pages = (end - start) >> PAGE_SHIFT; - if (newflags & VM_LOCKED) { - pages = -pages; - make_pages_present(start, end); - } - vma->vm_mm->locked_vm -= pages; + + if (end != vma->vm_end) { + error = split_vma(mm, vma, end, 0); + if (error) + return -EAGAIN; + } + + spin_lock(&mm->page_table_lock); + vma->vm_flags = newflags; + spin_unlock(&mm->page_table_lock); + + /* + * Keep track of amount of locked VM. + */ + pages = (end - start) >> PAGE_SHIFT; + if (newflags & VM_LOCKED) { + pages = -pages; + make_pages_present(start, end); } - return retval; + + vma->vm_mm->locked_vm -= pages; + return 0; } static int do_mlock(unsigned long start, size_t len, int on) diff -Nru a/mm/mmap.c b/mm/mmap.c --- a/mm/mmap.c Fri Sep 20 08:20:41 2002 +++ b/mm/mmap.c Fri Sep 20 08:20:41 2002 @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -132,47 +131,21 @@ } /* Remove one vm structure from the inode's i_mapping address space. */ -static inline void __remove_shared_vm_struct(struct vm_area_struct *vma) +static inline void remove_shared_vm_struct(struct vm_area_struct *vma) { - struct file * file = vma->vm_file; + struct file *file = vma->vm_file; if (file) { struct inode *inode = file->f_dentry->d_inode; + + spin_lock(&inode->i_mapping->i_shared_lock); if (vma->vm_flags & VM_DENYWRITE) atomic_inc(&inode->i_writecount); list_del_init(&vma->shared); + spin_unlock(&inode->i_mapping->i_shared_lock); } } -static inline void remove_shared_vm_struct(struct vm_area_struct *vma) -{ - lock_vma_mappings(vma); - __remove_shared_vm_struct(vma); - unlock_vma_mappings(vma); -} - -void lock_vma_mappings(struct vm_area_struct *vma) -{ - struct address_space *mapping; - - mapping = NULL; - if (vma->vm_file) - mapping = vma->vm_file->f_dentry->d_inode->i_mapping; - if (mapping) - spin_lock(&mapping->i_shared_lock); -} - -void unlock_vma_mappings(struct vm_area_struct *vma) -{ - struct address_space *mapping; - - mapping = NULL; - if (vma->vm_file) - mapping = vma->vm_file->f_dentry->d_inode->i_mapping; - if (mapping) - spin_unlock(&mapping->i_shared_lock); -} - /* * sys_brk() for the most part doesn't need the global kernel * lock, except when an application is doing something nasty @@ -364,11 +337,18 @@ static inline void vma_link(struct mm_struct * mm, struct vm_area_struct * vma, struct vm_area_struct * prev, struct rb_node ** rb_link, struct rb_node * rb_parent) { + struct address_space *mapping = NULL; + + if (vma->vm_file) + mapping = vma->vm_file->f_dentry->d_inode->i_mapping; + + if (mapping) + spin_lock(&mapping->i_shared_lock); spin_lock(&mm->page_table_lock); - lock_vma_mappings(vma); __vma_link(mm, vma, prev, rb_link, rb_parent); - unlock_vma_mappings(vma); spin_unlock(&mm->page_table_lock); + if (mapping) + spin_unlock(&mapping->i_shared_lock); mm->map_count++; validate_mm(mm); @@ -463,6 +443,11 @@ */ vm_flags = calc_vm_flags(prot,flags) | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; + if (flags & MAP_LOCKED) { + if (!capable(CAP_IPC_LOCK)) + return -EPERM; + vm_flags |= VM_LOCKED; + } /* mlock MCL_FUTURE? */ if (vm_flags & VM_LOCKED) { unsigned long locked = mm->locked_vm << PAGE_SHIFT; @@ -1049,10 +1034,11 @@ } /* - * Split a vma into two pieces at address 'addr', the original vma - * will contain the first part, a new vma is allocated for the tail. + * Split a vma into two pieces at address 'addr', a new vma is allocated + * either for the first part or the the tail. */ -static int splitvma(struct mm_struct *mm, struct vm_area_struct *mpnt, unsigned long addr) +int split_vma(struct mm_struct * mm, struct vm_area_struct * vma, + unsigned long addr, int new_below) { struct vm_area_struct *new; @@ -1064,31 +1050,34 @@ return -ENOMEM; /* most fields are the same, copy all, and then fixup */ - *new = *mpnt; + *new = *vma; + + if (new_below) { + new->vm_end = addr; + vma->vm_start = addr; + vma->vm_pgoff += ((addr - vma->vm_start) >> PAGE_SHIFT); + } else { + vma->vm_end = addr; + new->vm_start = addr; + new->vm_pgoff += ((addr - vma->vm_start) >> PAGE_SHIFT); + } - new->vm_start = addr; - new->vm_pgoff = mpnt->vm_pgoff + ((addr - mpnt->vm_start) >> PAGE_SHIFT); new->vm_raend = 0; - if (mpnt->vm_file) - get_file(mpnt->vm_file); - if (mpnt->vm_ops && mpnt->vm_ops->open) - mpnt->vm_ops->open(mpnt); - mpnt->vm_end = addr; /* Truncate area */ + if (new->vm_file) + get_file(new->vm_file); - spin_lock(&mm->page_table_lock); - lock_vma_mappings(mpnt); - __insert_vm_struct(mm, new); - unlock_vma_mappings(mpnt); - spin_unlock(&mm->page_table_lock); + if (new->vm_ops && new->vm_ops->open) + new->vm_ops->open(new); + insert_vm_struct(mm, new); return 0; } /* Munmap is split into 2 main parts -- this part which finds * what needs doing, and the areas themselves, which do the * work. This now handles partial unmappings. - * Jeremy Fitzhardine + * Jeremy Fitzhardinge */ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len) { @@ -1116,7 +1105,7 @@ * If we need to split any vma, do it now to save pain later. */ if (start > mpnt->vm_start) { - if (splitvma(mm, mpnt, start)) + if (split_vma(mm, mpnt, start, 0)) return -ENOMEM; prev = mpnt; mpnt = mpnt->vm_next; @@ -1125,7 +1114,7 @@ /* Does it split the last one? */ last = find_vma(mm, end); if (last && end > last->vm_start) { - if (splitvma(mm, last, end)) + if (split_vma(mm, last, end, 0)) return -ENOMEM; } @@ -1325,19 +1314,6 @@ * and into the inode's i_mmap ring. If vm_file is non-NULL * then the i_shared_lock must be held here. */ -void __insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) -{ - struct vm_area_struct * __vma, * prev; - struct rb_node ** rb_link, * rb_parent; - - __vma = find_vma_prepare(mm, vma->vm_start, &prev, &rb_link, &rb_parent); - if (__vma && __vma->vm_start < vma->vm_end) - BUG(); - __vma_link(mm, vma, prev, rb_link, rb_parent); - mm->map_count++; - validate_mm(mm); -} - void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) { struct vm_area_struct * __vma, * prev; diff -Nru a/mm/mprotect.c b/mm/mprotect.c --- a/mm/mprotect.c Fri Sep 20 08:20:44 2002 +++ b/mm/mprotect.c Fri Sep 20 08:20:44 2002 @@ -2,13 +2,14 @@ * mm/mprotect.c * * (C) Copyright 1994 Linus Torvalds + * (C) Copyright 2002 Christoph Hellwig * * Address space accounting code * (C) Copyright 2002 Red Hat Inc, All Rights Reserved */ + #include #include -#include #include #include #include @@ -21,8 +22,9 @@ #include #include -static inline void change_pte_range(pmd_t * pmd, unsigned long address, - unsigned long size, pgprot_t newprot) +static inline void +change_pte_range(pmd_t *pmd, unsigned long address, + unsigned long size, pgprot_t newprot) { pte_t * pte; unsigned long end; @@ -56,8 +58,9 @@ pte_unmap(pte - 1); } -static inline void change_pmd_range(pgd_t * pgd, unsigned long address, - unsigned long size, pgprot_t newprot) +static inline void +change_pmd_range(pgd_t *pgd, unsigned long address, + unsigned long size, pgprot_t newprot) { pmd_t * pmd; unsigned long end; @@ -81,7 +84,9 @@ } while (address && (address < end)); } -static void change_protection(struct vm_area_struct *vma, unsigned long start, unsigned long end, pgprot_t newprot) +static void +change_protection(struct vm_area_struct *vma, unsigned long start, + unsigned long end, pgprot_t newprot) { pgd_t *dir; unsigned long beg = start; @@ -100,158 +105,58 @@ spin_unlock(¤t->mm->page_table_lock); return; } - -static inline int mprotect_fixup_all(struct vm_area_struct * vma, struct vm_area_struct ** pprev, - int newflags, pgprot_t prot) +/* + * Try to merge a vma with the previous flag, return 1 if successful or 0 if it + * was impossible. + */ +static int +mprotect_attempt_merge(struct vm_area_struct *vma, struct vm_area_struct *prev, + unsigned long end, int newflags) { - struct vm_area_struct * prev = *pprev; struct mm_struct * mm = vma->vm_mm; - if (prev && prev->vm_end == vma->vm_start && can_vma_merge(prev, newflags) && - !vma->vm_file && !(vma->vm_flags & VM_SHARED)) { + if (!prev || !vma) + return 0; + if (prev->vm_end != vma->vm_start) + return 0; + if (!can_vma_merge(prev, newflags)) + return 0; + if (vma->vm_file || (vma->vm_flags & VM_SHARED)) + return 0; + + /* + * If the whole area changes to the protection of the previous one + * we can just get rid of it. + */ + if (end == vma->vm_end) { spin_lock(&mm->page_table_lock); - prev->vm_end = vma->vm_end; + prev->vm_end = end; __vma_unlink(mm, vma, prev); spin_unlock(&mm->page_table_lock); kmem_cache_free(vm_area_cachep, vma); mm->map_count--; + return 1; + } - return 0; - } - + /* + * Otherwise extend it. + */ spin_lock(&mm->page_table_lock); - vma->vm_flags = newflags; - vma->vm_page_prot = prot; - spin_unlock(&mm->page_table_lock); - - *pprev = vma; - - return 0; -} - -static inline int mprotect_fixup_start(struct vm_area_struct * vma, struct vm_area_struct ** pprev, - unsigned long end, - int newflags, pgprot_t prot) -{ - struct vm_area_struct * n, * prev = *pprev; - - *pprev = vma; - - if (prev && prev->vm_end == vma->vm_start && can_vma_merge(prev, newflags) && - !vma->vm_file && !(vma->vm_flags & VM_SHARED)) { - spin_lock(&vma->vm_mm->page_table_lock); - prev->vm_end = end; - vma->vm_start = end; - spin_unlock(&vma->vm_mm->page_table_lock); - - return 0; - } - n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!n) - return -ENOMEM; - *n = *vma; - n->vm_end = end; - n->vm_flags = newflags; - n->vm_raend = 0; - n->vm_page_prot = prot; - if (n->vm_file) - get_file(n->vm_file); - if (n->vm_ops && n->vm_ops->open) - n->vm_ops->open(n); - vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT; - lock_vma_mappings(vma); - spin_lock(&vma->vm_mm->page_table_lock); + prev->vm_end = end; vma->vm_start = end; - __insert_vm_struct(current->mm, n); - spin_unlock(&vma->vm_mm->page_table_lock); - unlock_vma_mappings(vma); - - return 0; -} - -static inline int mprotect_fixup_end(struct vm_area_struct * vma, struct vm_area_struct ** pprev, - unsigned long start, - int newflags, pgprot_t prot) -{ - struct vm_area_struct * n; - - n = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); - if (!n) - return -ENOMEM; - *n = *vma; - n->vm_start = start; - n->vm_pgoff += (n->vm_start - vma->vm_start) >> PAGE_SHIFT; - n->vm_flags = newflags; - n->vm_raend = 0; - n->vm_page_prot = prot; - if (n->vm_file) - get_file(n->vm_file); - if (n->vm_ops && n->vm_ops->open) - n->vm_ops->open(n); - lock_vma_mappings(vma); - spin_lock(&vma->vm_mm->page_table_lock); - vma->vm_end = start; - __insert_vm_struct(current->mm, n); - spin_unlock(&vma->vm_mm->page_table_lock); - unlock_vma_mappings(vma); - - *pprev = n; - - return 0; -} - -static inline int mprotect_fixup_middle(struct vm_area_struct * vma, struct vm_area_struct ** pprev, - unsigned long start, unsigned long end, - int newflags, pgprot_t prot) -{ - struct vm_area_struct * left, * right; - - left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!left) - return -ENOMEM; - right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!right) { - kmem_cache_free(vm_area_cachep, left); - return -ENOMEM; - } - *left = *vma; - *right = *vma; - left->vm_end = start; - right->vm_start = end; - right->vm_pgoff += (right->vm_start - left->vm_start) >> PAGE_SHIFT; - left->vm_raend = 0; - right->vm_raend = 0; - if (vma->vm_file) - atomic_add(2,&vma->vm_file->f_count); - if (vma->vm_ops && vma->vm_ops->open) { - vma->vm_ops->open(left); - vma->vm_ops->open(right); - } - vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT; - vma->vm_raend = 0; - vma->vm_page_prot = prot; - lock_vma_mappings(vma); - spin_lock(&vma->vm_mm->page_table_lock); - vma->vm_start = start; - vma->vm_end = end; - vma->vm_flags = newflags; - __insert_vm_struct(current->mm, left); - __insert_vm_struct(current->mm, right); - spin_unlock(&vma->vm_mm->page_table_lock); - unlock_vma_mappings(vma); - - *pprev = right; - - return 0; + spin_unlock(&mm->page_table_lock); + return 1; } -static int mprotect_fixup(struct vm_area_struct * vma, struct vm_area_struct ** pprev, +static int +mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, unsigned long start, unsigned long end, unsigned int newflags) { + struct mm_struct * mm = vma->vm_mm; + unsigned long charged = 0; pgprot_t newprot; int error; - unsigned long charged = 0; if (newflags == vma->vm_flags) { *pprev = vma; @@ -266,32 +171,50 @@ * FIXME? We haven't defined a VM_NORESERVE flag, so mprotecting * a MAP_NORESERVE private mapping to writable will now reserve. */ - if ((newflags & VM_WRITE) && - !(vma->vm_flags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) { - charged = (end - start) >> PAGE_SHIFT; - if (!vm_enough_memory(charged)) - return -ENOMEM; - newflags |= VM_ACCOUNT; + if (newflags & VM_WRITE) { + if (!(vma->vm_flags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) { + charged = (end - start) >> PAGE_SHIFT; + if (!vm_enough_memory(charged)) + return -ENOMEM; + newflags |= VM_ACCOUNT; + } } + newprot = protection_map[newflags & 0xf]; + if (start == vma->vm_start) { - if (end == vma->vm_end) - error = mprotect_fixup_all(vma, pprev, newflags, newprot); - else - error = mprotect_fixup_start(vma, pprev, end, newflags, newprot); - } else if (end == vma->vm_end) - error = mprotect_fixup_end(vma, pprev, start, newflags, newprot); - else - error = mprotect_fixup_middle(vma, pprev, start, end, newflags, newprot); - if (error) { - vm_unacct_memory(charged); - return error; + /* + * Try to merge with the previous vma. + */ + if (mprotect_attempt_merge(vma, *pprev, end, newflags)) + return 0; + } else { + error = split_vma(mm, vma, start, 1); + if (error) + goto fail; + } + + if (end != vma->vm_end) { + error = split_vma(mm, vma, end, 0); + if (error) + goto fail; } + + spin_lock(&mm->page_table_lock); + vma->vm_flags = newflags; + vma->vm_page_prot = newprot; + spin_unlock(&mm->page_table_lock); + change_protection(vma, start, end, newprot); return 0; + +fail: + vm_unacct_memory(charged); + return error; } -asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot) +asmlinkage long +sys_mprotect(unsigned long start, size_t len, unsigned long prot) { unsigned long nstart, end, tmp; struct vm_area_struct * vma, * next, * prev; @@ -357,8 +280,10 @@ goto out; } } - if (next && prev->vm_end == next->vm_start && can_vma_merge(next, prev->vm_flags) && - !prev->vm_file && !(prev->vm_flags & VM_SHARED)) { + + if (next && prev->vm_end == next->vm_start && + can_vma_merge(next, prev->vm_flags) && + !prev->vm_file && !(prev->vm_flags & VM_SHARED)) { spin_lock(&prev->vm_mm->page_table_lock); prev->vm_end = next->vm_end; __vma_unlink(prev->vm_mm, next, prev); diff -Nru a/mm/mremap.c b/mm/mremap.c --- a/mm/mremap.c Fri Sep 20 08:20:46 2002 +++ b/mm/mremap.c Fri Sep 20 08:20:46 2002 @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff -Nru a/mm/numa.c b/mm/numa.c --- a/mm/numa.c Fri Sep 20 08:20:47 2002 +++ b/mm/numa.c Fri Sep 20 08:20:47 2002 @@ -22,11 +22,21 @@ * Should be invoked with paramters (0, 0, unsigned long *[], start_paddr). */ void __init free_area_init_node(int nid, pg_data_t *pgdat, struct page *pmap, - unsigned long *zones_size, unsigned long zone_start_pfn, + unsigned long *zones_size, unsigned long node_start_pfn, unsigned long *zholes_size) { - free_area_init_core(0, &contig_page_data, &mem_map, zones_size, - zone_start_pfn, zholes_size, pmap); + unsigned long size; + + contig_page_data.node_id = 0; + contig_page_data.node_start_pfn = node_start_pfn; + calculate_totalpages (&contig_page_data, zones_size, zholes_size); + if (pmap == (struct page *)0) { + size = (pgdat->node_size + 1) * sizeof(struct page); + pmap = (struct page *) alloc_bootmem_node(pgdat, size); + } + contig_page_data.node_mem_map = pmap; + free_area_init_core(&contig_page_data, zones_size, zholes_size); + mem_map = contig_page_data.node_mem_map; } #endif /* !CONFIG_DISCONTIGMEM */ @@ -48,71 +58,31 @@ * Nodes can be initialized parallely, in no particular order. */ void __init free_area_init_node(int nid, pg_data_t *pgdat, struct page *pmap, - unsigned long *zones_size, unsigned long zone_start_pfn, + unsigned long *zones_size, unsigned long node_start_pfn, unsigned long *zholes_size) { - int i, size = 0; - struct page *discard; - - if (mem_map == NULL) - mem_map = (struct page *)PAGE_OFFSET; + int i; + unsigned long size; - free_area_init_core(nid, pgdat, &discard, zones_size, zone_start_pfn, - zholes_size, pmap); pgdat->node_id = nid; + pgdat->node_start_pfn = node_start_pfn; + calculate_totalpages (pgdat, zones_size, zholes_size); + if (pmap == (struct page *)0) { + size = (pgdat->node_size + 1) * sizeof(struct page); + pmap = (struct page *) alloc_bootmem_node(pgdat, size); + } + pgdat->node_mem_map = pmap; + free_area_init_core(pgdat, zones_size, zholes_size); /* * Get space for the valid bitmap. */ + size = 0; for (i = 0; i < MAX_NR_ZONES; i++) size += zones_size[i]; size = LONG_ALIGN((size + 7) >> 3); pgdat->valid_addr_bitmap = (unsigned long *)alloc_bootmem_node(pgdat, size); memset(pgdat->valid_addr_bitmap, 0, size); -} - -static struct page * alloc_pages_pgdat(pg_data_t *pgdat, unsigned int gfp_mask, - unsigned int order) -{ - return __alloc_pages(gfp_mask, order, pgdat->node_zonelists + (gfp_mask & GFP_ZONEMASK)); -} - -/* - * This can be refined. Currently, tries to do round robin, instead - * should do concentratic circle search, starting from current node. - */ -struct page * _alloc_pages(unsigned int gfp_mask, unsigned int order) -{ - struct page *ret = 0; - pg_data_t *start, *temp; -#ifndef CONFIG_NUMA - unsigned long flags; - static pg_data_t *next = 0; -#endif - - if (order >= MAX_ORDER) - return NULL; -#ifdef CONFIG_NUMA - temp = NODE_DATA(numa_node_id()); -#else - if (!next) - next = pgdat_list; - temp = next; - next = next->pgdat_next; -#endif - start = temp; - while (temp) { - if ((ret = alloc_pages_pgdat(temp, gfp_mask, order))) - return(ret); - temp = temp->pgdat_next; - } - temp = pgdat_list; - while (temp != start) { - if ((ret = alloc_pages_pgdat(temp, gfp_mask, order))) - return(ret); - temp = temp->pgdat_next; - } - return(0); } #endif /* CONFIG_DISCONTIGMEM */ diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c --- a/mm/page-writeback.c Fri Sep 20 08:20:47 2002 +++ b/mm/page-writeback.c Fri Sep 20 08:20:47 2002 @@ -51,7 +51,7 @@ * It should be somewhat larger than RATELIMIT_PAGES to ensure that reasonably * large amounts of I/O are submitted. */ -static inline int sync_writeback_pages(void) +static inline long sync_writeback_pages(void) { return ratelimit_pages + ratelimit_pages / 2; } @@ -73,11 +73,6 @@ int dirty_async_ratio = 40; /* - * The generator of dirty data performs sync writeout at this level - */ -int dirty_sync_ratio = 50; - -/* * The interval between `kupdate'-style writebacks, in centiseconds * (hundredths of a second) */ @@ -105,15 +100,11 @@ * - Does nothing at all. * * balance_dirty_pages() can sleep. - * - * FIXME: WB_SYNC_LAST doesn't actually work. It waits on the last dirty - * inode on the superblock list. It should wait when nr_to_write is - * exhausted. Doesn't seem to matter. */ void balance_dirty_pages(struct address_space *mapping) { struct page_state ps; - long background_thresh, async_thresh, sync_thresh; + long background_thresh, async_thresh; unsigned long dirty_and_writeback; struct backing_dev_info *bdi; @@ -122,18 +113,17 @@ background_thresh = (dirty_background_ratio * total_pages) / 100; async_thresh = (dirty_async_ratio * total_pages) / 100; - sync_thresh = (dirty_sync_ratio * total_pages) / 100; bdi = mapping->backing_dev_info; - if (dirty_and_writeback > sync_thresh) { - int nr_to_write = sync_writeback_pages(); + if (dirty_and_writeback > async_thresh) { + struct writeback_control wbc = { + .bdi = bdi, + .sync_mode = WB_SYNC_NONE, + .older_than_this = NULL, + .nr_to_write = sync_writeback_pages(), + }; - writeback_backing_dev(bdi, &nr_to_write, WB_SYNC_LAST, NULL); - get_page_state(&ps); - } else if (dirty_and_writeback > async_thresh) { - int nr_to_write = sync_writeback_pages(); - - writeback_backing_dev(bdi, &nr_to_write, WB_SYNC_NONE, NULL); + writeback_inodes(&wbc); get_page_state(&ps); } @@ -177,7 +167,12 @@ { long min_pages = _min_pages; long background_thresh; - int nr_to_write; + struct writeback_control wbc = { + .bdi = NULL, + .sync_mode = WB_SYNC_NONE, + .older_than_this = NULL, + .nr_to_write = 0, + }; CHECK_EMERGENCY_SYNC @@ -185,14 +180,13 @@ do { struct page_state ps; - get_page_state(&ps); if (ps.nr_dirty < background_thresh && min_pages <= 0) break; - nr_to_write = MAX_WRITEBACK_PAGES; - writeback_unlocked_inodes(&nr_to_write, WB_SYNC_NONE, NULL); - min_pages -= MAX_WRITEBACK_PAGES - nr_to_write; - } while (nr_to_write <= 0); + wbc.nr_to_write = MAX_WRITEBACK_PAGES; + writeback_inodes(&wbc); + min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; + } while (wbc.nr_to_write <= 0); blk_run_queues(); } @@ -230,7 +224,12 @@ unsigned long start_jif; unsigned long next_jif; struct page_state ps; - int nr_to_write; + struct writeback_control wbc = { + .bdi = NULL, + .sync_mode = WB_SYNC_NONE, + .older_than_this = &oldest_jif, + .nr_to_write = 0, + }; sync_supers(); get_page_state(&ps); @@ -238,8 +237,8 @@ oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100; start_jif = jiffies; next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100; - nr_to_write = ps.nr_dirty; - writeback_unlocked_inodes(&nr_to_write, WB_SYNC_NONE, &oldest_jif); + wbc.nr_to_write = ps.nr_dirty; + writeback_inodes(&wbc); blk_run_queues(); yield(); @@ -312,8 +311,6 @@ dirty_background_ratio /= 100; dirty_async_ratio *= correction; dirty_async_ratio /= 100; - dirty_sync_ratio *= correction; - dirty_sync_ratio /= 100; } init_timer(&wb_timer); @@ -351,7 +348,7 @@ * So. The proper fix is to leave the page locked-and-dirty and to pass * it all the way down. */ -int generic_vm_writeback(struct page *page, int *nr_to_write) +int generic_vm_writeback(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; @@ -363,7 +360,7 @@ unlock_page(page); if (inode) { - do_writepages(inode->i_mapping, nr_to_write); + do_writepages(inode->i_mapping, wbc); /* * This iput() will internally call ext2_discard_prealloc(), @@ -392,11 +389,11 @@ } EXPORT_SYMBOL(generic_vm_writeback); -int do_writepages(struct address_space *mapping, int *nr_to_write) +int do_writepages(struct address_space *mapping, struct writeback_control *wbc) { if (mapping->a_ops->writepages) - return mapping->a_ops->writepages(mapping, nr_to_write); - return generic_writepages(mapping, nr_to_write); + return mapping->a_ops->writepages(mapping, wbc); + return generic_writepages(mapping, wbc); } /** diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c --- a/mm/page_alloc.c Fri Sep 20 08:20:41 2002 +++ b/mm/page_alloc.c Fri Sep 20 08:20:41 2002 @@ -256,14 +256,6 @@ } #endif /* CONFIG_SOFTWARE_SUSPEND */ -#ifndef CONFIG_DISCONTIGMEM -struct page *_alloc_pages(unsigned int gfp_mask, unsigned int order) -{ - return __alloc_pages(gfp_mask, order, - contig_page_data.node_zonelists+(gfp_mask & GFP_ZONEMASK)); -} -#endif - static /* inline */ struct page * balance_classzone(struct zone* classzone, unsigned int gfp_mask, unsigned int order, int * freed) @@ -563,6 +555,7 @@ ret->nr_page_table_pages += ps->nr_page_table_pages; ret->nr_reverse_maps += ps->nr_reverse_maps; ret->nr_mapped += ps->nr_mapped; + ret->nr_slab += ps->nr_slab; } } @@ -679,13 +672,41 @@ /* * Builds allocation fallback zone lists. */ -static inline void build_zonelists(pg_data_t *pgdat) +static int __init build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist, int j, int k) +{ + switch (k) { + struct zone *zone; + default: + BUG(); + case ZONE_HIGHMEM: + zone = pgdat->node_zones + ZONE_HIGHMEM; + if (zone->size) { +#ifndef CONFIG_HIGHMEM + BUG(); +#endif + zonelist->zones[j++] = zone; + } + case ZONE_NORMAL: + zone = pgdat->node_zones + ZONE_NORMAL; + if (zone->size) + zonelist->zones[j++] = zone; + case ZONE_DMA: + zone = pgdat->node_zones + ZONE_DMA; + if (zone->size) + zonelist->zones[j++] = zone; + } + + return j; +} + +static void __init build_zonelists(pg_data_t *pgdat) { - int i, j, k; + int i, j, k, node, local_node; + local_node = pgdat->node_id; + printk("Building zonelist for node : %d\n", local_node); for (i = 0; i <= GFP_ZONEMASK; i++) { struct zonelist *zonelist; - struct zone *zone; zonelist = pgdat->node_zonelists + i; memset(zonelist, 0, sizeof(*zonelist)); @@ -697,33 +718,49 @@ if (i & __GFP_DMA) k = ZONE_DMA; - switch (k) { - default: - BUG(); - /* - * fallthrough: - */ - case ZONE_HIGHMEM: - zone = pgdat->node_zones + ZONE_HIGHMEM; - if (zone->size) { -#ifndef CONFIG_HIGHMEM - BUG(); -#endif - zonelist->zones[j++] = zone; - } - case ZONE_NORMAL: - zone = pgdat->node_zones + ZONE_NORMAL; - if (zone->size) - zonelist->zones[j++] = zone; - case ZONE_DMA: - zone = pgdat->node_zones + ZONE_DMA; - if (zone->size) - zonelist->zones[j++] = zone; - } + j = build_zonelists_node(pgdat, zonelist, j, k); + /* + * Now we build the zonelist so that it contains the zones + * of all the other nodes. + * We don't want to pressure a particular node, so when + * building the zones for node N, we make sure that the + * zones coming right after the local ones are those from + * node N+1 (modulo N) + */ + for (node = local_node + 1; node < numnodes; node++) + j = build_zonelists_node(NODE_DATA(node), zonelist, j, k); + for (node = 0; node < local_node; node++) + j = build_zonelists_node(NODE_DATA(node), zonelist, j, k); + zonelist->zones[j++] = NULL; } } +void __init build_all_zonelists(void) +{ + int i; + + for(i = 0 ; i < numnodes ; i++) + build_zonelists(NODE_DATA(i)); +} + +void __init calculate_totalpages (pg_data_t *pgdat, unsigned long *zones_size, + unsigned long *zholes_size) +{ + unsigned long realtotalpages, totalpages = 0; + int i; + + for (i = 0; i < MAX_NR_ZONES; i++) + totalpages += zones_size[i]; + pgdat->node_size = totalpages; + + realtotalpages = totalpages; + if (zholes_size) + for (i = 0; i < MAX_NR_ZONES; i++) + realtotalpages -= zholes_size[i]; + printk("On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages); +} + /* * Helper functions to size the waitqueue hash table. * Essentially these want to choose hash table sizes sufficiently @@ -774,46 +811,18 @@ * - mark all memory queues empty * - clear the memory bitmaps */ -void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap, - unsigned long *zones_size, unsigned long zone_start_pfn, - unsigned long *zholes_size, struct page *lmem_map) +void __init free_area_init_core(pg_data_t *pgdat, + unsigned long *zones_size, unsigned long *zholes_size) { unsigned long i, j; - unsigned long map_size; - unsigned long totalpages, offset, realtotalpages; + unsigned long local_offset; const unsigned long zone_required_alignment = 1UL << (MAX_ORDER-1); + int nid = pgdat->node_id; + struct page *lmem_map = pgdat->node_mem_map; + unsigned long zone_start_pfn = pgdat->node_start_pfn; - totalpages = 0; - for (i = 0; i < MAX_NR_ZONES; i++) - totalpages += zones_size[i]; - - realtotalpages = totalpages; - if (zholes_size) - for (i = 0; i < MAX_NR_ZONES; i++) - realtotalpages -= zholes_size[i]; - - printk("On node %d totalpages: %lu\n", nid, realtotalpages); - - /* - * Some architectures (with lots of mem and discontinous memory - * maps) have to search for a good mem_map area: - * For discontigmem, the conceptual mem map array starts from - * PAGE_OFFSET, we need to align the actual array onto a mem map - * boundary, so that MAP_NR works. - */ - map_size = (totalpages + 1)*sizeof(struct page); - if (lmem_map == (struct page *)0) { - lmem_map = (struct page *) alloc_bootmem_node(pgdat, map_size); - lmem_map = (struct page *)(PAGE_OFFSET + - MAP_ALIGN((unsigned long)lmem_map - PAGE_OFFSET)); - } - *gmap = pgdat->node_mem_map = lmem_map; - pgdat->node_size = totalpages; - pgdat->node_start_pfn = zone_start_pfn; - pgdat->node_start_mapnr = (lmem_map - mem_map); pgdat->nr_zones = 0; - - offset = lmem_map - mem_map; + local_offset = 0; /* offset within lmem_map */ for (j = 0; j < MAX_NR_ZONES; j++) { struct zone *zone = pgdat->node_zones + j; unsigned long mask; @@ -865,8 +874,7 @@ zone->pages_low = mask*2; zone->pages_high = mask*3; - zone->zone_mem_map = mem_map + offset; - zone->zone_start_mapnr = offset; + zone->zone_mem_map = lmem_map + local_offset; zone->zone_start_pfn = zone_start_pfn; if ((zone_start_pfn) & (zone_required_alignment-1)) @@ -878,7 +886,7 @@ * done. Non-atomic initialization, single-pass. */ for (i = 0; i < size; i++) { - struct page *page = mem_map + offset + i; + struct page *page = lmem_map + local_offset + i; set_page_zone(page, nid * MAX_NR_ZONES + j); set_page_count(page, 0); SetPageReserved(page); @@ -892,7 +900,7 @@ zone_start_pfn++; } - offset += size; + local_offset += size; for (i = 0; ; i++) { unsigned long bitmap_size; @@ -931,13 +939,15 @@ (unsigned long *) alloc_bootmem_node(pgdat, bitmap_size); } } - build_zonelists(pgdat); } +#ifndef CONFIG_DISCONTIGMEM void __init free_area_init(unsigned long *zones_size) { - free_area_init_core(0, &contig_page_data, &mem_map, zones_size, 0, 0, 0); + free_area_init_node(0, &contig_page_data, NULL, zones_size, 0, NULL); + mem_map = contig_page_data.node_mem_map; } +#endif static int __init setup_mem_frac(char *str) { diff -Nru a/mm/page_io.c b/mm/page_io.c --- a/mm/page_io.c Fri Sep 20 08:20:42 2002 +++ b/mm/page_io.c Fri Sep 20 08:20:42 2002 @@ -47,22 +47,29 @@ return bio; } -static void end_swap_bio_write(struct bio *bio) +static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; + if (bio->bi_size) + return 1; + if (!uptodate) SetPageError(page); end_page_writeback(page); bio_put(bio); + return 0; } -static void end_swap_bio_read(struct bio *bio) +static int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; + if (bio->bi_size) + return 1; + if (!uptodate) { SetPageError(page); ClearPageUptodate(page); @@ -71,6 +78,7 @@ } unlock_page(page); bio_put(bio); + return 0; } /* @@ -123,12 +131,12 @@ * Swap pages are !PageLocked and PageWriteback while under writeout so that * memory allocators will throttle against them. */ -static int swap_vm_writeback(struct page *page, int *nr_to_write) +static int swap_vm_writeback(struct page *page, struct writeback_control *wbc) { struct address_space *mapping = page->mapping; unlock_page(page); - return generic_writepages(mapping, nr_to_write); + return generic_writepages(mapping, wbc); } struct address_space_operations swap_aops = { diff -Nru a/mm/shmem.c b/mm/shmem.c --- a/mm/shmem.c Fri Sep 20 08:20:45 2002 +++ b/mm/shmem.c Fri Sep 20 08:20:45 2002 @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff -Nru a/mm/slab.c b/mm/slab.c --- a/mm/slab.c Fri Sep 20 08:20:47 2002 +++ b/mm/slab.c Fri Sep 20 08:20:47 2002 @@ -545,6 +545,7 @@ */ while (i--) { ClearPageSlab(page); + dec_page_state(nr_slab); page++; } free_pages((unsigned long)addr, cachep->gfporder); @@ -1203,6 +1204,7 @@ SET_PAGE_CACHE(page, cachep); SET_PAGE_SLAB(page, slabp); SetPageSlab(page); + inc_page_state(nr_slab); page++; } while (--i); @@ -1545,8 +1547,7 @@ STATS_INC_FREEMISS(cachep); batchcount = cachep->batchcount; cc->avail -= batchcount; - free_block(cachep, - &cc_entry(cc)[cc->avail],batchcount); + free_block(cachep, &cc_entry(cc)[cc->avail], batchcount); cc_entry(cc)[cc->avail++] = objp; return; } else { @@ -1727,8 +1728,13 @@ return 0; } +/* + * If slab debugging is enabled, don't batch slabs + * on the per-cpu lists by defaults. + */ static void enable_cpucache (kmem_cache_t *cachep) { +#ifndef CONFIG_DEBUG_SLAB int err; int limit; @@ -1746,6 +1752,7 @@ if (err) printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n", cachep->name, -err); +#endif } static void enable_all_cpucaches (void) diff -Nru a/mm/swap.c b/mm/swap.c --- a/mm/swap.c Fri Sep 20 08:20:44 2002 +++ b/mm/swap.c Fri Sep 20 08:20:44 2002 @@ -124,9 +124,9 @@ if (page_count(page) == 0) { if (!pagevec_add(&pages_to_free, page)) { spin_unlock_irq(&zone->lru_lock); - pagevec_free(&pages_to_free); + __pagevec_free(&pages_to_free); pagevec_init(&pages_to_free); - spin_lock_irq(&zone->lru_lock); + zone = NULL; /* No lock is held */ } } } @@ -165,8 +165,8 @@ } /* - * Move all the inactive pages to the head of the inactive list - * and release them. Reinitialises the caller's pagevec. + * Move all the inactive pages to the head of the inactive list and release + * them. Reinitialises the caller's pagevec. */ void pagevec_deactivate_inactive(struct pagevec *pvec) { @@ -180,8 +180,6 @@ struct zone *pagezone = page_zone(page); if (pagezone != zone) { - if (PageActive(page) || !PageLRU(page)) - continue; if (zone) spin_unlock_irq(&zone->lru_lock); zone = pagezone; diff -Nru a/mm/swap_state.c b/mm/swap_state.c --- a/mm/swap_state.c Fri Sep 20 08:20:45 2002 +++ b/mm/swap_state.c Fri Sep 20 08:20:45 2002 @@ -12,7 +12,6 @@ #include #include #include -#include #include #include /* block_sync_page() */ @@ -119,7 +118,7 @@ int add_to_swap(struct page * page) { swp_entry_t entry; - int flags; + int pf_flags; if (!PageLocked(page)) BUG(); @@ -142,7 +141,7 @@ * just not all of them. */ - flags = current->flags; + pf_flags = current->flags; current->flags &= ~PF_MEMALLOC; current->flags |= PF_NOWARN; ClearPageUptodate(page); /* why? */ @@ -154,20 +153,20 @@ */ switch (add_to_swap_cache(page, entry)) { case 0: /* Success */ - current->flags = flags; + current->flags = pf_flags; SetPageUptodate(page); set_page_dirty(page); swap_free(entry); return 1; case -ENOMEM: /* radix-tree allocation */ - current->flags = flags; + current->flags = pf_flags; swap_free(entry); return 0; default: /* ENOENT: raced */ break; } /* Raced with "speculative" read_swap_cache_async */ - current->flags = flags; + current->flags = pf_flags; swap_free(entry); } } diff -Nru a/mm/swapfile.c b/mm/swapfile.c --- a/mm/swapfile.c Fri Sep 20 08:20:43 2002 +++ b/mm/swapfile.c Fri Sep 20 08:20:43 2002 @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff -Nru a/mm/vmscan.c b/mm/vmscan.c --- a/mm/vmscan.c Fri Sep 20 08:20:42 2002 +++ b/mm/vmscan.c Fri Sep 20 08:20:42 2002 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -145,6 +144,7 @@ if (!add_to_swap(page)) goto activate_locked; pte_chain_lock(page); + mapping = page->mapping; } /* @@ -174,15 +174,18 @@ */ if (PageDirty(page) && is_page_cache_freeable(page) && mapping && may_enter_fs) { - int (*writeback)(struct page *, int *); + int (*writeback)(struct page *, + struct writeback_control *); const int cluster_size = SWAP_CLUSTER_MAX; - int nr_to_write = cluster_size; + struct writeback_control wbc = { + .nr_to_write = cluster_size, + }; writeback = mapping->a_ops->vm_writeback; if (writeback == NULL) writeback = generic_vm_writeback; - (*writeback)(page, &nr_to_write); - *max_scan -= (cluster_size - nr_to_write); + (*writeback)(page, &wbc); + *max_scan -= (cluster_size - wbc.nr_to_write); goto keep; } diff -Nru a/net/Config.in b/net/Config.in --- a/net/Config.in Fri Sep 20 08:20:43 2002 +++ b/net/Config.in Fri Sep 20 08:20:43 2002 @@ -65,6 +65,9 @@ source net/decnet/Config.in fi dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET +if [ "$CONFIG_BRIDGE" != "n" -a "$CONFIG_NETFILTER" != "n" ]; then + source net/bridge/netfilter/Config.in +fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25 tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB diff -Nru a/net/Makefile b/net/Makefile --- a/net/Makefile Fri Sep 20 08:20:45 2002 +++ b/net/Makefile Fri Sep 20 08:20:45 2002 @@ -5,9 +5,6 @@ # Rewritten to use lists instead of if-statements. # -O_TARGET := network.o - - export-objs := netsyms.o obj-y := socket.o core/ diff -Nru a/net/ax25/Config.in b/net/ax25/Config.in --- a/net/ax25/Config.in Fri Sep 20 08:20:47 2002 +++ b/net/ax25/Config.in Fri Sep 20 08:20:47 2002 @@ -1,7 +1,7 @@ # # Amateur Radio protocols and AX.25 device configuration # -# 19971130 Now in an own category to make correct compilation of the +# 19971130 Now in an own category to make correct compilation of the # AX.25 stuff easier... # Joerg Reuter DL1BKE # 19980129 Moved to net/ax25/Config.in, sourcing device drivers. diff -Nru a/net/ax25/TODO b/net/ax25/TODO --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ax25/TODO Fri Sep 20 08:20:49 2002 @@ -0,0 +1,24 @@ +Do the ax25_list_lock, ax25_dev_lock, linkfail_lockreally, ax25_frag_lock and +listen_lock have to be bh-safe? + +Do the netrom and rose locks have to be bh-safe? + +A device might be deleted after lookup in the SIOCADDRT ioctl but before it's +being used. + +Routes to a device being taken down might be deleted by ax25_rt_device_down +but added by somebody else before the device has been deleted fully. + +Massive amounts of lock_kernel / unlock_kernel are just a temporary solution to +get around the removal of SOCKOPS_WRAP. A serious locking strategy has to be +implemented. + +The ax25_rt_find_route synopsys is pervert but I somehow had to deal with +the race caused by the static variable in it's previous implementation. + +Implement proper socket locking in netrom and rose. + +Check socket locking when ax25_rcv is sending to raw sockets. In particular +ax25_send_to_raw() seems fishy. Heck - ax25_rcv is fishy. + +Handle XID and TEST frames properly. diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c --- a/net/ax25/af_ax25.c Fri Sep 20 08:20:47 2002 +++ b/net/ax25/af_ax25.c Fri Sep 20 08:20:47 2002 @@ -1,109 +1,18 @@ /* - * AX.25 release 038 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * AX.25 006 Alan(GW4PTS) Nearly died of shock - it's working 8-) - * AX.25 007 Alan(GW4PTS) Removed the silliest bugs - * AX.25 008 Alan(GW4PTS) Cleaned up, fixed a few state machine problems, added callbacks - * AX.25 009 Alan(GW4PTS) Emergency patch kit to fix memory corruption - * AX.25 010 Alan(GW4PTS) Added RAW sockets/Digipeat. - * AX.25 011 Alan(GW4PTS) RAW socket and datagram fixes (thanks) - Raw sendto now gets PID right - * datagram sendto uses correct target address. - * AX.25 012 Alan(GW4PTS) Correct incoming connection handling, send DM to failed connects. - * Use skb->data not skb+1. Support sk->priority correctly. - * Correct receive on SOCK_DGRAM. - * AX.25 013 Alan(GW4PTS) Send DM to all unknown frames, missing initialiser fixed - * Leave spare SSID bits set (DAMA etc) - thanks for bug report, - * removed device registration (it's not used or needed). Clean up for - * gcc 2.5.8. PID to AX25_P_ - * AX.25 014 Alan(GW4PTS) Cleanup and NET3 merge - * AX.25 015 Alan(GW4PTS) Internal test version. - * AX.25 016 Alan(GW4PTS) Semi Internal version for PI card - * work. - * AX.25 017 Alan(GW4PTS) Fixed some small bugs reported by - * G4KLX - * AX.25 018 Alan(GW4PTS) Fixed a small error in SOCK_DGRAM - * AX.25 019 Alan(GW4PTS) Clean ups for the non INET kernel and device ioctls in AX.25 - * AX.25 020 Jonathan(G4KLX) /proc support and other changes. - * AX.25 021 Alan(GW4PTS) Added AX25_T1, AX25_N2, AX25_T3 as requested. - * AX.25 022 Jonathan(G4KLX) More work on the ax25 auto router and /proc improved (again)! - * Alan(GW4PTS) Added TIOCINQ/OUTQ - * AX.25 023 Alan(GW4PTS) Fixed shutdown bug - * AX.25 023 Alan(GW4PTS) Linus changed timers - * AX.25 024 Alan(GW4PTS) Small bug fixes - * AX.25 025 Alan(GW4PTS) More fixes, Linux 1.1.51 compatibility stuff, timers again! - * AX.25 026 Alan(GW4PTS) Small state fix. - * AX.25 027 Alan(GW4PTS) Socket close crash fixes. - * AX.25 028 Alan(GW4PTS) Callsign control including settings per uid. - * Small bug fixes. - * Protocol set by sockets only. - * Small changes to allow for start of NET/ROM layer. - * AX.25 028a Jonathan(G4KLX) Changes to state machine. - * AX.25 028b Jonathan(G4KLX) Extracted ax25 control block - * from sock structure. - * AX.25 029 Alan(GW4PTS) Combined 028b and some KA9Q code - * Jonathan(G4KLX) and removed all the old Berkeley, added IP mode registration. - * Darryl(G7LED) stuff. Cross-port digipeating. Minor fixes and enhancements. - * Alan(GW4PTS) Missed suser() on axassociate checks - * AX.25 030 Alan(GW4PTS) Added variable length headers. - * Jonathan(G4KLX) Added BPQ Ethernet interface. - * Steven(GW7RRM) Added digi-peating control ioctl. - * Added extended AX.25 support. - * Added AX.25 frame segmentation. - * Darryl(G7LED) Changed connect(), recvfrom(), sendto() sockaddr/addrlen to - * fall inline with bind() and new policy. - * Moved digipeating ctl to new ax25_dev structs. - * Fixed ax25_release(), set TCP_CLOSE, wakeup app - * context, THEN make the sock dead. - * Alan(GW4PTS) Cleaned up for single recvmsg methods. - * Alan(GW4PTS) Fixed not clearing error on connect failure. - * AX.25 031 Jonathan(G4KLX) Added binding to any device. - * Joerg(DL1BKE) Added DAMA support, fixed (?) digipeating, fixed buffer locking - * for "virtual connect" mode... Result: Probably the - * "Most Buggiest Code You've Ever Seen" (TM) - * HaJo(DD8NE) Implementation of a T5 (idle) timer - * Joerg(DL1BKE) Renamed T5 to IDLE and changed behaviour: - * the timer gets reloaded on every received or transmitted - * I frame for IP or NETROM. The idle timer is not active - * on "vanilla AX.25" connections. Furthermore added PACLEN - * to provide AX.25-layer based fragmentation (like WAMPES) - * AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout error. - * ax25_send_frame() limits the number of enqueued - * datagrams per socket. - * AX.25 033 Jonathan(G4KLX) Removed auto-router. - * Hans(PE1AYX) Converted to Module. - * Joerg(DL1BKE) Moved BPQ Ethernet to separate driver. - * AX.25 034 Jonathan(G4KLX) 2.1 changes - * Alan(GW4PTS) Small POSIXisations - * AX.25 035 Alan(GW4PTS) Started fixing to the new - * format. - * Hans(PE1AYX) Fixed interface to IP layer. - * Alan(GW4PTS) Added asynchronous support. - * Frederic(F1OAT) Support for pseudo-digipeating. - * Jonathan(G4KLX) Support for packet forwarding. - * AX.25 036 Jonathan(G4KLX) Major restructuring. - * Joerg(DL1BKE) Fixed DAMA Slave. - * Jonathan(G4KLX) Fix wildcard listen parameter setting. - * AX.25 037 Jonathan(G4KLX) New timer architecture. - * AX.25 038 Matthias(DG2FEF) Small fixes to the syscall interface to make kernel - * independent of AX25_MAX_DIGIS used by applications. - * Tomi(OH2BNS) Fixed ax25_getname(). - * Joerg(DL1BKE) Starting to phase out the support for full_sockaddr_ax25 - * with only 6 digipeaters and sockaddr_ax25 in ax25_bind(), - * ax25_connect() and ax25_sendmsg() - * Joerg(DL1BKE) Added support for SO_BINDTODEVICE - * Arnaldo C. Melo s/suser/capable(CAP_NET_ADMIN)/, some more cleanups - * Michal Ostrowski Module initialization cleanup. + * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk) + * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) + * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de) + * Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl) + * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) */ - #include #include #include @@ -114,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -134,13 +44,15 @@ #include #include #include +#include #include #include #include -ax25_cb *volatile ax25_list; +ax25_cb *ax25_list; +spinlock_t ax25_list_lock = SPIN_LOCK_UNLOCKED; static struct proto_ops ax25_proto_ops; @@ -171,27 +83,24 @@ static void ax25_remove_socket(ax25_cb *ax25) { ax25_cb *s; - unsigned long flags; - - save_flags(flags); cli(); + spin_lock_bh(&ax25_list_lock); if ((s = ax25_list) == ax25) { ax25_list = s->next; - restore_flags(flags); + spin_unlock_bh(&ax25_list_lock); return; } while (s != NULL && s->next != NULL) { if (s->next == ax25) { s->next = ax25->next; - restore_flags(flags); + spin_unlock_bh(&ax25_list_lock); return; } s = s->next; } - - restore_flags(flags); + spin_unlock_bh(&ax25_list_lock); } /* @@ -205,18 +114,21 @@ if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) return; + spin_lock_bh(&ax25_list_lock); for (s = ax25_list; s != NULL; s = s->next) { if (s->ax25_dev == ax25_dev) { s->ax25_dev = NULL; ax25_disconnect(s, ENETUNREACH); } } + spin_unlock_bh(&ax25_list_lock); } /* * Handle device status changes. */ -static int ax25_device_event(struct notifier_block *this,unsigned long event, void *ptr) +static int ax25_device_event(struct notifier_block *this, unsigned long event, + void *ptr) { struct net_device *dev = (struct net_device *)ptr; @@ -225,16 +137,16 @@ return NOTIFY_DONE; switch (event) { - case NETDEV_UP: - ax25_dev_device_up(dev); - break; - case NETDEV_DOWN: - ax25_kill_by_device(dev); - ax25_rt_device_down(dev); - ax25_dev_device_down(dev); - break; - default: - break; + case NETDEV_UP: + ax25_dev_device_up(dev); + break; + case NETDEV_DOWN: + ax25_kill_by_device(dev); + ax25_rt_device_down(dev); + ax25_dev_device_down(dev); + break; + default: + break; } return NOTIFY_DONE; @@ -245,80 +157,73 @@ */ void ax25_insert_socket(ax25_cb *ax25) { - unsigned long flags; - - save_flags(flags); - cli(); - + spin_lock_bh(&ax25_list_lock); ax25->next = ax25_list; ax25_list = ax25; - - restore_flags(flags); + spin_unlock_bh(&ax25_list_lock); } /* * Find a socket that wants to accept the SABM we have just * received. */ -struct sock *ax25_find_listener(ax25_address *addr, int digi, struct net_device *dev, int type) +struct sock *ax25_find_listener(ax25_address *addr, int digi, + struct net_device *dev, int type) { - unsigned long flags; ax25_cb *s; - save_flags(flags); - cli(); - + spin_lock_bh(&ax25_list_lock); for (s = ax25_list; s != NULL; s = s->next) { if ((s->iamdigi && !digi) || (!s->iamdigi && digi)) continue; if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == type && s->sk->state == TCP_LISTEN) { /* If device is null we match any device */ if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) { - restore_flags(flags); + spin_unlock_bh(&ax25_list_lock); + return s->sk; } } } + spin_unlock_bh(&ax25_list_lock); - restore_flags(flags); return NULL; } /* * Find an AX.25 socket given both ends. */ -struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, int type) +struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr, + int type) { + struct sock *sk = NULL; ax25_cb *s; - unsigned long flags; - - save_flags(flags); - cli(); + spin_lock_bh(&ax25_list_lock); for (s = ax25_list; s != NULL; s = s->next) { if (s->sk != NULL && ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->sk->type == type) { - restore_flags(flags); - return s->sk; + sk = s->sk; + /* XXX Sleeps with spinlock held, use refcounts instead. XXX */ + lock_sock(sk); + break; } } - restore_flags(flags); + spin_unlock_bh(&ax25_list_lock); - return NULL; + return sk; } /* * Find an AX.25 control block given both ends. It will only pick up * floating AX.25 control blocks or non Raw socket bound control blocks. */ -ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi *digi, struct net_device *dev) +ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, + ax25_digi *digi, struct net_device *dev) { ax25_cb *s; - unsigned long flags; - - save_flags(flags); - cli(); + spin_lock_bh(&ax25_list_lock); for (s = ax25_list; s != NULL; s = s->next) { if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET) continue; @@ -334,12 +239,12 @@ if (s->digipeat != NULL && s->digipeat->ndigi != 0) continue; } - restore_flags(flags); + spin_unlock_bh(&ax25_list_lock); + return s; } } - - restore_flags(flags); + spin_unlock_bh(&ax25_list_lock); return NULL; } @@ -349,22 +254,21 @@ */ struct sock *ax25_addr_match(ax25_address *addr) { - unsigned long flags; + struct sock *sk = NULL; ax25_cb *s; - save_flags(flags); - cli(); - + spin_lock_bh(&ax25_list_lock); for (s = ax25_list; s != NULL; s = s->next) { - if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == SOCK_RAW) { - restore_flags(flags); - return s->sk; + if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && + s->sk->type == SOCK_RAW) { + sk = s->sk; + lock_sock(sk); + break; } } + spin_unlock_bh(&ax25_list_lock); - restore_flags(flags); - - return NULL; + return sk; } void ax25_send_to_raw(struct sock *sk, struct sk_buff *skb, int proto) @@ -400,17 +304,16 @@ } /* - * This is called from user mode and the timers. Thus it protects itself against - * interrupt users but doesn't worry about being called during work. - * Once it is removed from the queue no interrupt or bottom half will - * touch it and we are (fairly 8-) ) safe. + * This is called from user mode and the timers. Thus it protects itself + * against interrupt users but doesn't worry about being called during + * work. Once it is removed from the queue no interrupt or bottom half + * will touch it and we are (fairly 8-) ) safe. */ -void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer */ +void ax25_destroy_socket(ax25_cb *ax25) { struct sk_buff *skb; - unsigned long flags; - save_flags(flags); cli(); + ax25_remove_socket(ax25); ax25_stop_heartbeat(ax25); ax25_stop_t1timer(ax25); @@ -418,15 +321,17 @@ ax25_stop_t3timer(ax25); ax25_stop_idletimer(ax25); - ax25_remove_socket(ax25); ax25_clear_queues(ax25); /* Flush the queues */ if (ax25->sk != NULL) { while ((skb = skb_dequeue(&ax25->sk->receive_queue)) != NULL) { - if (skb->sk != ax25->sk) { /* A pending connection */ + if (skb->sk != ax25->sk) { + /* A pending connection */ ax25_cb *sax25 = ax25_sk(skb->sk); - skb->sk->dead = 1; /* Queue the unaccepted socket for death */ + /* Queue the unaccepted socket for death */ + skb->sk->dead = 1; + ax25_start_heartbeat(sax25); sax25->state = AX25_STATE_0; } @@ -450,8 +355,6 @@ } else { ax25_free_cb(ax25); } - - restore_flags(flags); } /* @@ -484,66 +387,66 @@ return -ENOTCONN; switch (ax25_ctl.cmd) { - case AX25_KILL: - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + case AX25_KILL: + ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); #ifdef CONFIG_AX25_DAMA_SLAVE - if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) - ax25_dama_off(ax25); + if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) + ax25_dama_off(ax25); #endif - ax25_disconnect(ax25, ENETRESET); - break; - - case AX25_WINDOW: - if (ax25->modulus == AX25_MODULUS) { - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7) - return -EINVAL; - } else { - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63) - return -EINVAL; - } - ax25->window = ax25_ctl.arg; - break; + ax25_disconnect(ax25, ENETRESET); + break; - case AX25_T1: - if (ax25_ctl.arg < 1) + case AX25_WINDOW: + if (ax25->modulus == AX25_MODULUS) { + if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7) return -EINVAL; - ax25->rtt = (ax25_ctl.arg * HZ) / 2; - ax25->t1 = ax25_ctl.arg * HZ; - break; - - case AX25_T2: - if (ax25_ctl.arg < 1) - return -EINVAL; - ax25->t2 = ax25_ctl.arg * HZ; - break; - - case AX25_N2: - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31) - return -EINVAL; - ax25->n2count = 0; - ax25->n2 = ax25_ctl.arg; - break; - - case AX25_T3: - if (ax25_ctl.arg < 0) - return -EINVAL; - ax25->t3 = ax25_ctl.arg * HZ; - break; - - case AX25_IDLE: - if (ax25_ctl.arg < 0) - return -EINVAL; - ax25->idle = ax25_ctl.arg * 60 * HZ; - break; - - case AX25_PACLEN: - if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) - return -EINVAL; - ax25->paclen = ax25_ctl.arg; - break; + } else { + if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63) + return -EINVAL; + } + ax25->window = ax25_ctl.arg; + break; + + case AX25_T1: + if (ax25_ctl.arg < 1) + return -EINVAL; + ax25->rtt = (ax25_ctl.arg * HZ) / 2; + ax25->t1 = ax25_ctl.arg * HZ; + break; + + case AX25_T2: + if (ax25_ctl.arg < 1) + return -EINVAL; + ax25->t2 = ax25_ctl.arg * HZ; + break; + + case AX25_N2: + if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31) + return -EINVAL; + ax25->n2count = 0; + ax25->n2 = ax25_ctl.arg; + break; + + case AX25_T3: + if (ax25_ctl.arg < 0) + return -EINVAL; + ax25->t3 = ax25_ctl.arg * HZ; + break; + + case AX25_IDLE: + if (ax25_ctl.arg < 0) + return -EINVAL; + ax25->idle = ax25_ctl.arg * 60 * HZ; + break; + + case AX25_PACLEN: + if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) + return -EINVAL; + ax25->paclen = ax25_ctl.arg; + break; - default: - return -EINVAL; + default: + return -EINVAL; } return 0; @@ -631,13 +534,14 @@ * AX25 socket object */ -static int ax25_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) +static int ax25_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) { struct sock *sk = sock->sk; - ax25_cb *ax25 = ax25_sk(sk); + ax25_cb *ax25; struct net_device *dev; char devname[IFNAMSIZ]; - int opt; + int opt, res = 0; if (level != SOL_AX25) return -ENOPROTOOPT; @@ -648,98 +552,131 @@ if (get_user(opt, (int *)optval)) return -EFAULT; + lock_sock(sk); + ax25 = ax25_sk(sk); + switch (optname) { - case AX25_WINDOW: - if (ax25->modulus == AX25_MODULUS) { - if (opt < 1 || opt > 7) - return -EINVAL; - } else { - if (opt < 1 || opt > 63) - return -EINVAL; + case AX25_WINDOW: + if (ax25->modulus == AX25_MODULUS) { + if (opt < 1 || opt > 7) { + res = -EINVAL; + break; } - ax25->window = opt; - return 0; + } else { + if (opt < 1 || opt > 63) { + res = -EINVAL; + break; + } + } + ax25->window = opt; + break; + + case AX25_T1: + if (opt < 1) { + res = -EINVAL; + break; + } + ax25->rtt = (opt * HZ) / 2; + ax25->t1 = opt * HZ; + break; - case AX25_T1: - if (opt < 1) - return -EINVAL; - ax25->rtt = (opt * HZ) / 2; - ax25->t1 = opt * HZ; - return 0; - - case AX25_T2: - if (opt < 1) - return -EINVAL; - ax25->t2 = opt * HZ; - return 0; - - case AX25_N2: - if (opt < 1 || opt > 31) - return -EINVAL; - ax25->n2 = opt; - return 0; - - case AX25_T3: - if (opt < 1) - return -EINVAL; - ax25->t3 = opt * HZ; - return 0; - - case AX25_IDLE: - if (opt < 0) - return -EINVAL; - ax25->idle = opt * 60 * HZ; - return 0; - - case AX25_BACKOFF: - if (opt < 0 || opt > 2) - return -EINVAL; - ax25->backoff = opt; - return 0; - - case AX25_EXTSEQ: - ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS; - return 0; - - case AX25_PIDINCL: - ax25->pidincl = opt ? 1 : 0; - return 0; - - case AX25_IAMDIGI: - ax25->iamdigi = opt ? 1 : 0; - return 0; - - case AX25_PACLEN: - if (opt < 16 || opt > 65535) - return -EINVAL; - ax25->paclen = opt; - return 0; - - case SO_BINDTODEVICE: - if (optlen > IFNAMSIZ) optlen=IFNAMSIZ; - if (copy_from_user(devname, optval, optlen)) - return -EFAULT; - - dev = dev_get_by_name(devname); - if (dev == NULL) return -ENODEV; - - if (sk->type == SOCK_SEQPACKET && - (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN)) - return -EADDRNOTAVAIL; - - ax25->ax25_dev = ax25_dev_ax25dev(dev); - ax25_fillin_cb(ax25, ax25->ax25_dev); - return 0; + case AX25_T2: + if (opt < 1) { + res = -EINVAL; + break; + } + ax25->t2 = opt * HZ; + break; - default: - return -ENOPROTOOPT; + case AX25_N2: + if (opt < 1 || opt > 31) { + res = -EINVAL; + break; + } + ax25->n2 = opt; + break; + + case AX25_T3: + if (opt < 1) { + res = -EINVAL; + break; + } + ax25->t3 = opt * HZ; + break; + + case AX25_IDLE: + if (opt < 0) { + res = -EINVAL; + break; + } + ax25->idle = opt * 60 * HZ; + break; + + case AX25_BACKOFF: + if (opt < 0 || opt > 2) { + res = -EINVAL; + break; + } + ax25->backoff = opt; + break; + + case AX25_EXTSEQ: + ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS; + break; + + case AX25_PIDINCL: + ax25->pidincl = opt ? 1 : 0; + break; + + case AX25_IAMDIGI: + ax25->iamdigi = opt ? 1 : 0; + break; + + case AX25_PACLEN: + if (opt < 16 || opt > 65535) { + res = -EINVAL; + break; + } + ax25->paclen = opt; + break; + + case SO_BINDTODEVICE: + if (optlen > IFNAMSIZ) + optlen=IFNAMSIZ; + if (copy_from_user(devname, optval, optlen)) { + res = -EFAULT; + break; + } + + dev = dev_get_by_name(devname); + if (dev == NULL) { + res = -ENODEV; + break; + } + + if (sk->type == SOCK_SEQPACKET && + (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN)) { + res = -EADDRNOTAVAIL; + break; + } + + ax25->ax25_dev = ax25_dev_ax25dev(dev); + ax25_fillin_cb(ax25, ax25->ax25_dev); + break; + + default: + res = -ENOPROTOOPT; } + release_sock(sk); + + return res; } -static int ax25_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) +static int ax25_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) { struct sock *sk = sock->sk; - ax25_cb *ax25 = ax25_sk(sk); + ax25_cb *ax25; struct ax25_dev *ax25_dev; char devname[IFNAMSIZ]; void *valptr; @@ -751,76 +688,81 @@ if (get_user(maxlen, optlen)) return -EFAULT; - + if (maxlen < 1) return -EFAULT; valptr = (void *) &val; length = min_t(unsigned int, maxlen, sizeof(int)); - switch (optname) { - case AX25_WINDOW: - val = ax25->window; - break; - - case AX25_T1: - val = ax25->t1 / HZ; - break; - - case AX25_T2: - val = ax25->t2 / HZ; - break; - - case AX25_N2: - val = ax25->n2; - break; - - case AX25_T3: - val = ax25->t3 / HZ; - break; - - case AX25_IDLE: - val = ax25->idle / (60 * HZ); - break; - - case AX25_BACKOFF: - val = ax25->backoff; - break; - - case AX25_EXTSEQ: - val = (ax25->modulus == AX25_EMODULUS); - break; - - case AX25_PIDINCL: - val = ax25->pidincl; - break; - - case AX25_IAMDIGI: - val = ax25->iamdigi; - break; - - case AX25_PACLEN: - val = ax25->paclen; - break; - - case SO_BINDTODEVICE: - ax25_dev = ax25->ax25_dev; + lock_sock(sk); + ax25 = ax25_sk(sk); - if (ax25_dev != NULL && ax25_dev->dev != NULL) { - strncpy(devname, ax25_dev->dev->name, IFNAMSIZ); - length = min_t(unsigned int, strlen(ax25_dev->dev->name)+1, maxlen); - devname[length-1] = '\0'; - } else { - *devname = '\0'; - length = 1; - } + switch (optname) { + case AX25_WINDOW: + val = ax25->window; + break; + + case AX25_T1: + val = ax25->t1 / HZ; + break; + + case AX25_T2: + val = ax25->t2 / HZ; + break; + + case AX25_N2: + val = ax25->n2; + break; + + case AX25_T3: + val = ax25->t3 / HZ; + break; + + case AX25_IDLE: + val = ax25->idle / (60 * HZ); + break; + + case AX25_BACKOFF: + val = ax25->backoff; + break; + + case AX25_EXTSEQ: + val = (ax25->modulus == AX25_EMODULUS); + break; + + case AX25_PIDINCL: + val = ax25->pidincl; + break; + + case AX25_IAMDIGI: + val = ax25->iamdigi; + break; + + case AX25_PACLEN: + val = ax25->paclen; + break; + + case SO_BINDTODEVICE: + ax25_dev = ax25->ax25_dev; + + if (ax25_dev != NULL && ax25_dev->dev != NULL) { + strncpy(devname, ax25_dev->dev->name, IFNAMSIZ); + length = min_t(unsigned int, strlen(ax25_dev->dev->name)+1, maxlen); + devname[length-1] = '\0'; + } else { + *devname = '\0'; + length = 1; + } - valptr = (void *) devname; - break; + valptr = (void *) devname; + break; - default: - return -ENOPROTOOPT; + default: + release_sock(sk); + return -ENOPROTOOPT; } + release_sock(sk); if (put_user(length, optlen)) return -EFAULT; @@ -831,14 +773,20 @@ static int ax25_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; + int res = 0; + lock_sock(sk); if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) { sk->max_ack_backlog = backlog; sk->state = TCP_LISTEN; - return 0; + goto out; } + res = -EOPNOTSUPP; - return -EOPNOTSUPP; +out: + release_sock(sk); + + return res; } int ax25_create(struct socket *sock, int protocol) @@ -847,46 +795,48 @@ ax25_cb *ax25; switch (sock->type) { - case SOCK_DGRAM: - if (protocol == 0 || protocol == PF_AX25) - protocol = AX25_P_TEXT; - break; - case SOCK_SEQPACKET: - switch (protocol) { - case 0: - case PF_AX25: /* For CLX */ - protocol = AX25_P_TEXT; - break; - case AX25_P_SEGMENT: + case SOCK_DGRAM: + if (protocol == 0 || protocol == PF_AX25) + protocol = AX25_P_TEXT; + break; + + case SOCK_SEQPACKET: + switch (protocol) { + case 0: + case PF_AX25: /* For CLX */ + protocol = AX25_P_TEXT; + break; + case AX25_P_SEGMENT: #ifdef CONFIG_INET - case AX25_P_ARP: - case AX25_P_IP: + case AX25_P_ARP: + case AX25_P_IP: #endif #ifdef CONFIG_NETROM - case AX25_P_NETROM: + case AX25_P_NETROM: #endif #ifdef CONFIG_ROSE - case AX25_P_ROSE: + case AX25_P_ROSE: #endif - return -ESOCKTNOSUPPORT; + return -ESOCKTNOSUPPORT; #ifdef CONFIG_NETROM_MODULE - case AX25_P_NETROM: - if (ax25_protocol_is_registered(AX25_P_NETROM)) - return -ESOCKTNOSUPPORT; + case AX25_P_NETROM: + if (ax25_protocol_is_registered(AX25_P_NETROM)) + return -ESOCKTNOSUPPORT; #endif #ifdef CONFIG_ROSE_MODULE - case AX25_P_ROSE: - if (ax25_protocol_is_registered(AX25_P_ROSE)) - return -ESOCKTNOSUPPORT; + case AX25_P_ROSE: + if (ax25_protocol_is_registered(AX25_P_ROSE)) + return -ESOCKTNOSUPPORT; #endif - default: - break; - } - break; - case SOCK_RAW: - break; default: - return -ESOCKTNOSUPPORT; + break; + } + break; + + case SOCK_RAW: + break; + default: + return -ESOCKTNOSUPPORT; } if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1, NULL)) == NULL) @@ -923,14 +873,14 @@ } switch (osk->type) { - case SOCK_DGRAM: - break; - case SOCK_SEQPACKET: - break; - default: - sk_free(sk); - ax25_free_cb(ax25); - return NULL; + case SOCK_DGRAM: + break; + case SOCK_SEQPACKET: + break; + default: + sk_free(sk); + ax25_free_cb(ax25); + return NULL; } sock_init_data(NULL, sk); @@ -985,58 +935,61 @@ struct sock *sk = sock->sk; ax25_cb *ax25; - if (sk == NULL) return 0; + if (sk == NULL) + return 0; + lock_sock(sk); ax25 = ax25_sk(sk); if (sk->type == SOCK_SEQPACKET) { switch (ax25->state) { - case AX25_STATE_0: - ax25_disconnect(ax25, 0); - ax25_destroy_socket(ax25); - break; + case AX25_STATE_0: + ax25_disconnect(ax25, 0); + ax25_destroy_socket(ax25); + break; - case AX25_STATE_1: - case AX25_STATE_2: - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25_disconnect(ax25, 0); - ax25_destroy_socket(ax25); - break; + case AX25_STATE_1: + case AX25_STATE_2: + ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + ax25_disconnect(ax25, 0); + ax25_destroy_socket(ax25); + break; - case AX25_STATE_3: - case AX25_STATE_4: - ax25_clear_queues(ax25); - ax25->n2count = 0; - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_send_control(ax25, - AX25_DISC, - AX25_POLLON, - AX25_COMMAND); - ax25_stop_t2timer(ax25); - ax25_stop_t3timer(ax25); - ax25_stop_idletimer(ax25); - break; + case AX25_STATE_3: + case AX25_STATE_4: + ax25_clear_queues(ax25); + ax25->n2count = 0; + + switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_send_control(ax25, + AX25_DISC, + AX25_POLLON, + AX25_COMMAND); + ax25_stop_t2timer(ax25); + ax25_stop_t3timer(ax25); + ax25_stop_idletimer(ax25); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - ax25_stop_t3timer(ax25); - ax25_stop_idletimer(ax25); - break; -#endif - } - ax25_calculate_t1(ax25); - ax25_start_t1timer(ax25); - ax25->state = AX25_STATE_2; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; - sk->destroy = 1; + case AX25_PROTO_DAMA_SLAVE: + ax25_stop_t3timer(ax25); + ax25_stop_idletimer(ax25); break; +#endif + } + ax25_calculate_t1(ax25); + ax25_start_t1timer(ax25); + ax25->state = AX25_STATE_2; + sk->state = TCP_CLOSE; + sk->shutdown |= SEND_SHUTDOWN; + sk->state_change(sk); + sk->dead = 1; + sk->destroy = 1; + break; - default: - break; + default: + break; } } else { sk->state = TCP_CLOSE; @@ -1046,8 +999,9 @@ ax25_destroy_socket(ax25); } - sock->sk = NULL; + sock->sk = NULL; sk->socket = NULL; /* Not used, but we should do this */ + release_sock(sk); return 0; } @@ -1055,26 +1009,25 @@ /* * We support a funny extension here so you can (as root) give any callsign * digipeated via a local address as source. This hack is obsolete now - * that we've implemented support for SO_BINDTODEVICE. It is however small + * that we've implemented support for SO_BINDTODEVICE. It is however small * and trivially backward compatible. */ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sock *sk = sock->sk; - ax25_cb *ax25 = ax25_sk(sk); struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; - ax25_address *call; ax25_dev *ax25_dev = NULL; + ax25_address *call; + ax25_cb *ax25; + int err = 0; - if (sk->zapped == 0) - return -EINVAL; - - if (addr_len != sizeof(struct sockaddr_ax25) && + if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) { /* support for old structure may go away some time */ if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) + (addr_len > sizeof(struct full_sockaddr_ax25))) { return -EINVAL; + } printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n", current->comm); @@ -1084,8 +1037,17 @@ return -EINVAL; call = ax25_findbyuid(current->euid); - if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) + if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) { return -EACCES; + } + + lock_sock(sk); + + ax25 = ax25_sk(sk); + if (sk->zapped == 0) { + err = -EINVAL; + goto out; + } if (call == NULL) ax25->source_addr = addr->fsa_ax25.sax25_call; @@ -1095,17 +1057,20 @@ /* * User already set interface with SO_BINDTODEVICE */ - if (ax25->ax25_dev != NULL) goto done; if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) { if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 && - (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) - return -EADDRNOTAVAIL; - } else { - if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) - return -EADDRNOTAVAIL; + (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) { + err = -EADDRNOTAVAIL; + goto out; + } + } else { + if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) { + err = -EADDRNOTAVAIL; + goto out; + } } if (ax25_dev != NULL) @@ -1114,41 +1079,24 @@ done: ax25_insert_socket(ax25); sk->zapped = 0; + +out: + release_sock(sk); + return 0; } /* * FIXME: nonblock behaviour looks like it may have a bug. */ -static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) +static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags) { struct sock *sk = sock->sk; ax25_cb *ax25 = ax25_sk(sk); struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr; ax25_digi *digi = NULL; - int ct = 0, err; - - /* deal with restarts */ - if (sock->state == SS_CONNECTING) { - switch (sk->state) { - case TCP_SYN_SENT: /* still trying */ - return -EINPROGRESS; - - case TCP_ESTABLISHED: /* connection established */ - sock->state = SS_CONNECTED; - return 0; - - case TCP_CLOSE: /* connection refused */ - sock->state = SS_UNCONNECTED; - return -ECONNREFUSED; - } - } - - if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET) - return -EISCONN; /* No reconnect on a seqpacket socket */ - - sk->state = TCP_CLOSE; - sock->state = SS_UNCONNECTED; + int ct = 0, err = 0; /* * some sanity checks. code further down depends on this @@ -1162,8 +1110,9 @@ else if (addr_len != sizeof(struct full_sockaddr_ax25)) { /* support for old structure may go away some time */ if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) + (addr_len > sizeof(struct full_sockaddr_ax25))) { return -EINVAL; + } printk(KERN_WARNING "ax25_connect(): %s uses old (6 digipeater) socket structure.\n", current->comm); @@ -1172,21 +1121,54 @@ if (fsa->fsa_ax25.sax25_family != AF_AX25) return -EINVAL; + lock_sock(sk); + + /* deal with restarts */ + if (sock->state == SS_CONNECTING) { + switch (sk->state) { + case TCP_SYN_SENT: /* still trying */ + err = -EINPROGRESS; + goto out; + + case TCP_ESTABLISHED: /* connection established */ + sock->state = SS_CONNECTED; + goto out; + + case TCP_CLOSE: /* connection refused */ + sock->state = SS_UNCONNECTED; + err = -ECONNREFUSED; + goto out; + } + } + + if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET) { + err = -EISCONN; /* No reconnect on a seqpacket socket */ + goto out; + } + + sk->state = TCP_CLOSE; + sock->state = SS_UNCONNECTED; + if (ax25->digipeat != NULL) { kfree(ax25->digipeat); ax25->digipeat = NULL; } - + /* * Handle digi-peaters to be used. */ - if (addr_len > sizeof(struct sockaddr_ax25) && fsa->fsa_ax25.sax25_ndigis != 0) { + if (addr_len > sizeof(struct sockaddr_ax25) && + fsa->fsa_ax25.sax25_ndigis != 0) { /* Valid number of digipeaters ? */ - if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) - return -EINVAL; + if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) { + err = -EINVAL; + goto out; + } - if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) - return -ENOBUFS; + if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) { + err = -ENOBUFS; + goto out; + } digi->ndigi = fsa->fsa_ax25.sax25_ndigis; digi->lastrepeat = -1; @@ -1214,19 +1196,24 @@ printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n", current->comm); if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0) - return err; + goto out; + ax25_fillin_cb(ax25, ax25->ax25_dev); ax25_insert_socket(ax25); } else { - if (ax25->ax25_dev == NULL) - return -EHOSTUNREACH; + if (ax25->ax25_dev == NULL) { + err = -EHOSTUNREACH; + goto out; + } } if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, ax25->ax25_dev->dev)) { - if (digi != NULL) kfree(digi); - return -EADDRINUSE; /* Already such a connection */ + if (digi != NULL) + kfree(digi); + err = -EADDRINUSE; /* Already such a connection */ + goto out; } ax25->dest_addr = fsa->fsa_ax25.sax25_call; @@ -1236,7 +1223,7 @@ if (sk->type != SOCK_SEQPACKET) { sock->state = SS_CONNECTED; sk->state = TCP_ESTABLISHED; - return 0; + goto out; } /* Move to connecting socket, ax.25 lapb WAIT_UA.. */ @@ -1244,21 +1231,20 @@ sk->state = TCP_SYN_SENT; switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_establish_data_link(ax25); - break; + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_std_establish_data_link(ax25); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - ax25->modulus = AX25_MODULUS; - ax25->window = - ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - if (ax25->ax25_dev->dama.slave) - ax25_ds_establish_data_link(ax25); - else - ax25_std_establish_data_link(ax25); - break; + case AX25_PROTO_DAMA_SLAVE: + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + if (ax25->ax25_dev->dama.slave) + ax25_ds_establish_data_link(ax25); + else + ax25_std_establish_data_link(ax25); + break; #endif } @@ -1267,30 +1253,43 @@ ax25_start_heartbeat(ax25); /* Now the loop */ - if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) - return -EINPROGRESS; - - cli(); /* To avoid races on the sleep */ + if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { + err = -EINPROGRESS; + goto out; + } - /* A DM or timeout will go to closed, a UA will go to ABM */ - while (sk->state == TCP_SYN_SENT) { - interruptible_sleep_on(sk->sleep); - if (signal_pending(current)) { - sti(); + if (sk->state == TCP_SYN_SENT) { + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue(sk->sleep, &wait); + for (;;) { + if (sk->state != TCP_SYN_SENT) + break; + set_current_state(TASK_INTERRUPTIBLE); + release_sock(sk); + if (!signal_pending(tsk)) { + schedule(); + lock_sock(sk); + continue; + } return -ERESTARTSYS; } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep, &wait); } if (sk->state != TCP_ESTABLISHED) { /* Not in ABM, not in WAIT_UA -> failed */ - sti(); sock->state = SS_UNCONNECTED; - return sock_error(sk); /* Always set at this point */ + err = sock_error(sk); /* Always set at this point */ + goto out; } sock->state = SS_CONNECTED; - sti(); +out: + release_sock(sk); return 0; } @@ -1298,9 +1297,12 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) { - struct sock *sk; - struct sock *newsk; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); struct sk_buff *skb; + struct sock *newsk; + struct sock *sk; + int err = 0; if (sock->state != SS_UNCONNECTED) return -EINVAL; @@ -1308,26 +1310,40 @@ if ((sk = sock->sk) == NULL) return -EINVAL; - if (sk->type != SOCK_SEQPACKET) - return -EOPNOTSUPP; + lock_sock(sk); + if (sk->type != SOCK_SEQPACKET) { + err = -EOPNOTSUPP; + goto out; + } - if (sk->state != TCP_LISTEN) - return -EINVAL; + if (sk->state != TCP_LISTEN) { + err = -EINVAL; + goto out; + } /* * The read queue this time is holding sockets ready to use * hooked into the SABM we saved */ - do { - if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) { - if (flags & O_NONBLOCK) - return -EWOULDBLOCK; - - interruptible_sleep_on(sk->sleep); - if (signal_pending(current)) - return -ERESTARTSYS; + add_wait_queue(sk->sleep, &wait); + for (;;) { + skb = skb_dequeue(&sk->receive_queue); + if (skb) + break; + + current->state = TASK_INTERRUPTIBLE; + release_sock(sk); + if (flags & O_NONBLOCK) + return -EWOULDBLOCK; + if (!signal_pending(tsk)) { + schedule(); + lock_sock(sk); + continue; } - } while (skb == NULL); + return -ERESTARTSYS; + } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep, &wait); newsk = skb->sk; newsk->pair = NULL; @@ -1340,19 +1356,29 @@ newsock->sk = newsk; newsock->state = SS_CONNECTED; - return 0; +out: + release_sock(sk); + + return err; } -static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) +static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer) { - struct sock *sk = sock->sk; - ax25_cb *ax25 = ax25_sk(sk); struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr; + struct sock *sk = sock->sk; unsigned char ndigi, i; + ax25_cb *ax25; + int err = 0; + + lock_sock(sk); + ax25 = ax25_sk(sk); if (peer != 0) { - if (sk->state != TCP_ESTABLISHED) - return -ENOTCONN; + if (sk->state != TCP_ESTABLISHED) { + err = -ENOTCONN; + goto out; + } fsa->fsa_ax25.sax25_family = AF_AX25; fsa->fsa_ax25.sax25_call = ax25->dest_addr; @@ -1377,41 +1403,53 @@ } } *uaddr_len = sizeof (struct full_sockaddr_ax25); - return 0; + +out: + release_sock(sk); + + return err; } -static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) +static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, + struct scm_cookie *scm) { - struct sock *sk = sock->sk; - ax25_cb *ax25 = ax25_sk(sk); struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name; - int err; + struct sock *sk = sock->sk; struct sockaddr_ax25 sax; struct sk_buff *skb; + ax25_digi dtmp, *dp; unsigned char *asmptr; - int size; - ax25_digi *dp; - ax25_digi dtmp; - int lv; - int addr_len = msg->msg_namelen; + ax25_cb *ax25; + int lv, size, err, addr_len = msg->msg_namelen; - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) + if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) { return -EINVAL; + } + + lock_sock(sk); + ax25 = ax25_sk(sk); - if (sk->zapped) - return -EADDRNOTAVAIL; + if (sk->zapped) { + err = -EADDRNOTAVAIL; + goto out; + } if (sk->shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); - return -EPIPE; + err = -EPIPE; + goto out; } - if (ax25->ax25_dev == NULL) - return -ENETUNREACH; + if (ax25->ax25_dev == NULL) { + err = -ENETUNREACH; + goto out; + } if (usax != NULL) { - if (usax->sax25_family != AF_AX25) - return -EINVAL; + if (usax->sax25_family != AF_AX25) { + err = -EINVAL; + goto out; + } if (addr_len == sizeof(struct sockaddr_ax25)) { printk(KERN_WARNING "ax25_sendmsg(): %s uses obsolete socket structure\n", @@ -1420,8 +1458,10 @@ else if (addr_len != sizeof(struct full_sockaddr_ax25)) { /* support for old structure may go away some time */ if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) - return -EINVAL; + (addr_len > sizeof(struct full_sockaddr_ax25))) { + err = -EINVAL; + goto out; + } printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n", current->comm); @@ -1432,8 +1472,10 @@ struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax; /* Valid number of digipeaters ? */ - if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) - return -EINVAL; + if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) { + err = -EINVAL; + goto out; + } dtmp.ndigi = usax->sax25_ndigis; @@ -1447,8 +1489,10 @@ } sax = *usax; - if (sk->type == SOCK_SEQPACKET && ax25cmp(&ax25->dest_addr, &sax.sax25_call) != 0) - return -EISCONN; + if (sk->type == SOCK_SEQPACKET && ax25cmp(&ax25->dest_addr, &sax.sax25_call) != 0) { + err = -EISCONN; + goto out; + } if (usax->sax25_ndigis == 0) dp = NULL; else @@ -1459,8 +1503,10 @@ * it has become closed (not started closed) and is VC * we ought to SIGPIPE, EPIPE */ - if (sk->state != TCP_ESTABLISHED) - return -ENOTCONN; + if (sk->state != TCP_ESTABLISHED) { + err = -ENOTCONN; + goto out; + } sax.sax25_family = AF_AX25; sax.sax25_call = ax25->dest_addr; dp = ax25->digipeat; @@ -1474,8 +1520,9 @@ /* Assume the worst case */ size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN; - if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) - return err; + skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, &err); + if (skb == NULL) + goto out; skb_reserve(skb, size - len); @@ -1497,60 +1544,73 @@ /* Connected mode sockets go via the LAPB machine */ if (sk->state != TCP_ESTABLISHED) { kfree_skb(skb); - return -ENOTCONN; + err = -ENOTCONN; + goto out; } /* Shove it onto the queue and kick */ ax25_output(ax25, ax25->paclen, skb); - return len; - } else { - asmptr = skb_push(skb, 1 + ax25_addr_size(dp)); + err = len; + goto out; + } - SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp); + asmptr = skb_push(skb, 1 + ax25_addr_size(dp)); - if (dp != NULL) - SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi); + SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp); - /* Build an AX.25 header */ - asmptr += (lv = ax25_addr_build(asmptr, &ax25->source_addr, - &sax.sax25_call, dp, - AX25_COMMAND, AX25_MODULUS)); + if (dp != NULL) + SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi); - SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv); + /* Build an AX.25 header */ + asmptr += (lv = ax25_addr_build(asmptr, &ax25->source_addr, + &sax.sax25_call, dp, + AX25_COMMAND, AX25_MODULUS)); - skb->h.raw = asmptr; + SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv); - SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr); + skb->h.raw = asmptr; - *asmptr = AX25_UI; + SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr); - /* Datagram frames go straight out of the door as UI */ - skb->dev = ax25->ax25_dev->dev; + *asmptr = AX25_UI; - ax25_queue_xmit(skb); + /* Datagram frames go straight out of the door as UI */ + skb->dev = ax25->ax25_dev->dev; - return len; - } + ax25_queue_xmit(skb); + + err = len; + +out: + release_sock(sk); + + return err; } -static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) +static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, + int flags, struct scm_cookie *scm) { struct sock *sk = sock->sk; - int copied; struct sk_buff *skb; - int er; + int copied; + int err = 0; + lock_sock(sk); /* * This works for seqpacket too. The receiver has ordered the * queue for us! We do one quick check first though */ - if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED) - return -ENOTCONN; + if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED) { + err = -ENOTCONN; + goto out; + } /* Now we can treat all alike */ - if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) - return er; + skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + flags & MSG_DONTWAIT, &err); + if (skb == NULL) + goto out; if (!ax25_sk(sk)->pidincl) skb_pull(skb, 1); /* Remove PID */ @@ -1561,7 +1621,7 @@ if (copied > size) { copied = size; msg->msg_flags |= MSG_TRUNC; - } + } skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); @@ -1590,8 +1650,12 @@ } skb_free_datagram(sk, skb); + err = copied; + +out: + release_sock(sk); - return copied; + return err; } static int ax25_shutdown(struct socket *sk, int how) @@ -1603,137 +1667,173 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; + int res = 0; + lock_sock(sk); switch (cmd) { - case TIOCOUTQ: { - long amount; - amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); - if (amount < 0) - amount = 0; - return put_user(amount, (int *)arg); - } - - case TIOCINQ: { - struct sk_buff *skb; - long amount = 0L; - /* These two are safe on a single CPU system as only user tasks fiddle here */ - if ((skb = skb_peek(&sk->receive_queue)) != NULL) - amount = skb->len; - return put_user(amount, (int *)arg); - } - - case SIOCGSTAMP: - if (sk != NULL) { - if (sk->stamp.tv_sec == 0) - return -ENOENT; - return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; - } - return -EINVAL; + case TIOCOUTQ: { + long amount; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + if (amount < 0) + amount = 0; + res = put_user(amount, (int *)arg); + break; + } + + case TIOCINQ: { + struct sk_buff *skb; + long amount = 0L; + /* These two are safe on a single CPU system as only user tasks fiddle here */ + if ((skb = skb_peek(&sk->receive_queue)) != NULL) + amount = skb->len; + res = put_user(amount, (int *)arg); + break; + } + + case SIOCGSTAMP: + if (sk != NULL) { + if (sk->stamp.tv_sec == 0) { + res = -ENOENT; + break; + } + res = copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; + break; + } + res = -EINVAL; + break; - case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */ - case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */ - case SIOCAX25GETUID: { - struct sockaddr_ax25 sax25; - if (copy_from_user(&sax25, (void *)arg, sizeof(sax25))) - return -EFAULT; - return ax25_uid_ioctl(cmd, &sax25); - } - - case SIOCAX25NOUID: { /* Set the default policy (default/bar) */ - long amount; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (get_user(amount, (long *)arg)) - return -EFAULT; - if (amount > AX25_NOUID_BLOCK) - return -EINVAL; - ax25_uid_policy = amount; - return 0; - } - - case SIOCADDRT: - case SIOCDELRT: - case SIOCAX25OPTRT: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - return ax25_rt_ioctl(cmd, (void *)arg); - - case SIOCAX25CTLCON: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - return ax25_ctl_ioctl(cmd, (void *)arg); - - case SIOCAX25GETINFO: - case SIOCAX25GETINFOOLD: { - ax25_cb *ax25 = ax25_sk(sk); - struct ax25_info_struct ax25_info; - - ax25_info.t1 = ax25->t1 / HZ; - ax25_info.t2 = ax25->t2 / HZ; - ax25_info.t3 = ax25->t3 / HZ; - ax25_info.idle = ax25->idle / (60 * HZ); - ax25_info.n2 = ax25->n2; - ax25_info.t1timer = ax25_display_timer(&ax25->t1timer) / HZ; - ax25_info.t2timer = ax25_display_timer(&ax25->t2timer) / HZ; - ax25_info.t3timer = ax25_display_timer(&ax25->t3timer) / HZ; - ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ); - ax25_info.n2count = ax25->n2count; - ax25_info.state = ax25->state; - ax25_info.rcv_q = atomic_read(&sk->rmem_alloc); - ax25_info.snd_q = atomic_read(&sk->wmem_alloc); - ax25_info.vs = ax25->vs; - ax25_info.vr = ax25->vr; - ax25_info.va = ax25->va; - ax25_info.vs_max = ax25->vs; /* reserved */ - ax25_info.paclen = ax25->paclen; - ax25_info.window = ax25->window; - - /* old structure? */ - if (cmd == SIOCAX25GETINFOOLD) { - static int warned = 0; - if (!warned) { - printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n", - current->comm); - warned=1; - } + case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */ + case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */ + case SIOCAX25GETUID: { + struct sockaddr_ax25 sax25; + if (copy_from_user(&sax25, (void *)arg, sizeof(sax25))) { + res = -EFAULT; + break; + } + res = ax25_uid_ioctl(cmd, &sax25); + break; + } - if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated))) - return -EFAULT; - } else { - if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct))) - return -EINVAL; - } - return 0; - } - - case SIOCAX25ADDFWD: - case SIOCAX25DELFWD: { - struct ax25_fwd_struct ax25_fwd; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd))) - return -EFAULT; - return ax25_fwd_ioctl(cmd, &ax25_fwd); - } - - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - return -EINVAL; + case SIOCAX25NOUID: { /* Set the default policy (default/bar) */ + long amount; + if (!capable(CAP_NET_ADMIN)) { + res = -EPERM; + break; + } + if (get_user(amount, (long *)arg)) { + res = -EFAULT; + break; + } + if (amount > AX25_NOUID_BLOCK) { + res = -EINVAL; + break; + } + ax25_uid_policy = amount; + res = 0; + break; + } - default: - return dev_ioctl(cmd, (void *)arg); + case SIOCADDRT: + case SIOCDELRT: + case SIOCAX25OPTRT: + if (!capable(CAP_NET_ADMIN)) { + res = -EPERM; + break; + } + res = ax25_rt_ioctl(cmd, (void *)arg); + break; + + case SIOCAX25CTLCON: + if (!capable(CAP_NET_ADMIN)) { + res = -EPERM; + break; + } + res = ax25_ctl_ioctl(cmd, (void *)arg); + break; + + case SIOCAX25GETINFO: + case SIOCAX25GETINFOOLD: { + ax25_cb *ax25 = ax25_sk(sk); + struct ax25_info_struct ax25_info; + + ax25_info.t1 = ax25->t1 / HZ; + ax25_info.t2 = ax25->t2 / HZ; + ax25_info.t3 = ax25->t3 / HZ; + ax25_info.idle = ax25->idle / (60 * HZ); + ax25_info.n2 = ax25->n2; + ax25_info.t1timer = ax25_display_timer(&ax25->t1timer) / HZ; + ax25_info.t2timer = ax25_display_timer(&ax25->t2timer) / HZ; + ax25_info.t3timer = ax25_display_timer(&ax25->t3timer) / HZ; + ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ); + ax25_info.n2count = ax25->n2count; + ax25_info.state = ax25->state; + ax25_info.rcv_q = atomic_read(&sk->rmem_alloc); + ax25_info.snd_q = atomic_read(&sk->wmem_alloc); + ax25_info.vs = ax25->vs; + ax25_info.vr = ax25->vr; + ax25_info.va = ax25->va; + ax25_info.vs_max = ax25->vs; /* reserved */ + ax25_info.paclen = ax25->paclen; + ax25_info.window = ax25->window; + + /* old structure? */ + if (cmd == SIOCAX25GETINFOOLD) { + static int warned = 0; + if (!warned) { + printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n", + current->comm); + warned=1; + } + + if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated))) { + res = -EFAULT; + break; + } + } else { + if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct))) { + res = -EINVAL; + break; + } + } + res = 0; + break; } - /*NOTREACHED*/ - return 0; + case SIOCAX25ADDFWD: + case SIOCAX25DELFWD: { + struct ax25_fwd_struct ax25_fwd; + if (!capable(CAP_NET_ADMIN)) { + res = -EPERM; + break; + } + if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd))) { + res = -EFAULT; + break; + } + res = ax25_fwd_ioctl(cmd, &ax25_fwd); + break; + } + + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + res = -EINVAL; + break; + + default: + res = dev_ioctl(cmd, (void *)arg); + break; + } + release_sock(sk); + + return res; } static int ax25_get_info(char *buffer, char **start, off_t offset, int length) @@ -1744,28 +1844,28 @@ off_t pos = 0; off_t begin = 0; - cli(); + spin_lock_bh(&ax25_list_lock); /* * New format: - * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode + * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode */ - + for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) { - len += sprintf(buffer+len, "%8.8lx %s %s%s ", - (long) ax25, + len += sprintf(buffer+len, "%8.8lx %s %s%s ", + (long) ax25, ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name, ax2asc(&ax25->source_addr), ax25->iamdigi? "*":""); len += sprintf(buffer+len, "%s", ax2asc(&ax25->dest_addr)); - + for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { len += sprintf(buffer+len, ",%s%s", ax2asc(&ax25->digipeat->calls[k]), ax25->digipeat->repeated[k]? "*":""); } - + len += sprintf(buffer+len, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d", ax25->state, ax25->vs, ax25->vr, ax25->va, @@ -1799,7 +1899,7 @@ break; } - sti(); + spin_unlock_bh(&ax25_list_lock); *start = buffer + (offset - begin); len -= (offset - begin); @@ -1814,7 +1914,7 @@ .create = ax25_create, }; -static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = { +static struct proto_ops ax25_proto_ops = { .family = PF_AX25, .release = ax25_release, @@ -1835,15 +1935,14 @@ .sendpage = sock_no_sendpage, }; -#include -SOCKOPS_WRAP(ax25_proto, PF_AX25); - /* * Called by socket.c on kernel start up */ static struct packet_type ax25_packet_type = { - .type = __constant_htons(ETH_P_AX25), - .func = ax25_kiss_rcv, + .type = __constant_htons(ETH_P_AX25), + .dev = NULL, /* All devices */ + .func = ax25_kiss_rcv, + .data = (void *) 1 }; static struct notifier_block ax25_dev_notifier = { diff -Nru a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c --- a/net/ax25/ax25_addr.c Fri Sep 20 08:20:48 2002 +++ b/net/ax25/ax25_addr.c Fri Sep 20 08:20:48 2002 @@ -1,24 +1,11 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; - * - * History - * AX.25 036 Jonathan(G4KLX) Split from ax25_subr.c. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include @@ -165,14 +152,14 @@ if (flags != NULL) { *flags = 0; - + if (buf[6] & AX25_CBIT) *flags = AX25_COMMAND; if (buf[13] & AX25_CBIT) *flags = AX25_RESPONSE; } - if (dama != NULL) + if (dama != NULL) *dama = ~buf[13] & AX25_DAMA_FLAG; /* Copy to, from */ @@ -243,7 +230,7 @@ if (d == NULL || d->ndigi == 0) { buf[6] |= AX25_EBIT; return 2 * AX25_ADDR_LEN; - } + } buf += AX25_ADDR_LEN; len += AX25_ADDR_LEN; @@ -277,7 +264,7 @@ return AX25_ADDR_LEN * (2 + dp->ndigi); } -/* +/* * Reverse Digipeat List. May not pass both parameters as same struct */ void ax25_digi_invert(ax25_digi *in, ax25_digi *out) diff -Nru a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c --- a/net/ax25/ax25_dev.c Fri Sep 20 08:20:42 2002 +++ b/net/ax25/ax25_dev.c Fri Sep 20 08:20:42 2002 @@ -1,21 +1,11 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Other kernels modules in this kit are generally BSD derived. See the copyright headers. - * - * - * History - * AX.25 036 Jonathan(G4KLX) Split from ax25_route.c. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include @@ -27,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -41,27 +32,35 @@ #include ax25_dev *ax25_dev_list; +spinlock_t ax25_dev_lock = SPIN_LOCK_UNLOCKED; ax25_dev *ax25_dev_ax25dev(struct net_device *dev) { - ax25_dev *ax25_dev; + ax25_dev *ax25_dev, *res = NULL; + spin_lock_bh(&ax25_dev_lock); for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) - if (ax25_dev->dev == dev) - return ax25_dev; + if (ax25_dev->dev == dev) { + res = ax25_dev; + break; + } + spin_unlock_bh(&ax25_dev_lock); - return NULL; + return res; } ax25_dev *ax25_addr_ax25dev(ax25_address *addr) { - ax25_dev *ax25_dev; + ax25_dev *ax25_dev, *res = NULL; + spin_lock_bh(&ax25_dev_lock); for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) - if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) - return ax25_dev; + if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) { + res = ax25_dev; + } + spin_unlock_bh(&ax25_dev_lock); - return NULL; + return res; } /* @@ -71,7 +70,6 @@ void ax25_dev_device_up(struct net_device *dev) { ax25_dev *ax25_dev; - unsigned long flags; if ((ax25_dev = kmalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) { printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n"); @@ -100,10 +98,10 @@ ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL; ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT; - save_flags(flags); cli(); + spin_lock_bh(&ax25_dev_lock); ax25_dev->next = ax25_dev_list; ax25_dev_list = ax25_dev; - restore_flags(flags); + spin_unlock_bh(&ax25_dev_lock); ax25_register_sysctl(); } @@ -111,14 +109,13 @@ void ax25_dev_device_down(struct net_device *dev) { ax25_dev *s, *ax25_dev; - unsigned long flags; if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) return; ax25_unregister_sysctl(); - save_flags(flags); cli(); + spin_lock_bh(&ax25_dev_lock); #ifdef CONFIG_AX25_DAMA_SLAVE ax25_ds_del_timer(ax25_dev); @@ -133,7 +130,7 @@ if ((s = ax25_dev_list) == ax25_dev) { ax25_dev_list = s->next; - restore_flags(flags); + spin_unlock_bh(&ax25_dev_lock); kfree(ax25_dev); ax25_register_sysctl(); return; @@ -142,7 +139,7 @@ while (s != NULL && s->next != NULL) { if (s->next == ax25_dev) { s->next = ax25_dev->next; - restore_flags(flags); + spin_unlock_bh(&ax25_dev_lock); kfree(ax25_dev); ax25_register_sysctl(); return; @@ -150,8 +147,8 @@ s = s->next; } + spin_unlock_bh(&ax25_dev_lock); - restore_flags(flags); ax25_register_sysctl(); } @@ -163,22 +160,22 @@ return -EINVAL; switch (cmd) { - case SIOCAX25ADDFWD: - if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL) - return -EINVAL; - if (ax25_dev->forward != NULL) - return -EINVAL; - ax25_dev->forward = fwd_dev->dev; - break; - - case SIOCAX25DELFWD: - if (ax25_dev->forward == NULL) - return -EINVAL; - ax25_dev->forward = NULL; - break; + case SIOCAX25ADDFWD: + if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL) + return -EINVAL; + if (ax25_dev->forward != NULL) + return -EINVAL; + ax25_dev->forward = fwd_dev->dev; + break; - default: + case SIOCAX25DELFWD: + if (ax25_dev->forward == NULL) return -EINVAL; + ax25_dev->forward = NULL; + break; + + default: + return -EINVAL; } return 0; @@ -202,12 +199,16 @@ */ void __exit ax25_dev_free(void) { - ax25_dev *s, *ax25_dev = ax25_dev_list; + ax25_dev *s, *ax25_dev; + spin_lock_bh(&ax25_dev_lock); + ax25_dev = ax25_dev_list; while (ax25_dev != NULL) { s = ax25_dev; ax25_dev = ax25_dev->next; kfree(s); } + ax25_dev_list = NULL; + spin_unlock_bh(&ax25_dev_lock); } diff -Nru a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c --- a/net/ax25/ax25_ds_in.c Fri Sep 20 08:20:42 2002 +++ b/net/ax25/ax25_ds_in.c Fri Sep 20 08:20:42 2002 @@ -1,27 +1,12 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; - * - * History - * AX.25 036 Jonathan(G4KLX) Cloned from ax25_in.c - * Joerg(DL1BKE) Fixed it. - * AX.25 037 Jonathan(G4KLX) New timer architecture. - * Joerg(DL1BKE) ax25->n2count never got reset + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) */ - #include #include #include @@ -53,54 +38,56 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) { switch (frametype) { - case AX25_SABM: - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - break; - - case AX25_SABME: - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); - break; - - case AX25_UA: - ax25_calculate_rtt(ax25); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - if (ax25->sk != NULL) { - ax25->sk->state = TCP_ESTABLISHED; - /* For WAIT_SABM connections we will produce an accept ready socket here */ - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - } - ax25_dama_on(ax25); - - /* according to DK4EG´s spec we are required to - * send a RR RESPONSE FINAL NR=0. - */ - - ax25_std_enquiry_response(ax25); - break; - - case AX25_DM: - if (pf) ax25_disconnect(ax25, ECONNREFUSED); - break; - - default: - if (pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); - break; + case AX25_SABM: + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + break; + + case AX25_SABME: + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + break; + + case AX25_DISC: + ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); + break; + + case AX25_UA: + ax25_calculate_rtt(ax25); + ax25_stop_t1timer(ax25); + ax25_start_t3timer(ax25); + ax25_start_idletimer(ax25); + ax25->vs = 0; + ax25->va = 0; + ax25->vr = 0; + ax25->state = AX25_STATE_3; + ax25->n2count = 0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_ESTABLISHED; + /* For WAIT_SABM connections we will produce an accept ready socket here */ + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + } + ax25_dama_on(ax25); + + /* according to DK4EG´s spec we are required to + * send a RR RESPONSE FINAL NR=0. + */ + + ax25_std_enquiry_response(ax25); + break; + + case AX25_DM: + if (pf) + ax25_disconnect(ax25, ECONNREFUSED); + break; + + default: + if (pf) + ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); + break; } return 0; @@ -114,38 +101,38 @@ static int ax25_ds_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) { switch (frametype) { - case AX25_SABM: - case AX25_SABME: - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25_dama_off(ax25); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + case AX25_SABM: + case AX25_SABME: + ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + ax25_dama_off(ax25); + break; + + case AX25_DISC: + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25_dama_off(ax25); + ax25_disconnect(ax25, 0); + break; + + case AX25_DM: + case AX25_UA: + if (pf) { ax25_dama_off(ax25); ax25_disconnect(ax25, 0); - break; + } + break; - case AX25_DM: - case AX25_UA: - if (pf) { - ax25_dama_off(ax25); - ax25_disconnect(ax25, 0); - } - break; - - case AX25_I: - case AX25_REJ: - case AX25_RNR: - case AX25_RR: - if (pf) { - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25_dama_off(ax25); - } - break; + case AX25_I: + case AX25_REJ: + case AX25_RNR: + case AX25_RR: + if (pf) { + ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + ax25_dama_off(ax25); + } + break; - default: - break; + default: + break; } return 0; @@ -161,127 +148,127 @@ int queued = 0; switch (frametype) { - case AX25_SABM: - case AX25_SABME: - if (frametype == AX25_SABM) { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - } else { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; - } - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - ax25->condition = 0x00; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25_requeue_frames(ax25); - ax25_dama_on(ax25); - break; + case AX25_SABM: + case AX25_SABME: + if (frametype == AX25_SABM) { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + } else { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; + } + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25_stop_t1timer(ax25); + ax25_start_t3timer(ax25); + ax25_start_idletimer(ax25); + ax25->condition = 0x00; + ax25->vs = 0; + ax25->va = 0; + ax25->vr = 0; + ax25_requeue_frames(ax25); + ax25_dama_on(ax25); + break; + + case AX25_DISC: + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25_dama_off(ax25); + ax25_disconnect(ax25, 0); + break; + + case AX25_DM: + ax25_dama_off(ax25); + ax25_disconnect(ax25, ECONNRESET); + break; + + case AX25_RR: + case AX25_RNR: + if (frametype == AX25_RR) + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + else + ax25->condition |= AX25_COND_PEER_RX_BUSY; - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_dama_off(ax25); - ax25_disconnect(ax25, 0); - break; + if (ax25_validate_nr(ax25, nr)) { + if (ax25_check_iframes_acked(ax25, nr)) + ax25->n2count=0; + if (type == AX25_COMMAND && pf) + ax25_ds_enquiry_response(ax25); + } else { + ax25_ds_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; - case AX25_DM: - ax25_dama_off(ax25); - ax25_disconnect(ax25, ECONNRESET); - break; + case AX25_REJ: + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - case AX25_RR: - case AX25_RNR: - if (frametype == AX25_RR) - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - else - ax25->condition |= AX25_COND_PEER_RX_BUSY; - - if (ax25_validate_nr(ax25, nr)) { - if (ax25_check_iframes_acked(ax25, nr)) - ax25->n2count=0; - if (type == AX25_COMMAND && pf) - ax25_ds_enquiry_response(ax25); - } else { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; + if (ax25_validate_nr(ax25, nr)) { + if (ax25->va != nr) + ax25->n2count=0; - case AX25_REJ: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + ax25_frames_acked(ax25, nr); + ax25_calculate_rtt(ax25); + ax25_stop_t1timer(ax25); + ax25_start_t3timer(ax25); + ax25_requeue_frames(ax25); - if (ax25_validate_nr(ax25, nr)) { - if (ax25->va != nr) - ax25->n2count=0; - - ax25_frames_acked(ax25, nr); - ax25_calculate_rtt(ax25); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - ax25_requeue_frames(ax25); + if (type == AX25_COMMAND && pf) + ax25_ds_enquiry_response(ax25); + } else { + ax25_ds_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; - if (type == AX25_COMMAND && pf) - ax25_ds_enquiry_response(ax25); - } else { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } + case AX25_I: + if (!ax25_validate_nr(ax25, nr)) { + ax25_ds_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; break; - - case AX25_I: - if (!ax25_validate_nr(ax25, nr)) { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - break; - } - if (ax25->condition & AX25_COND_PEER_RX_BUSY) { - ax25_frames_acked(ax25, nr); + } + if (ax25->condition & AX25_COND_PEER_RX_BUSY) { + ax25_frames_acked(ax25, nr); + ax25->n2count = 0; + } else { + if (ax25_check_iframes_acked(ax25, nr)) ax25->n2count = 0; + } + if (ax25->condition & AX25_COND_OWN_RX_BUSY) { + if (pf) ax25_ds_enquiry_response(ax25); + break; + } + if (ns == ax25->vr) { + ax25->vr = (ax25->vr + 1) % ax25->modulus; + queued = ax25_rx_iframe(ax25, skb); + if (ax25->condition & AX25_COND_OWN_RX_BUSY) + ax25->vr = ns; /* ax25->vr - 1 */ + ax25->condition &= ~AX25_COND_REJECT; + if (pf) { + ax25_ds_enquiry_response(ax25); } else { - if (ax25_check_iframes_acked(ax25, nr)) - ax25->n2count = 0; + if (!(ax25->condition & AX25_COND_ACK_PENDING)) { + ax25->condition |= AX25_COND_ACK_PENDING; + ax25_start_t2timer(ax25); + } } - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { + } else { + if (ax25->condition & AX25_COND_REJECT) { if (pf) ax25_ds_enquiry_response(ax25); - break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; - queued = ax25_rx_iframe(ax25, skb); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25->vr = ns; /* ax25->vr - 1 */ - ax25->condition &= ~AX25_COND_REJECT; - if (pf) { - ax25_ds_enquiry_response(ax25); - } else { - if (!(ax25->condition & AX25_COND_ACK_PENDING)) { - ax25->condition |= AX25_COND_ACK_PENDING; - ax25_start_t2timer(ax25); - } - } } else { - if (ax25->condition & AX25_COND_REJECT) { - if (pf) ax25_ds_enquiry_response(ax25); - } else { - ax25->condition |= AX25_COND_REJECT; - ax25_ds_enquiry_response(ax25); - ax25->condition &= ~AX25_COND_ACK_PENDING; - } + ax25->condition |= AX25_COND_REJECT; + ax25_ds_enquiry_response(ax25); + ax25->condition &= ~AX25_COND_ACK_PENDING; } - break; + } + break; - case AX25_FRMR: - case AX25_ILLEGAL: - ax25_ds_establish_data_link(ax25); - ax25->state = AX25_STATE_1; - break; + case AX25_FRMR: + case AX25_ILLEGAL: + ax25_ds_establish_data_link(ax25); + ax25->state = AX25_STATE_1; + break; - default: - break; + default: + break; } return queued; @@ -297,15 +284,15 @@ frametype = ax25_decode(ax25, skb, &ns, &nr, &pf); switch (ax25->state) { - case AX25_STATE_1: - queued = ax25_ds_state1_machine(ax25, skb, frametype, pf, type); - break; - case AX25_STATE_2: - queued = ax25_ds_state2_machine(ax25, skb, frametype, pf, type); - break; - case AX25_STATE_3: - queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type); - break; + case AX25_STATE_1: + queued = ax25_ds_state1_machine(ax25, skb, frametype, pf, type); + break; + case AX25_STATE_2: + queued = ax25_ds_state2_machine(ax25, skb, frametype, pf, type); + break; + case AX25_STATE_3: + queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type); + break; } return queued; diff -Nru a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c --- a/net/ax25/ax25_ds_subr.c Fri Sep 20 08:20:47 2002 +++ b/net/ax25/ax25_ds_subr.c Fri Sep 20 08:20:47 2002 @@ -1,27 +1,12 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; - * - * History - * AX.25 036 Jonathan(G4KLX) Cloned from ax25_out.c and ax25_subr.c. - * Joerg(DL1BKE) Changed ax25_ds_enquiry_response(), - * fixed ax25_dama_on() and ax25_dama_off(). - * AX.25 037 Jonathan(G4KLX) New timer architecture. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) */ - #include #include #include @@ -31,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +59,7 @@ * DL1BKE-7->DB0PRA-6 DB0ACH * * Flexnet refuses to send us *any* I frame if we send - * a REJ in case AX25_COND_REJECT is set. It is superfluous in + * a REJ in case AX25_COND_REJECT is set. It is superfluous in * this mode anyway (a RR or RNR invokes the retransmission). * Is this a Flexnet bug? */ @@ -93,6 +79,7 @@ ax25_start_t3timer(ax25); ax25_ds_set_timer(ax25->ax25_dev); + spin_lock_bh(&ax25_list_lock); for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) { if (ax25o == ax25) continue; @@ -118,6 +105,7 @@ if (ax25o->state != AX25_STATE_0) ax25_start_t3timer(ax25o); } + spin_unlock_bh(&ax25_list_lock); } void ax25_ds_establish_data_link(ax25_cb *ax25) @@ -132,8 +120,8 @@ /* * :::FIXME::: - * This is a kludge. Not all drivers recognize kiss commands. - * We need a driver level request to switch duplex mode, that does + * This is a kludge. Not all drivers recognize kiss commands. + * We need a driver level request to switch duplex mode, that does * either SCC changing, PI config or KISS as required. Currently * this request isn't reliable. */ @@ -164,19 +152,24 @@ * A nasty problem arises if we count the number of DAMA connections * wrong, especially when connections on the device already existed * and our network node (or the sysop) decides to turn on DAMA Master - * mode. We thus flag the 'real' slave connections with + * mode. We thus flag the 'real' slave connections with * ax25->dama_slave=1 and look on every disconnect if still slave * connections exist. */ static int ax25_check_dama_slave(ax25_dev *ax25_dev) { ax25_cb *ax25; + int res = 0; + spin_lock_bh(&ax25_list_lock); for (ax25 = ax25_list; ax25 != NULL ; ax25 = ax25->next) - if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) - return 1; + if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) { + res = 1; + break; + } + spin_unlock_bh(&ax25_list_lock); - return 0; + return res; } void ax25_dev_dama_on(ax25_dev *ax25_dev) diff -Nru a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c --- a/net/ax25/ax25_ds_timer.c Fri Sep 20 08:20:47 2002 +++ b/net/ax25/ax25_ds_timer.c Fri Sep 20 08:20:47 2002 @@ -1,23 +1,16 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * AX.25 036 Jonathan(G4KLX) Cloned from ax25_timer.c. - * Joerg(DL1BKE) Added DAMA Slave Timeout timer - * AX.25 037 Jonathan(G4KLX) New timer architecture. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) */ - #include #include #include +#include #include #include #include @@ -41,7 +34,7 @@ /* * Add DAMA slave timeout timer to timer list. - * Unlike the connection based timers the timeout function gets + * Unlike the connection based timers the timeout function gets * triggered every second. Please note that NET_AX25_DAMA_SLAVE_TIMEOUT * (aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in * 1/10th of a second. @@ -58,7 +51,8 @@ void ax25_ds_del_timer(ax25_dev *ax25_dev) { - if (ax25_dev) del_timer(&ax25_dev->dama.slave_timer); + if (ax25_dev) + del_timer(&ax25_dev->dama.slave_timer); } void ax25_ds_set_timer(ax25_dev *ax25_dev) @@ -80,15 +74,16 @@ { ax25_dev *ax25_dev = (struct ax25_dev *) arg; ax25_cb *ax25; - + if (ax25_dev == NULL || !ax25_dev->dama.slave) return; /* Yikes! */ - + if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout) { ax25_ds_set_timer(ax25_dev); return; } - + + spin_lock_bh(&ax25_list_lock); for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) { if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE)) continue; @@ -96,7 +91,8 @@ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25_disconnect(ax25, ETIMEDOUT); } - + spin_unlock_bh(&ax25_list_lock); + ax25_dev_dama_off(ax25_dev); } @@ -104,33 +100,33 @@ { switch (ax25->state) { - case AX25_STATE_0: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { - ax25_destroy_socket(ax25); - return; + case AX25_STATE_0: + /* Magic here: If we listen() and a new link dies before it + is accepted() it isn't 'dead' so doesn't get removed. */ + if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { + ax25_destroy_socket(ax25); + return; + } + break; + + case AX25_STATE_3: + /* + * Check the state of the receive buffer. + */ + if (ax25->sk != NULL) { + if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && + (ax25->condition & AX25_COND_OWN_RX_BUSY)) { + ax25->condition &= ~AX25_COND_OWN_RX_BUSY; + ax25->condition &= ~AX25_COND_ACK_PENDING; + break; } - break; - - case AX25_STATE_3: - /* - * Check the state of the receive buffer. - */ - if (ax25->sk != NULL) { - if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && - (ax25->condition & AX25_COND_OWN_RX_BUSY)) { - ax25->condition &= ~AX25_COND_OWN_RX_BUSY; - ax25->condition &= ~AX25_COND_ACK_PENDING; - break; - } - } - break; + } + break; } ax25_start_heartbeat(ax25); } - + /* dl1bke 960114: T3 works much like the IDLE timeout, but * gets reloaded with every frame for this * connection. @@ -168,7 +164,7 @@ } /* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC - * within the poll of any connected channel. Remember + * within the poll of any connected channel. Remember * that we are not allowed to send anything unless we * get polled by the Master. * @@ -176,48 +172,47 @@ * ax25_enquiry_response(). */ void ax25_ds_t1_timeout(ax25_cb *ax25) -{ +{ switch (ax25->state) { - - case AX25_STATE_1: - if (ax25->n2count == ax25->n2) { - if (ax25->modulus == AX25_MODULUS) { - ax25_disconnect(ax25, ETIMEDOUT); - return; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - ax25->n2count = 0; - ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND); - } - } else { - ax25->n2count++; - if (ax25->modulus == AX25_MODULUS) - ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND); - else - ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND); - } - break; - - case AX25_STATE_2: - if (ax25->n2count == ax25->n2) { - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25_disconnect(ax25, ETIMEDOUT); - return; - } else { - ax25->n2count++; - } - break; - - case AX25_STATE_3: - if (ax25->n2count == ax25->n2) { - ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); + case AX25_STATE_1: + if (ax25->n2count == ax25->n2) { + if (ax25->modulus == AX25_MODULUS) { ax25_disconnect(ax25, ETIMEDOUT); return; } else { - ax25->n2count++; + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + ax25->n2count = 0; + ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND); } - break; + } else { + ax25->n2count++; + if (ax25->modulus == AX25_MODULUS) + ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND); + else + ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND); + } + break; + + case AX25_STATE_2: + if (ax25->n2count == ax25->n2) { + ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + ax25_disconnect(ax25, ETIMEDOUT); + return; + } else { + ax25->n2count++; + } + break; + + case AX25_STATE_3: + if (ax25->n2count == ax25->n2) { + ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); + ax25_disconnect(ax25, ETIMEDOUT); + return; + } else { + ax25->n2count++; + } + break; } ax25_calculate_t1(ax25); diff -Nru a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c --- a/net/ax25/ax25_iface.c Fri Sep 20 08:20:46 2002 +++ b/net/ax25/ax25_iface.c Fri Sep 20 08:20:46 2002 @@ -1,18 +1,11 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include @@ -20,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -40,22 +34,25 @@ unsigned int pid; int (*func)(struct sk_buff *, ax25_cb *); } *protocol_list; +static rwlock_t protocol_list_lock = RW_LOCK_UNLOCKED; static struct linkfail_struct { struct linkfail_struct *next; void (*func)(ax25_cb *, int); } *linkfail_list; +static spinlock_t linkfail_lock = SPIN_LOCK_UNLOCKED; static struct listen_struct { struct listen_struct *next; ax25_address callsign; struct net_device *dev; } *listen_list; +static spinlock_t listen_lock = SPIN_LOCK_UNLOCKED; -int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_cb *)) +int ax25_protocol_register(unsigned int pid, + int (*func)(struct sk_buff *, ax25_cb *)) { struct protocol_struct *protocol; - unsigned long flags; if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT) return 0; @@ -69,31 +66,28 @@ protocol->pid = pid; protocol->func = func; - save_flags(flags); - cli(); - + write_lock(&protocol_list_lock); protocol->next = protocol_list; protocol_list = protocol; - - restore_flags(flags); + write_unlock(&protocol_list_lock); return 1; } void ax25_protocol_release(unsigned int pid) { - struct protocol_struct *s, *protocol = protocol_list; - unsigned long flags; + struct protocol_struct *s, *protocol; - if (protocol == NULL) + write_lock(&protocol_list_lock); + protocol = protocol_list; + if (protocol == NULL) { + write_unlock(&protocol_list_lock); return; - - save_flags(flags); - cli(); + } if (protocol->pid == pid) { protocol_list = protocol->next; - restore_flags(flags); + write_unlock(&protocol_list_lock); kfree(protocol); return; } @@ -102,52 +96,45 @@ if (protocol->next->pid == pid) { s = protocol->next; protocol->next = protocol->next->next; - restore_flags(flags); + write_unlock(&protocol_list_lock); kfree(s); return; } protocol = protocol->next; } - - restore_flags(flags); + write_unlock(&protocol_list_lock); } int ax25_linkfail_register(void (*func)(ax25_cb *, int)) { struct linkfail_struct *linkfail; - unsigned long flags; if ((linkfail = kmalloc(sizeof(*linkfail), GFP_ATOMIC)) == NULL) return 0; linkfail->func = func; - save_flags(flags); - cli(); - + spin_lock_bh(&linkfail_lock); linkfail->next = linkfail_list; linkfail_list = linkfail; - - restore_flags(flags); + spin_unlock_bh(&linkfail_lock); return 1; } void ax25_linkfail_release(void (*func)(ax25_cb *, int)) { - struct linkfail_struct *s, *linkfail = linkfail_list; - unsigned long flags; + struct linkfail_struct *s, *linkfail; + spin_lock_bh(&linkfail_lock); + linkfail = linkfail_list; if (linkfail == NULL) return; - save_flags(flags); - cli(); - if (linkfail->func == func) { linkfail_list = linkfail->next; - restore_flags(flags); + spin_unlock_bh(&linkfail_lock); kfree(linkfail); return; } @@ -156,21 +143,19 @@ if (linkfail->next->func == func) { s = linkfail->next; linkfail->next = linkfail->next->next; - restore_flags(flags); + spin_unlock_bh(&linkfail_lock); kfree(s); return; } linkfail = linkfail->next; } - - restore_flags(flags); + spin_unlock_bh(&linkfail_lock); } int ax25_listen_register(ax25_address *callsign, struct net_device *dev) { struct listen_struct *listen; - unsigned long flags; if (ax25_listen_mine(callsign, dev)) return 0; @@ -181,31 +166,26 @@ listen->callsign = *callsign; listen->dev = dev; - save_flags(flags); - cli(); - + spin_lock_bh(&listen_lock); listen->next = listen_list; listen_list = listen; - - restore_flags(flags); + spin_unlock_bh(&listen_lock); return 1; } void ax25_listen_release(ax25_address *callsign, struct net_device *dev) { - struct listen_struct *s, *listen = listen_list; - unsigned long flags; + struct listen_struct *s, *listen; + spin_lock_bh(&listen_lock); + listen = listen_list; if (listen == NULL) return; - save_flags(flags); - cli(); - if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { listen_list = listen->next; - restore_flags(flags); + spin_unlock_bh(&listen_lock); kfree(listen); return; } @@ -214,35 +194,41 @@ if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) { s = listen->next; listen->next = listen->next->next; - restore_flags(flags); + spin_unlock_bh(&listen_lock); kfree(s); return; } listen = listen->next; } - - restore_flags(flags); + spin_unlock_bh(&listen_lock); } int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *) { + int (*res)(struct sk_buff *, ax25_cb *) = NULL; struct protocol_struct *protocol; + read_lock(&protocol_list_lock); for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) - if (protocol->pid == pid) - return protocol->func; + if (protocol->pid == pid) { + res = protocol->func; + break; + } + read_unlock(&protocol_list_lock); - return NULL; + return res; } int ax25_listen_mine(ax25_address *callsign, struct net_device *dev) { struct listen_struct *listen; + spin_lock_bh(&listen_lock); for (listen = listen_list; listen != NULL; listen = listen->next) if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) return 1; + spin_unlock_bh(&listen_lock); return 0; } @@ -251,18 +237,24 @@ { struct linkfail_struct *linkfail; + spin_lock_bh(&linkfail_lock); for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next) (linkfail->func)(ax25, reason); + spin_unlock_bh(&linkfail_lock); } int ax25_protocol_is_registered(unsigned int pid) { struct protocol_struct *protocol; + int res = 0; + read_lock(&protocol_list_lock); for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) - if (protocol->pid == pid) - return 1; + if (protocol->pid == pid) { + res = 1; + break; + } + read_unlock(&protocol_list_lock); - return 0; + return res; } - diff -Nru a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c --- a/net/ax25/ax25_in.c Fri Sep 20 08:20:43 2002 +++ b/net/ax25/ax25_in.c Fri Sep 20 08:20:43 2002 @@ -1,44 +1,14 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; - * - * History - * AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams. - * AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from - * the sock structure. - * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. - * Jonathan(G4KLX) Added IP mode registration. - * AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception. - * Upgraded state machine for SABME. - * Added arbitrary protocol id support. - * AX.25 031 Joerg(DL1BKE) Added DAMA support - * HaJo(DD8NE) Added Idle Disc Timer T5 - * Joerg(DL1BKE) Renamed it to "IDLE" with a slightly - * different behaviour. Fixed defrag - * routine (I hope) - * AX.25 032 Darryl(G7LED) AX.25 segmentation fixed. - * AX.25 033 Jonathan(G4KLX) Remove auto-router. - * Modularisation changes. - * AX.25 035 Hans(PE1AYX) Fixed interface to IP layer. - * AX.25 036 Jonathan(G4KLX) Move DAMA code into own file. - * Joerg(DL1BKE) Fixed DAMA Slave. - * AX.25 037 Jonathan(G4KLX) New timer architecture. - * Thomas(DL9SAU) Fixed missing initialization of skb->protocol. + * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) + * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de) */ - #include #include #include @@ -146,7 +116,7 @@ #ifdef CONFIG_INET if (pid == AX25_P_IP) { - /* working around a TCP bug to keep additional listeners + /* working around a TCP bug to keep additional listeners * happy. TCP re-uses the buffer and destroys the original * content. */ @@ -199,37 +169,33 @@ return 0; switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - queued = ax25_std_frame_in(ax25, skb, type); - break; + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + queued = ax25_std_frame_in(ax25, skb, type); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (dama || ax25->ax25_dev->dama.slave) - queued = ax25_ds_frame_in(ax25, skb, type); - else - queued = ax25_std_frame_in(ax25, skb, type); - break; + case AX25_PROTO_DAMA_SLAVE: + if (dama || ax25->ax25_dev->dama.slave) + queued = ax25_ds_frame_in(ax25, skb, type); + else + queued = ax25_std_frame_in(ax25, skb, type); + break; #endif } return queued; } -static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *dev_addr, struct packet_type *ptype) +static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, + ax25_address *dev_addr, struct packet_type *ptype) { - struct sock *make; - struct sock *sk; - int type = 0; + ax25_address src, dest, *next_digi = NULL; + int type = 0, mine = 0, dama; + struct sock *make, *sk, *raw; ax25_digi dp, reverse_dp; ax25_cb *ax25; - ax25_address src, dest; - ax25_address *next_digi = NULL; ax25_dev *ax25_dev; - struct sock *raw; - int mine = 0; - int dama; /* * Process the AX.25/LAPB frame. @@ -274,8 +240,10 @@ if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) { skb->h.raw = skb->data + 2; /* skip control and pid */ - if ((raw = ax25_addr_match(&dest)) != NULL) + if ((raw = ax25_addr_match(&dest)) != NULL) { ax25_send_to_raw(raw, skb, skb->data[1]); + release_sock(raw); + } if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) { kfree_skb(skb); @@ -285,47 +253,49 @@ /* Now we are pointing at the pid byte */ switch (skb->data[1]) { #ifdef CONFIG_INET - case AX25_P_IP: - skb_pull(skb,2); /* drop PID/CTRL */ - skb->h.raw = skb->data; - skb->nh.raw = skb->data; - skb->dev = dev; - skb->pkt_type = PACKET_HOST; - skb->protocol = htons(ETH_P_IP); - ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ - break; - - case AX25_P_ARP: - skb_pull(skb,2); - skb->h.raw = skb->data; - skb->nh.raw = skb->data; - skb->dev = dev; - skb->pkt_type = PACKET_HOST; - skb->protocol = htons(ETH_P_ARP); - arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ - break; + case AX25_P_IP: + skb_pull(skb,2); /* drop PID/CTRL */ + skb->h.raw = skb->data; + skb->nh.raw = skb->data; + skb->dev = dev; + skb->pkt_type = PACKET_HOST; + skb->protocol = htons(ETH_P_IP); + ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ + break; + + case AX25_P_ARP: + skb_pull(skb,2); + skb->h.raw = skb->data; + skb->nh.raw = skb->data; + skb->dev = dev; + skb->pkt_type = PACKET_HOST; + skb->protocol = htons(ETH_P_ARP); + arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ + break; #endif - case AX25_P_TEXT: - /* Now find a suitable dgram socket */ - if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) { - if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) { - kfree_skb(skb); - } else { - /* - * Remove the control and PID. - */ - skb_pull(skb, 2); - if (sock_queue_rcv_skb(sk, skb) != 0) - kfree_skb(skb); - } - } else { + case AX25_P_TEXT: + /* Now find a suitable dgram socket */ + sk = ax25_get_socket(&dest, &src, SOCK_DGRAM); + if (sk != NULL) { + if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) { kfree_skb(skb); + } else { + /* + * Remove the control and PID. + */ + skb_pull(skb, 2); + if (sock_queue_rcv_skb(sk, skb) != 0) + kfree_skb(skb); } - break; + release_sock(sk); + } else { + kfree_skb(skb); + } + break; - default: - kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */ - break; + default: + kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */ + break; } return 0; @@ -349,9 +319,10 @@ if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) { /* - * Process the frame. If it is queued up internally it returns one otherwise we - * free it immediately. This routine itself wakes the user context layers so we - * do no further work + * Process the frame. If it is queued up internally it + * returns one otherwise we free it immediately. This + * routine itself wakes the user context layers so we do + * no further work */ if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) kfree_skb(skb); @@ -363,7 +334,8 @@ /* a) received not a SABM(E) */ - if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) { + if ((*skb->data & ~AX25_PF) != AX25_SABM && + (*skb->data & ~AX25_PF) != AX25_SABME) { /* * Never reply to a DM. Also ignore any connects for * addresses that are not our interfaces and not a socket. @@ -383,9 +355,12 @@ sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET); if (sk != NULL) { - if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, ax25_dev)) == NULL) { - if (mine) ax25_return_dm(dev, &src, &dest, &dp); + if (sk->ack_backlog == sk->max_ack_backlog || + (make = ax25_make_new(sk, ax25_dev)) == NULL) { + if (mine) + ax25_return_dm(dev, &src, &dest, &dp); kfree_skb(skb); + return 0; } @@ -486,4 +461,3 @@ return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype); } - diff -Nru a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c --- a/net/ax25/ax25_ip.c Fri Sep 20 08:20:44 2002 +++ b/net/ax25/ax25_ip.c Fri Sep 20 08:20:44 2002 @@ -1,18 +1,11 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * AX.25 036 Jonathan(G4KLX) Split from af_ax25.c. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include @@ -88,16 +81,16 @@ /* Append a suitable AX.25 PID */ switch (type) { - case ETH_P_IP: - *buff++ = AX25_P_IP; - break; - case ETH_P_ARP: - *buff++ = AX25_P_ARP; - break; - default: - printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type); - *buff++ = 0; - break; + case ETH_P_IP: + *buff++ = AX25_P_IP; + break; + case ETH_P_ARP: + *buff++ = AX25_P_ARP; + break; + default: + printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type); + *buff++ = 0; + break; } if (daddr != NULL) @@ -112,8 +105,8 @@ unsigned char *bp = skb->data; struct net_device *dev; ax25_address *src, *dst; - ax25_route *route; ax25_dev *ax25_dev; + ax25_route _route, *route = &_route; dst = (ax25_address *)(bp + 1); src = (ax25_address *)(bp + 8); @@ -121,14 +114,15 @@ if (arp_find(bp + 1, skb)) return 1; - route = ax25_rt_find_route(dst, NULL); + route = ax25_rt_find_route(route, dst, NULL); dev = route->dev; if (dev == NULL) dev = skb->dev; - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) - return 1; + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { + goto put; + } if (bp[16] == AX25_P_IP) { if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) { @@ -153,7 +147,7 @@ if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) { kfree_skb(skb); - return 1; + goto put; } if (skb->sk != NULL) @@ -167,10 +161,10 @@ skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ ourskb->nh.raw = ourskb->data; - ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c, + ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c, &dst_c, route->digipeat, dev); - return 1; + goto put; } } @@ -187,7 +181,7 @@ if (route->digipeat != NULL) { if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) { kfree_skb(skb); - return 1; + goto put; } skb = ourskb; @@ -196,6 +190,9 @@ skb->dev = dev; ax25_queue_xmit(skb); + +put: + ax25_put_route(route); return 1; } diff -Nru a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c --- a/net/ax25/ax25_out.c Fri Sep 20 08:20:47 2002 +++ b/net/ax25/ax25_out.c Fri Sep 20 08:20:47 2002 @@ -1,39 +1,13 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; - * - * History - * AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams. - * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. - * Jonathan(G4KLX) Only poll when window is full. - * AX.25 030 Jonathan(G4KLX) Added fragmentation to ax25_output. - * Added support for extended AX.25. - * AX.25 031 Joerg(DL1BKE) Added DAMA support - * Joerg(DL1BKE) Modified fragmenter to fragment vanilla - * AX.25 I-Frames. Added PACLEN parameter. - * Joerg(DL1BKE) Fixed a problem with buffer allocation - * for fragments. - * AX.25 037 Jonathan(G4KLX) New timer architecture. - * Joerg(DL1BKE) Fixed DAMA Slave mode: will work - * on non-DAMA interfaces like AX25L2V2 - * again (this behaviour is _required_). - * Joerg(DL1BKE) ax25_check_iframes_acked() returns a - * value now (for DAMA n2count handling) + * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) */ - #include #include #include @@ -44,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +32,8 @@ #include #include +static spinlock_t ax25_frag_lock = SPIN_LOCK_UNLOCKED; + ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev) { ax25_dev *ax25_dev; @@ -101,18 +78,18 @@ } switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_establish_data_link(ax25); - break; + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_std_establish_data_link(ax25); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (ax25_dev->dama.slave) - ax25_ds_establish_data_link(ax25); - else - ax25_std_establish_data_link(ax25); - break; + case AX25_PROTO_DAMA_SLAVE: + if (ax25_dev->dama.slave) + ax25_ds_establish_data_link(ax25); + else + ax25_std_establish_data_link(ax25); + break; #endif } @@ -138,7 +115,6 @@ struct sk_buff *skbn; unsigned char *p; int frontlen, len, fragno, ka9qfrag, first = 1; - long flags; if ((skb->len - 1) > paclen) { if (*skb->data == AX25_P_TEXT) { @@ -155,20 +131,18 @@ frontlen = skb_headroom(skb); /* Address space + CTRL */ while (skb->len > 0) { - save_flags(flags); - cli(); - + spin_lock_bh(&ax25_frag_lock); if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) { - restore_flags(flags); + spin_unlock_bh(&ax25_frag_lock); printk(KERN_CRIT "AX.25: ax25_output - out of memory\n"); return; } if (skb->sk != NULL) skb_set_owner_w(skbn, skb->sk); - - restore_flags(flags); - + + spin_unlock_bh(&ax25_frag_lock); + len = (paclen > skb->len) ? skb->len : paclen; if (ka9qfrag == 1) { @@ -202,24 +176,24 @@ } switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_kick(ax25); - break; + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_kick(ax25); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - /* - * A DAMA slave is _required_ to work as normal AX.25L2V2 - * if no DAMA master is available. - */ - case AX25_PROTO_DAMA_SLAVE: - if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25); - break; + /* + * A DAMA slave is _required_ to work as normal AX.25L2V2 + * if no DAMA master is available. + */ + case AX25_PROTO_DAMA_SLAVE: + if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25); + break; #endif } } -/* +/* * This procedure is passed a buffer descriptor for an iframe. It builds * the rest of the control part of the frame and then writes it out. */ @@ -305,15 +279,15 @@ * in DAMA mode. */ switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF); - break; + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - ax25_send_iframe(ax25, skbn, AX25_POLLOFF); - break; + case AX25_PROTO_DAMA_SLAVE: + ax25_send_iframe(ax25, skbn, AX25_POLLOFF); + break; #endif } diff -Nru a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c --- a/net/ax25/ax25_route.c Fri Sep 20 08:20:47 2002 +++ b/net/ax25/ax25_route.c Fri Sep 20 08:20:47 2002 @@ -1,49 +1,20 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Other kernels modules in this kit are generally BSD derived. See the copyright headers. - * - * - * History - * AX.25 020 Jonathan(G4KLX) First go. - * AX.25 022 Jonathan(G4KLX) Added the actual meat to this - we now have a nice heard list. - * AX.25 025 Alan(GW4PTS) First cut at autobinding by route scan. - * AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the - * sock structure. Device removal now - * removes the heard structure. - * AX.25 029 Steven(GW7RRM) Added /proc information for uid/callsign mapping. - * Jonathan(G4KLX) Handling of IP mode in the routing list and /proc entry. - * AX.25 030 Jonathan(G4KLX) Added digi-peaters to routing table, and - * ioctls to manipulate them. Added port - * configuration. - * AX.25 031 Jonathan(G4KLX) Added concept of default route. - * Joerg(DL1BKE) ax25_rt_build_path() find digipeater list and device by - * destination call. Needed for IP routing via digipeater - * Jonathan(G4KLX) Added routing for IP datagram packets. - * Joerg(DL1BKE) Changed routing for IP datagram and VC to use a default - * route if available. Does not overwrite default routes - * on route-table overflow anymore. - * Joerg(DL1BKE) Fixed AX.25 routing of IP datagram and VC, new ioctl() - * "SIOCAX25OPTRT" to set IP mode and a 'permanent' flag - * on routes. - * AX.25 033 Jonathan(G4KLX) Remove auto-router. - * Joerg(DL1BKE) Moved BPQ Ethernet driver to separate device. - * AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating. - * Jonathan(G4KLX) Support for packet forwarding. - * Arnaldo C. Melo s/suser/capable/ + * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) + * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de) + * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) */ - #include #include #include +#include #include #include #include @@ -56,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -65,8 +37,9 @@ #include static ax25_route *ax25_route_list; +static rwlock_t ax25_route_lock = RW_LOCK_UNLOCKED; -static ax25_route *ax25_find_route(ax25_address *, struct net_device *); +static ax25_route *ax25_get_route(ax25_address *, struct net_device *); /* * small macro to drop non-digipeated digipeaters and reverse path @@ -86,8 +59,10 @@ void ax25_rt_device_down(struct net_device *dev) { - ax25_route *s, *t, *ax25_rt = ax25_route_list; - + ax25_route *s, *t, *ax25_rt; + + write_lock(&ax25_route_lock); + ax25_rt = ax25_route_list; while (ax25_rt != NULL) { s = ax25_rt; ax25_rt = ax25_rt->next; @@ -111,129 +86,196 @@ } } } + write_unlock(&ax25_route_lock); } -int ax25_rt_ioctl(unsigned int cmd, void *arg) +static int ax25_rt_add(struct ax25_routes_struct *route) { - unsigned long flags; - ax25_route *s, *t, *ax25_rt; - struct ax25_routes_struct route; - struct ax25_route_opt_struct rt_option; + ax25_route *ax25_rt; ax25_dev *ax25_dev; int i; - switch (cmd) { - case SIOCADDRT: - if (copy_from_user(&route, arg, sizeof(route))) - return -EFAULT; - if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL) - return -EINVAL; - if (route.digi_count > AX25_MAX_DIGIS) - return -EINVAL; - for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == ax25_dev->dev) { - if (ax25_rt->digipeat != NULL) { - kfree(ax25_rt->digipeat); - ax25_rt->digipeat = NULL; - } - if (route.digi_count != 0) { - if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) - return -ENOMEM; - ax25_rt->digipeat->lastrepeat = -1; - ax25_rt->digipeat->ndigi = route.digi_count; - for (i = 0; i < route.digi_count; i++) { - ax25_rt->digipeat->repeated[i] = 0; - ax25_rt->digipeat->calls[i] = route.digi_addr[i]; - } - } - return 0; - } + if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL) + return -EINVAL; + if (route->digi_count > AX25_MAX_DIGIS) + return -EINVAL; + + write_lock(&ax25_route_lock); + + ax25_rt = ax25_route_list; + while (ax25_rt != NULL) { + if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 && + ax25_rt->dev == ax25_dev->dev) { + if (ax25_rt->digipeat != NULL) { + kfree(ax25_rt->digipeat); + ax25_rt->digipeat = NULL; } - if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) - return -ENOMEM; - ax25_rt->callsign = route.dest_addr; - ax25_rt->dev = ax25_dev->dev; - ax25_rt->digipeat = NULL; - ax25_rt->ip_mode = ' '; - if (route.digi_count != 0) { + if (route->digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - kfree(ax25_rt); + write_unlock(&ax25_route_lock); return -ENOMEM; } ax25_rt->digipeat->lastrepeat = -1; - ax25_rt->digipeat->ndigi = route.digi_count; - for (i = 0; i < route.digi_count; i++) { + ax25_rt->digipeat->ndigi = route->digi_count; + for (i = 0; i < route->digi_count; i++) { ax25_rt->digipeat->repeated[i] = 0; - ax25_rt->digipeat->calls[i] = route.digi_addr[i]; + ax25_rt->digipeat->calls[i] = route->digi_addr[i]; } } - save_flags(flags); cli(); - ax25_rt->next = ax25_route_list; - ax25_route_list = ax25_rt; - restore_flags(flags); - break; + return 0; + } + ax25_rt = ax25_rt->next; + } - case SIOCDELRT: - if (copy_from_user(&route, arg, sizeof(route))) - return -EFAULT; - if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL) - return -EINVAL; - ax25_rt = ax25_route_list; - while (ax25_rt != NULL) { - s = ax25_rt; - ax25_rt = ax25_rt->next; - if (s->dev == ax25_dev->dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) { - if (ax25_route_list == s) { - ax25_route_list = s->next; - if (s->digipeat != NULL) - kfree(s->digipeat); - kfree(s); - } else { - for (t = ax25_route_list; t != NULL; t = t->next) { - if (t->next == s) { - t->next = s->next; - if (s->digipeat != NULL) - kfree(s->digipeat); - kfree(s); - break; - } - } + if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) { + write_unlock(&ax25_route_lock); + return -ENOMEM; + } + + atomic_set(&ax25_rt->ref, 0); + ax25_rt->callsign = route->dest_addr; + ax25_rt->dev = ax25_dev->dev; + ax25_rt->digipeat = NULL; + ax25_rt->ip_mode = ' '; + if (route->digi_count != 0) { + if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + write_unlock(&ax25_route_lock); + kfree(ax25_rt); + return -ENOMEM; + } + ax25_rt->digipeat->lastrepeat = -1; + ax25_rt->digipeat->ndigi = route->digi_count; + for (i = 0; i < route->digi_count; i++) { + ax25_rt->digipeat->repeated[i] = 0; + ax25_rt->digipeat->calls[i] = route->digi_addr[i]; + } + } + ax25_rt->next = ax25_route_list; + ax25_route_list = ax25_rt; + write_unlock(&ax25_route_lock); + + return 0; +} + +static void ax25_rt_destroy(ax25_route *ax25_rt) +{ + if (atomic_read(&ax25_rt->ref) == 0) { + if (ax25_rt->digipeat != NULL) + kfree(ax25_rt->digipeat); + kfree(ax25_rt); + } + + /* + * Uh... Route is still in use; we can't yet destroy it. Retry later. + */ + init_timer(&ax25_rt->timer); + ax25_rt->timer.data = (unsigned long) ax25_rt; + ax25_rt->timer.function = (void *) ax25_rt_destroy; + ax25_rt->timer.expires = jiffies + 5 * HZ; + + add_timer(&ax25_rt->timer); +} + +static int ax25_rt_del(struct ax25_routes_struct *route) +{ + ax25_route *s, *t, *ax25_rt; + ax25_dev *ax25_dev; + + if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL) + return -EINVAL; + + write_lock(&ax25_route_lock); + + ax25_rt = ax25_route_list; + while (ax25_rt != NULL) { + s = ax25_rt; + ax25_rt = ax25_rt->next; + if (s->dev == ax25_dev->dev && + ax25cmp(&route->dest_addr, &s->callsign) == 0) { + if (ax25_route_list == s) { + ax25_route_list = s->next; + ax25_rt_destroy(s); + } else { + for (t = ax25_route_list; t != NULL; t = t->next) { + if (t->next == s) { + t->next = s->next; + ax25_rt_destroy(s); + break; } } } - break; + } + } + write_unlock(&ax25_route_lock); - case SIOCAX25OPTRT: - if (copy_from_user(&rt_option, arg, sizeof(rt_option))) - return -EFAULT; - if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL) - return -EINVAL; - for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (ax25_rt->dev == ax25_dev->dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) { - switch (rt_option.cmd) { - case AX25_SET_RT_IPMODE: - switch (rt_option.arg) { - case ' ': - case 'D': - case 'V': - ax25_rt->ip_mode = rt_option.arg; - break; - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } + return 0; +} + +static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option) +{ + ax25_route *ax25_rt; + ax25_dev *ax25_dev; + int err = 0; + + if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL) + return -EINVAL; + + write_lock(&ax25_route_lock); + + ax25_rt = ax25_route_list; + while (ax25_rt != NULL) { + if (ax25_rt->dev == ax25_dev->dev && + ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) { + switch (rt_option->cmd) { + case AX25_SET_RT_IPMODE: + switch (rt_option->arg) { + case ' ': + case 'D': + case 'V': + ax25_rt->ip_mode = rt_option->arg; + break; + default: + err = -EINVAL; + goto out; } + break; + default: + err = -EINVAL; + goto out; } - break; - - default: - return -EINVAL; + } + ax25_rt = ax25_rt->next; } - return 0; +out: + write_unlock(&ax25_route_lock); + return err; +} + +int ax25_rt_ioctl(unsigned int cmd, void *arg) +{ + struct ax25_route_opt_struct rt_option; + struct ax25_routes_struct route; + + switch (cmd) { + case SIOCADDRT: + if (copy_from_user(&route, arg, sizeof(route))) + return -EFAULT; + return ax25_rt_add(&route); + + case SIOCDELRT: + if (copy_from_user(&route, arg, sizeof(route))) + return -EFAULT; + return ax25_rt_del(&route); + + case SIOCAX25OPTRT: + if (copy_from_user(&rt_option, arg, sizeof(rt_option))) + return -EFAULT; + return ax25_rt_opt(&rt_option); + + default: + return -EINVAL; + } } int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length) @@ -244,8 +286,8 @@ off_t begin = 0; char *callsign; int i; - - cli(); + + read_lock(&ax25_route_lock); len += sprintf(buffer, "callsign dev mode digipeaters\n"); @@ -259,15 +301,15 @@ ax25_rt->dev ? ax25_rt->dev->name : "???"); switch (ax25_rt->ip_mode) { - case 'V': - len += sprintf(buffer + len, " vc"); - break; - case 'D': - len += sprintf(buffer + len, " dg"); - break; - default: - len += sprintf(buffer + len, " *"); - break; + case 'V': + len += sprintf(buffer + len, " vc"); + break; + case 'D': + len += sprintf(buffer + len, " dg"); + break; + default: + len += sprintf(buffer + len, " *"); + break; } if (ax25_rt->digipeat != NULL) @@ -286,26 +328,29 @@ if (pos > offset + length) break; } - - sti(); + read_unlock(&ax25_route_lock); *start = buffer + (offset - begin); len -= (offset - begin); - if (len > length) len = length; + if (len > length) + len = length; return len; -} +} /* * Find AX.25 route + * + * Only routes with a refernce rout of zero can be destroyed. */ -static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev) +static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) { ax25_route *ax25_spe_rt = NULL; ax25_route *ax25_def_rt = NULL; ax25_route *ax25_rt; + read_lock(&ax25_route_lock); /* * Bind to the physical interface we heard them on, or the default * route if none is found; @@ -324,10 +369,16 @@ } } + ax25_rt = ax25_def_rt; if (ax25_spe_rt != NULL) - return ax25_spe_rt; + ax25_rt = ax25_spe_rt; - return ax25_def_rt; + if (ax25_rt != NULL) + atomic_inc(&ax25_rt->ref); + + read_unlock(&ax25_route_lock); + + return ax25_rt; } /* @@ -346,7 +397,7 @@ digipeat->ndigi = k; } - + /* * Find which interface to use. @@ -355,24 +406,31 @@ { ax25_route *ax25_rt; ax25_address *call; + int err; - if ((ax25_rt = ax25_find_route(addr, NULL)) == NULL) + if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL) return -EHOSTUNREACH; - if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) - return -EHOSTUNREACH; + if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) { + err = -EHOSTUNREACH; + goto put; + } if ((call = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) - return -EPERM; + if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) { + err = -EPERM; + goto put; + } call = (ax25_address *)ax25->ax25_dev->dev->dev_addr; } ax25->source_addr = *call; if (ax25_rt->digipeat != NULL) { - if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) - return -ENOMEM; + if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + err = -ENOMEM; + goto put; + } memcpy(ax25->digipeat, ax25_rt->digipeat, sizeof(ax25_digi)); ax25_adjust_path(addr, ax25->digipeat); } @@ -380,31 +438,32 @@ if (ax25->sk != NULL) ax25->sk->zapped = 0; +put: + ax25_put_route(ax25_rt); + return 0; } -/* - * dl1bke 960117: build digipeater path - * dl1bke 960301: use the default route if it exists - */ -ax25_route *ax25_rt_find_route(ax25_address *addr, struct net_device *dev) +ax25_route *ax25_rt_find_route(ax25_route * route, ax25_address *addr, + struct net_device *dev) { - static ax25_route route; ax25_route *ax25_rt; - if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) { - route.next = NULL; - route.callsign = *addr; - route.dev = dev; - route.digipeat = NULL; - route.ip_mode = ' '; - return &route; - } + if ((ax25_rt = ax25_get_route(addr, dev))) + return ax25_rt; - return ax25_rt; + route->next = NULL; + atomic_set(&route->ref, 1); + route->callsign = *addr; + route->dev = dev; + route->digipeat = NULL; + route->ip_mode = ' '; + + return route; } -struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_address *dest, ax25_digi *digi) +struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, + ax25_address *dest, ax25_digi *digi) { struct sk_buff *skbn; unsigned char *bp; @@ -440,6 +499,7 @@ { ax25_route *s, *ax25_rt = ax25_route_list; + write_unlock(&ax25_route_lock); while (ax25_rt != NULL) { s = ax25_rt; ax25_rt = ax25_rt->next; @@ -449,4 +509,5 @@ kfree(s); } + write_unlock(&ax25_route_lock); } diff -Nru a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c --- a/net/ax25/ax25_std_in.c Fri Sep 20 08:20:43 2002 +++ b/net/ax25/ax25_std_in.c Fri Sep 20 08:20:43 2002 @@ -1,42 +1,19 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 + * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) + * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de) * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; - * - * History - * AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams. - * AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from - * the sock structure. - * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. - * Jonathan(G4KLX) Added IP mode registration. - * AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception. - * Upgraded state machine for SABME. - * Added arbitrary protocol id support. - * AX.25 031 Joerg(DL1BKE) Added DAMA support - * HaJo(DD8NE) Added Idle Disc Timer T5 - * Joerg(DL1BKE) Renamed it to "IDLE" with a slightly - * different behaviour. Fixed defrag - * routine (I hope) - * AX.25 032 Darryl(G7LED) AX.25 segmentation fixed. - * AX.25 033 Jonathan(G4KLX) Remove auto-router. - * Modularisation changes. - * AX.25 035 Hans(PE1AYX) Fixed interface to IP layer. - * AX.25 036 Jonathan(G4KLX) Cloned from ax25_in.c. - * AX.25 037 Jonathan(G4KLX) New timer architecture. + * Most of this code is based on the SDL diagrams published in the 7th ARRL + * Computer Networking Conference papers. The diagrams have mistakes in them, + * but are mostly correct. Before you modify the code could you read the SDL + * diagrams as the code is not obvious and probably very easy to break. */ - #include #include #include @@ -68,55 +45,55 @@ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) { switch (frametype) { - case AX25_SABM: - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - break; - - case AX25_SABME: - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); - break; - - case AX25_UA: - if (pf) { - ax25_calculate_rtt(ax25); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - if (ax25->sk != NULL) { - ax25->sk->state = TCP_ESTABLISHED; - /* For WAIT_SABM connections we will produce an accept ready socket here */ - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - } - } - break; - - case AX25_DM: - if (pf) { - if (ax25->modulus == AX25_MODULUS) { - ax25_disconnect(ax25, ECONNREFUSED); - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - } + case AX25_SABM: + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + break; + + case AX25_SABME: + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + break; + + case AX25_DISC: + ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); + break; + + case AX25_UA: + if (pf) { + ax25_calculate_rtt(ax25); + ax25_stop_t1timer(ax25); + ax25_start_t3timer(ax25); + ax25_start_idletimer(ax25); + ax25->vs = 0; + ax25->va = 0; + ax25->vr = 0; + ax25->state = AX25_STATE_3; + ax25->n2count = 0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_ESTABLISHED; + /* For WAIT_SABM connections we will produce an accept ready socket here */ + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + } + } + break; + + case AX25_DM: + if (pf) { + if (ax25->modulus == AX25_MODULUS) { + ax25_disconnect(ax25, ECONNREFUSED); + } else { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; } - break; + } + break; - default: - break; + default: + break; } return 0; @@ -130,30 +107,31 @@ static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) { switch (frametype) { - case AX25_SABM: - case AX25_SABME: - ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + case AX25_SABM: + case AX25_SABME: + ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); + break; + + case AX25_DISC: + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25_disconnect(ax25, 0); + break; + + case AX25_DM: + case AX25_UA: + if (pf) ax25_disconnect(ax25, 0); - break; + break; - case AX25_DM: - case AX25_UA: - if (pf) ax25_disconnect(ax25, 0); - break; - - case AX25_I: - case AX25_REJ: - case AX25_RNR: - case AX25_RR: - if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); - break; + case AX25_I: + case AX25_REJ: + case AX25_RNR: + case AX25_RR: + if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); + break; - default: - break; + default: + break; } return 0; @@ -169,116 +147,116 @@ int queued = 0; switch (frametype) { - case AX25_SABM: - case AX25_SABME: - if (frametype == AX25_SABM) { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - } else { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; - } - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + case AX25_SABM: + case AX25_SABME: + if (frametype == AX25_SABM) { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + } else { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; + } + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25_stop_t1timer(ax25); + ax25_stop_t2timer(ax25); + ax25_start_t3timer(ax25); + ax25_start_idletimer(ax25); + ax25->condition = 0x00; + ax25->vs = 0; + ax25->va = 0; + ax25->vr = 0; + ax25_requeue_frames(ax25); + break; + + case AX25_DISC: + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25_disconnect(ax25, 0); + break; + + case AX25_DM: + ax25_disconnect(ax25, ECONNRESET); + break; + + case AX25_RR: + case AX25_RNR: + if (frametype == AX25_RR) + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + else + ax25->condition |= AX25_COND_PEER_RX_BUSY; + if (type == AX25_COMMAND && pf) + ax25_std_enquiry_response(ax25); + if (ax25_validate_nr(ax25, nr)) { + ax25_check_iframes_acked(ax25, nr); + } else { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; + + case AX25_REJ: + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + if (type == AX25_COMMAND && pf) + ax25_std_enquiry_response(ax25); + if (ax25_validate_nr(ax25, nr)) { + ax25_frames_acked(ax25, nr); + ax25_calculate_rtt(ax25); ax25_stop_t1timer(ax25); - ax25_stop_t2timer(ax25); ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - ax25->condition = 0x00; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; ax25_requeue_frames(ax25); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_disconnect(ax25, 0); - break; - - case AX25_DM: - ax25_disconnect(ax25, ECONNRESET); - break; + } else { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; - case AX25_RR: - case AX25_RNR: - if (frametype == AX25_RR) - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - else - ax25->condition |= AX25_COND_PEER_RX_BUSY; - if (type == AX25_COMMAND && pf) - ax25_std_enquiry_response(ax25); - if (ax25_validate_nr(ax25, nr)) { - ax25_check_iframes_acked(ax25, nr); - } else { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } + case AX25_I: + if (!ax25_validate_nr(ax25, nr)) { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; break; - - case AX25_REJ: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - if (type == AX25_COMMAND && pf) + } + if (ax25->condition & AX25_COND_PEER_RX_BUSY) { + ax25_frames_acked(ax25, nr); + } else { + ax25_check_iframes_acked(ax25, nr); + } + if (ax25->condition & AX25_COND_OWN_RX_BUSY) { + if (pf) ax25_std_enquiry_response(ax25); + break; + } + if (ns == ax25->vr) { + ax25->vr = (ax25->vr + 1) % ax25->modulus; + queued = ax25_rx_iframe(ax25, skb); + if (ax25->condition & AX25_COND_OWN_RX_BUSY) + ax25->vr = ns; /* ax25->vr - 1 */ + ax25->condition &= ~AX25_COND_REJECT; + if (pf) { ax25_std_enquiry_response(ax25); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - ax25_calculate_rtt(ax25); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - ax25_requeue_frames(ax25); } else { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case AX25_I: - if (!ax25_validate_nr(ax25, nr)) { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - break; - } - if (ax25->condition & AX25_COND_PEER_RX_BUSY) { - ax25_frames_acked(ax25, nr); - } else { - ax25_check_iframes_acked(ax25, nr); + if (!(ax25->condition & AX25_COND_ACK_PENDING)) { + ax25->condition |= AX25_COND_ACK_PENDING; + ax25_start_t2timer(ax25); + } } - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { + } else { + if (ax25->condition & AX25_COND_REJECT) { if (pf) ax25_std_enquiry_response(ax25); - break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; - queued = ax25_rx_iframe(ax25, skb); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25->vr = ns; /* ax25->vr - 1 */ - ax25->condition &= ~AX25_COND_REJECT; - if (pf) { - ax25_std_enquiry_response(ax25); - } else { - if (!(ax25->condition & AX25_COND_ACK_PENDING)) { - ax25->condition |= AX25_COND_ACK_PENDING; - ax25_start_t2timer(ax25); - } - } } else { - if (ax25->condition & AX25_COND_REJECT) { - if (pf) ax25_std_enquiry_response(ax25); - } else { - ax25->condition |= AX25_COND_REJECT; - ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); - ax25->condition &= ~AX25_COND_ACK_PENDING; - } - } - break; - - case AX25_FRMR: - case AX25_ILLEGAL: - ax25_std_establish_data_link(ax25); - ax25->state = AX25_STATE_1; - break; + ax25->condition |= AX25_COND_REJECT; + ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); + ax25->condition &= ~AX25_COND_ACK_PENDING; + } + } + break; + + case AX25_FRMR: + case AX25_ILLEGAL: + ax25_std_establish_data_link(ax25); + ax25->state = AX25_STATE_1; + break; - default: - break; + default: + break; } return queued; @@ -294,145 +272,146 @@ int queued = 0; switch (frametype) { - case AX25_SABM: - case AX25_SABME: - if (frametype == AX25_SABM) { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - } else { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; - } - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + case AX25_SABM: + case AX25_SABME: + if (frametype == AX25_SABM) { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + } else { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; + } + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25_stop_t1timer(ax25); + ax25_stop_t2timer(ax25); + ax25_start_t3timer(ax25); + ax25_start_idletimer(ax25); + ax25->condition = 0x00; + ax25->vs = 0; + ax25->va = 0; + ax25->vr = 0; + ax25->state = AX25_STATE_3; + ax25->n2count = 0; + ax25_requeue_frames(ax25); + break; + + case AX25_DISC: + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25_disconnect(ax25, 0); + break; + + case AX25_DM: + ax25_disconnect(ax25, ECONNRESET); + break; + + case AX25_RR: + case AX25_RNR: + if (frametype == AX25_RR) + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + else + ax25->condition |= AX25_COND_PEER_RX_BUSY; + if (type == AX25_RESPONSE && pf) { ax25_stop_t1timer(ax25); - ax25_stop_t2timer(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - ax25->condition = 0x00; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - ax25_requeue_frames(ax25); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_disconnect(ax25, 0); - break; - - case AX25_DM: - ax25_disconnect(ax25, ECONNRESET); - break; - - case AX25_RR: - case AX25_RNR: - if (frametype == AX25_RR) - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - else - ax25->condition |= AX25_COND_PEER_RX_BUSY; - if (type == AX25_RESPONSE && pf) { - ax25_stop_t1timer(ax25); - ax25->n2count = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if (ax25->vs == ax25->va) { - ax25_start_t3timer(ax25); - ax25->state = AX25_STATE_3; - } else { - ax25_requeue_frames(ax25); - } - } else { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - if (type == AX25_COMMAND && pf) - ax25_std_enquiry_response(ax25); + ax25->n2count = 0; if (ax25_validate_nr(ax25, nr)) { ax25_frames_acked(ax25, nr); + if (ax25->vs == ax25->va) { + ax25_start_t3timer(ax25); + ax25->state = AX25_STATE_3; + } else { + ax25_requeue_frames(ax25); + } } else { ax25_std_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; } break; + } + if (type == AX25_COMMAND && pf) + ax25_std_enquiry_response(ax25); + if (ax25_validate_nr(ax25, nr)) { + ax25_frames_acked(ax25, nr); + } else { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; - case AX25_REJ: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - if (pf && type == AX25_RESPONSE) { - ax25_stop_t1timer(ax25); - ax25->n2count = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if (ax25->vs == ax25->va) { - ax25_start_t3timer(ax25); - ax25->state = AX25_STATE_3; - } else { - ax25_requeue_frames(ax25); - } - } else { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - if (type == AX25_COMMAND && pf) - ax25_std_enquiry_response(ax25); + case AX25_REJ: + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + if (pf && type == AX25_RESPONSE) { + ax25_stop_t1timer(ax25); + ax25->n2count = 0; if (ax25_validate_nr(ax25, nr)) { ax25_frames_acked(ax25, nr); - ax25_requeue_frames(ax25); + if (ax25->vs == ax25->va) { + ax25_start_t3timer(ax25); + ax25->state = AX25_STATE_3; + } else { + ax25_requeue_frames(ax25); + } } else { ax25_std_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; } break; - - case AX25_I: - if (!ax25_validate_nr(ax25, nr)) { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - break; - } + } + if (type == AX25_COMMAND && pf) + ax25_std_enquiry_response(ax25); + if (ax25_validate_nr(ax25, nr)) { ax25_frames_acked(ax25, nr); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { - if (pf) ax25_std_enquiry_response(ax25); - break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; - queued = ax25_rx_iframe(ax25, skb); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25->vr = ns; /* ax25->vr - 1 */ - ax25->condition &= ~AX25_COND_REJECT; - if (pf) { - ax25_std_enquiry_response(ax25); - } else { - if (!(ax25->condition & AX25_COND_ACK_PENDING)) { - ax25->condition |= AX25_COND_ACK_PENDING; - ax25_start_t2timer(ax25); - } - } - } else { - if (ax25->condition & AX25_COND_REJECT) { - if (pf) ax25_std_enquiry_response(ax25); - } else { - ax25->condition |= AX25_COND_REJECT; - ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); - ax25->condition &= ~AX25_COND_ACK_PENDING; - } - } - break; + ax25_requeue_frames(ax25); + } else { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; - case AX25_FRMR: - case AX25_ILLEGAL: - ax25_std_establish_data_link(ax25); + case AX25_I: + if (!ax25_validate_nr(ax25, nr)) { + ax25_std_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; break; - - default: + } + ax25_frames_acked(ax25, nr); + if (ax25->condition & AX25_COND_OWN_RX_BUSY) { + if (pf) + ax25_std_enquiry_response(ax25); break; + } + if (ns == ax25->vr) { + ax25->vr = (ax25->vr + 1) % ax25->modulus; + queued = ax25_rx_iframe(ax25, skb); + if (ax25->condition & AX25_COND_OWN_RX_BUSY) + ax25->vr = ns; /* ax25->vr - 1 */ + ax25->condition &= ~AX25_COND_REJECT; + if (pf) { + ax25_std_enquiry_response(ax25); + } else { + if (!(ax25->condition & AX25_COND_ACK_PENDING)) { + ax25->condition |= AX25_COND_ACK_PENDING; + ax25_start_t2timer(ax25); + } + } + } else { + if (ax25->condition & AX25_COND_REJECT) { + if (pf) ax25_std_enquiry_response(ax25); + } else { + ax25->condition |= AX25_COND_REJECT; + ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); + ax25->condition &= ~AX25_COND_ACK_PENDING; + } + } + break; + + case AX25_FRMR: + case AX25_ILLEGAL: + ax25_std_establish_data_link(ax25); + ax25->state = AX25_STATE_1; + break; + + default: + break; } return queued; @@ -448,18 +427,18 @@ frametype = ax25_decode(ax25, skb, &ns, &nr, &pf); switch (ax25->state) { - case AX25_STATE_1: - queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type); - break; - case AX25_STATE_2: - queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type); - break; - case AX25_STATE_3: - queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type); - break; - case AX25_STATE_4: - queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type); - break; + case AX25_STATE_1: + queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type); + break; + case AX25_STATE_2: + queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type); + break; + case AX25_STATE_3: + queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type); + break; + case AX25_STATE_4: + queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type); + break; } ax25_kick(ax25); diff -Nru a/net/ax25/ax25_std_subr.c b/net/ax25/ax25_std_subr.c --- a/net/ax25/ax25_std_subr.c Fri Sep 20 08:20:41 2002 +++ b/net/ax25/ax25_std_subr.c Fri Sep 20 08:20:41 2002 @@ -1,25 +1,11 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; - * - * History - * AX.25 036 Jonathan(G4KLX) Split from ax25_out.c. - * AX.25 037 Jonathan(G4KLX) New timer architecture. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include @@ -80,7 +66,7 @@ ax25_calculate_t1(ax25); ax25_start_t1timer(ax25); } - + void ax25_std_enquiry_response(ax25_cb *ax25) { if (ax25->condition & AX25_COND_OWN_RX_BUSY) diff -Nru a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c --- a/net/ax25/ax25_std_timer.c Fri Sep 20 08:20:44 2002 +++ b/net/ax25/ax25_std_timer.c Fri Sep 20 08:20:44 2002 @@ -1,27 +1,14 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams. - * AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the - * sock structure. - * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. - * AX.25 031 Joerg(DL1BKE) Added DAMA support - * AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout bug - * AX.25 033 Jonathan(G4KLX) Modularisation functions. - * AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating. - * AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c. - * AX.25 037 Jonathan(G4KLX) New timer architecture. + * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) + * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) */ - #include #include #include @@ -47,30 +34,29 @@ void ax25_std_heartbeat_expiry(ax25_cb *ax25) { switch (ax25->state) { - - case AX25_STATE_0: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { - ax25_destroy_socket(ax25); - return; - } - break; - - case AX25_STATE_3: - case AX25_STATE_4: - /* - * Check the state of the receive buffer. - */ - if (ax25->sk != NULL) { - if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && - (ax25->condition & AX25_COND_OWN_RX_BUSY)) { - ax25->condition &= ~AX25_COND_OWN_RX_BUSY; - ax25->condition &= ~AX25_COND_ACK_PENDING; - ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); - break; - } + case AX25_STATE_0: + /* Magic here: If we listen() and a new link dies before it + is accepted() it isn't 'dead' so doesn't get removed. */ + if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { + ax25_destroy_socket(ax25); + return; + } + break; + + case AX25_STATE_3: + case AX25_STATE_4: + /* + * Check the state of the receive buffer. + */ + if (ax25->sk != NULL) { + if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && + (ax25->condition & AX25_COND_OWN_RX_BUSY)) { + ax25->condition &= ~AX25_COND_OWN_RX_BUSY; + ax25->condition &= ~AX25_COND_ACK_PENDING; + ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); + break; } + } } ax25_start_heartbeat(ax25); @@ -117,53 +103,53 @@ void ax25_std_t1timer_expiry(ax25_cb *ax25) { switch (ax25->state) { - case AX25_STATE_1: - if (ax25->n2count == ax25->n2) { - if (ax25->modulus == AX25_MODULUS) { - ax25_disconnect(ax25, ETIMEDOUT); - return; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - ax25->n2count = 0; - ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); - } - } else { - ax25->n2count++; - if (ax25->modulus == AX25_MODULUS) - ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); - else - ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND); - } - break; - - case AX25_STATE_2: - if (ax25->n2count == ax25->n2) { - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + case AX25_STATE_1: + if (ax25->n2count == ax25->n2) { + if (ax25->modulus == AX25_MODULUS) { ax25_disconnect(ax25, ETIMEDOUT); return; } else { - ax25->n2count++; - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + ax25->n2count = 0; + ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); } - break; - - case AX25_STATE_3: - ax25->n2count = 1; + } else { + ax25->n2count++; + if (ax25->modulus == AX25_MODULUS) + ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); + else + ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND); + } + break; + + case AX25_STATE_2: + if (ax25->n2count == ax25->n2) { + ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + ax25_disconnect(ax25, ETIMEDOUT); + return; + } else { + ax25->n2count++; + ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + } + break; + + case AX25_STATE_3: + ax25->n2count = 1; + ax25_std_transmit_enquiry(ax25); + ax25->state = AX25_STATE_4; + break; + + case AX25_STATE_4: + if (ax25->n2count == ax25->n2) { + ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); + ax25_disconnect(ax25, ETIMEDOUT); + return; + } else { + ax25->n2count++; ax25_std_transmit_enquiry(ax25); - ax25->state = AX25_STATE_4; - break; - - case AX25_STATE_4: - if (ax25->n2count == ax25->n2) { - ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); - ax25_disconnect(ax25, ETIMEDOUT); - return; - } else { - ax25->n2count++; - ax25_std_transmit_enquiry(ax25); - } - break; + } + break; } ax25_calculate_t1(ax25); diff -Nru a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c --- a/net/ax25/ax25_subr.c Fri Sep 20 08:20:48 2002 +++ b/net/ax25/ax25_subr.c Fri Sep 20 08:20:48 2002 @@ -1,38 +1,14 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; - * - * History - * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. Removed - * old BSD code. - * AX.25 030 Jonathan(G4KLX) Added support for extended AX.25. - * Added fragmentation support. - * Darryl(G7LED) Added function ax25_requeue_frames() to split - * it up from ax25_frames_acked(). - * AX.25 031 Joerg(DL1BKE) DAMA needs KISS Fullduplex ON/OFF. - * Thus we have ax25_kiss_cmd() now... ;-) - * Dave Brown(N2RJT) - * Killed a silly bug in the DAMA code. - * Joerg(DL1BKE) Found the real bug in ax25.h, sri. - * AX.25 032 Joerg(DL1BKE) Added ax25_queue_length to count the number of - * enqueued buffers of a socket.. - * AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating. - * AX.25 037 Jonathan(G4KLX) New timer architecture. + * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) + * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) */ - #include #include #include @@ -172,9 +148,9 @@ return frametype; } -/* +/* * This routine is called when the HDLC layer internally generates a - * command or response for the remote machine ( eg. RR, UA etc. ). + * command or response for the remote machine ( eg. RR, UA etc. ). * Only supervisory or unnumbered frames are processed. */ void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type) @@ -231,7 +207,7 @@ skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi)); skb->nh.raw = skb->data; - + ax25_digi_invert(digi, &retdigi); dptr = skb_put(skb, 1); @@ -257,18 +233,18 @@ int n, t = 2; switch (ax25->backoff) { - case 0: - break; + case 0: + break; - case 1: - t += 2 * ax25->n2count; - break; - - case 2: - for (n = 0; n < ax25->n2count; n++) - t *= 2; - if (t > 8) t = 8; - break; + case 1: + t += 2 * ax25->n2count; + break; + + case 2: + for (n = 0; n < ax25->n2count; n++) + t *= 2; + if (t > 8) t = 8; + break; } ax25->t1 = t * ax25->rtt; diff -Nru a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c --- a/net/ax25/ax25_timer.c Fri Sep 20 08:20:47 2002 +++ b/net/ax25/ax25_timer.c Fri Sep 20 08:20:47 2002 @@ -1,30 +1,17 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams. - * AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the - * sock structure. - * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. - * AX.25 031 Joerg(DL1BKE) Added DAMA support - * AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout bug - * AX.25 033 Jonathan(G4KLX) Modularisation functions. - * AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating. - * AX.25 036 Jonathan(G4KLX) Split Standard and DAMA code into separate files. - * Joerg(DL1BKE) Fixed DAMA Slave. We are *required* to start with - * standard AX.25 mode. - * AX.25 037 Jonathan(G4KLX) New timer architecture. - * Tomi(OH2BNS) Fixed heartbeat expiry (check ax25_dev). + * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi) + * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk) + * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) + * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) + * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org) */ - #include #include #include @@ -152,105 +139,121 @@ static void ax25_heartbeat_expiry(unsigned long param) { - ax25_cb *ax25 = (ax25_cb *)param; int proto = AX25_PROTO_STD_SIMPLEX; + ax25_cb *ax25 = (ax25_cb *)param; + struct sock *sk = ax25->sk; if (ax25->ax25_dev) proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]; + bh_lock_sock(sk); + switch (proto) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_heartbeat_expiry(ax25); - break; + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_std_heartbeat_expiry(ax25); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (ax25->ax25_dev->dama.slave) - ax25_ds_heartbeat_expiry(ax25); - else - ax25_std_heartbeat_expiry(ax25); - break; + case AX25_PROTO_DAMA_SLAVE: + if (ax25->ax25_dev->dama.slave) + ax25_ds_heartbeat_expiry(ax25); + else + ax25_std_heartbeat_expiry(ax25); + break; #endif } + bh_unlock_sock(sk); } static void ax25_t1timer_expiry(unsigned long param) { ax25_cb *ax25 = (ax25_cb *)param; + struct sock *sk = ax25->sk; + bh_lock_sock(sk); switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_t1timer_expiry(ax25); - break; + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_std_t1timer_expiry(ax25); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (!ax25->ax25_dev->dama.slave) - ax25_std_t1timer_expiry(ax25); - break; + case AX25_PROTO_DAMA_SLAVE: + if (!ax25->ax25_dev->dama.slave) + ax25_std_t1timer_expiry(ax25); + break; #endif } + bh_unlock_sock(sk); } static void ax25_t2timer_expiry(unsigned long param) { ax25_cb *ax25 = (ax25_cb *)param; + struct sock *sk = ax25->sk; + bh_lock_sock(sk); switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_t2timer_expiry(ax25); - break; + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_std_t2timer_expiry(ax25); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (!ax25->ax25_dev->dama.slave) - ax25_std_t2timer_expiry(ax25); - break; + case AX25_PROTO_DAMA_SLAVE: + if (!ax25->ax25_dev->dama.slave) + ax25_std_t2timer_expiry(ax25); + break; #endif } + bh_unlock_sock(sk); } static void ax25_t3timer_expiry(unsigned long param) { ax25_cb *ax25 = (ax25_cb *)param; + struct sock *sk = ax25->sk; + bh_lock_sock(sk); switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_t3timer_expiry(ax25); - break; + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_std_t3timer_expiry(ax25); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (ax25->ax25_dev->dama.slave) - ax25_ds_t3timer_expiry(ax25); - else - ax25_std_t3timer_expiry(ax25); - break; + case AX25_PROTO_DAMA_SLAVE: + if (ax25->ax25_dev->dama.slave) + ax25_ds_t3timer_expiry(ax25); + else + ax25_std_t3timer_expiry(ax25); + break; #endif } + bh_unlock_sock(sk); } static void ax25_idletimer_expiry(unsigned long param) { ax25_cb *ax25 = (ax25_cb *)param; + struct sock *sk = ax25->sk; + bh_lock_sock(sk); switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_idletimer_expiry(ax25); - break; + case AX25_PROTO_STD_SIMPLEX: + case AX25_PROTO_STD_DUPLEX: + ax25_std_idletimer_expiry(ax25); + break; #ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (ax25->ax25_dev->dama.slave) - ax25_ds_idletimer_expiry(ax25); - else - ax25_std_idletimer_expiry(ax25); - break; + case AX25_PROTO_DAMA_SLAVE: + if (ax25->ax25_dev->dama.slave) + ax25_ds_idletimer_expiry(ax25); + else + ax25_std_idletimer_expiry(ax25); + break; #endif } + bh_unlock_sock(sk); } diff -Nru a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c --- a/net/ax25/ax25_uid.c Fri Sep 20 08:20:43 2002 +++ b/net/ax25/ax25_uid.c Fri Sep 20 08:20:43 2002 @@ -1,18 +1,11 @@ /* - * AX.25 release 037 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * AX.25 036 Jonathan(G4KLX) Split from af_ax25.c. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include @@ -23,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -47,17 +41,23 @@ */ static ax25_uid_assoc *ax25_uid_list; +static rwlock_t ax25_uid_lock = RW_LOCK_UNLOCKED; int ax25_uid_policy = 0; ax25_address *ax25_findbyuid(uid_t uid) { ax25_uid_assoc *ax25_uid; + ax25_address *res = NULL; + read_lock(&ax25_uid_lock); for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { - if (ax25_uid->uid == uid) - return &ax25_uid->call; + if (ax25_uid->uid == uid) { + res = &ax25_uid->call; + break; + } } + read_unlock(&ax25_uid_lock); return NULL; } @@ -65,63 +65,77 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) { ax25_uid_assoc *s, *ax25_uid; - unsigned long flags; + unsigned long res; switch (cmd) { - case SIOCAX25GETUID: - for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { - if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) - return ax25_uid->uid; + case SIOCAX25GETUID: + res = -ENOENT; + read_lock(&ax25_uid_lock); + for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { + if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { + res = ax25_uid->uid; + break; } - return -ENOENT; + } + read_unlock(&ax25_uid_lock); - case SIOCAX25ADDUID: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (ax25_findbyuid(sax->sax25_uid)) - return -EEXIST; - if (sax->sax25_uid == 0) - return -EINVAL; - if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL) - return -ENOMEM; - ax25_uid->uid = sax->sax25_uid; - ax25_uid->call = sax->sax25_call; - save_flags(flags); cli(); - ax25_uid->next = ax25_uid_list; - ax25_uid_list = ax25_uid; - restore_flags(flags); - return 0; + return res; + + case SIOCAX25ADDUID: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (ax25_findbyuid(sax->sax25_uid)) + return -EEXIST; + if (sax->sax25_uid == 0) + return -EINVAL; + if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL) + return -ENOMEM; + + ax25_uid->uid = sax->sax25_uid; + ax25_uid->call = sax->sax25_call; - case SIOCAX25DELUID: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { - if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) - break; + write_lock(&ax25_uid_lock); + ax25_uid->next = ax25_uid_list; + ax25_uid_list = ax25_uid; + write_unlock(&ax25_uid_lock); + + return 0; + + case SIOCAX25DELUID: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + write_lock(&ax25_uid_lock); + for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { + if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { + break; } - if (ax25_uid == NULL) - return -ENOENT; - save_flags(flags); cli(); - if ((s = ax25_uid_list) == ax25_uid) { - ax25_uid_list = s->next; - restore_flags(flags); + } + if (ax25_uid == NULL) { + write_unlock(&ax25_uid_lock); + return -ENOENT; + } + if ((s = ax25_uid_list) == ax25_uid) { + ax25_uid_list = s->next; + write_unlock(&ax25_uid_lock); + kfree(ax25_uid); + return 0; + } + while (s != NULL && s->next != NULL) { + if (s->next == ax25_uid) { + s->next = ax25_uid->next; + write_unlock(&ax25_uid_lock); kfree(ax25_uid); return 0; } - while (s != NULL && s->next != NULL) { - if (s->next == ax25_uid) { - s->next = ax25_uid->next; - restore_flags(flags); - kfree(ax25_uid); - return 0; - } - s = s->next; - } - restore_flags(flags); - return -ENOENT; + s = s->next; + } + write_unlock(&ax25_uid_lock); - default: - return -EINVAL; + return -ENOENT; + + default: + return -EINVAL; } return -EINVAL; /*NOTREACHED */ @@ -134,8 +148,7 @@ off_t pos = 0; off_t begin = 0; - cli(); - + read_lock(&ax25_uid_lock); len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy); for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { @@ -151,13 +164,13 @@ if (pos > offset + length) break; } - - sti(); + read_unlock(&ax25_uid_lock); *start = buffer + (offset - begin); len -= offset - begin; - if (len > length) len = length; + if (len > length) + len = length; return len; } @@ -167,12 +180,16 @@ */ void __exit ax25_uid_free(void) { - ax25_uid_assoc *s, *ax25_uid = ax25_uid_list; + ax25_uid_assoc *s, *ax25_uid; + write_lock(&ax25_uid_lock); + ax25_uid = ax25_uid_list; while (ax25_uid != NULL) { s = ax25_uid; ax25_uid = ax25_uid->next; kfree(s); } + ax25_uid_list = NULL; + write_unlock(&ax25_uid_lock); } diff -Nru a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c --- a/net/ax25/sysctl_net_ax25.c Fri Sep 20 08:20:44 2002 +++ b/net/ax25/sysctl_net_ax25.c Fri Sep 20 08:20:44 2002 @@ -1,13 +1,15 @@ -/* -*- linux-c -*- - * sysctl_net_ax25.c: sysctl interface to net AX.25 subsystem. +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * Begun April 1, 1996, Mike Shaver. - * Added /proc/sys/net/ax25 directory entry (empty =) ). [MS] + * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com) */ - #include #include #include +#include #include static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1}; @@ -105,6 +107,7 @@ ax25_dev *ax25_dev; int n, k; + spin_lock_bh(&ax25_dev_lock); for (ax25_table_size = sizeof(ctl_table), ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) ax25_table_size += sizeof(ctl_table); @@ -119,6 +122,7 @@ while (n--) kfree(ax25_table[n].child); kfree(ax25_table); + spin_unlock_bh(&ax25_dev_lock); return; } memcpy(child, ax25_param_table, sizeof(ax25_param_table)); @@ -128,7 +132,7 @@ ax25_table[n].mode = 0555; #ifndef CONFIG_AX25_DAMA_SLAVE - /* + /* * We do not wish to have a representation of this parameter * in /proc/sys/ when configured *not* to include the * AX.25 DAMA slave code, do we? @@ -144,6 +148,7 @@ n++; } + spin_unlock_bh(&ax25_dev_lock); ax25_dir_table[0].child = ax25_table; diff -Nru a/net/bridge/Makefile b/net/bridge/Makefile --- a/net/bridge/Makefile Fri Sep 20 08:20:48 2002 +++ b/net/bridge/Makefile Fri Sep 20 08:20:48 2002 @@ -2,10 +2,13 @@ # Makefile for the IEEE 802.1d ethernet bridging layer. # +export-objs := br.o + obj-$(CONFIG_BRIDGE) += bridge.o bridge-objs := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \ br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \ br_stp_if.o br_stp_timer.o +obj-$(CONFIG_BRIDGE_NF_EBTABLES) += netfilter/ include $(TOPDIR)/Rules.make diff -Nru a/net/bridge/br.c b/net/bridge/br.c --- a/net/bridge/br.c Fri Sep 20 08:20:43 2002 +++ b/net/bridge/br.c Fri Sep 20 08:20:43 2002 @@ -28,6 +28,8 @@ #include "../atm/lec.h" #endif +int (*br_should_route_hook) (struct sk_buff **pskb) = NULL; + void br_dec_use_count() { MOD_DEC_USE_COUNT; @@ -73,6 +75,8 @@ br_fdb_put_hook = NULL; #endif } + +EXPORT_SYMBOL(br_should_route_hook); module_init(br_init) module_exit(br_deinit) diff -Nru a/net/bridge/br_forward.c b/net/bridge/br_forward.c --- a/net/bridge/br_forward.c Fri Sep 20 08:20:44 2002 +++ b/net/bridge/br_forward.c Fri Sep 20 08:20:44 2002 @@ -49,6 +49,9 @@ static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb) { skb->dev = to->dev; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, __br_forward_finish); } diff -Nru a/net/bridge/br_input.c b/net/bridge/br_input.c --- a/net/bridge/br_input.c Fri Sep 20 08:20:43 2002 +++ b/net/bridge/br_input.c Fri Sep 20 08:20:43 2002 @@ -24,6 +24,9 @@ static int br_pass_frame_up_finish(struct sk_buff *skb) { +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif netif_rx(skb); return 0; @@ -112,7 +115,7 @@ return 0; } -void br_handle_frame(struct sk_buff *skb) +int br_handle_frame(struct sk_buff *skb) { struct net_bridge *br; unsigned char *dest; @@ -146,25 +149,29 @@ goto handle_special_frame; if (p->state == BR_STATE_FORWARDING) { + if (br_should_route_hook && br_should_route_hook(&skb)) + return -1; + NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, br_handle_frame_finish); read_unlock(&br->lock); - return; + return 0; } err: read_unlock(&br->lock); err_nolock: kfree_skb(skb); - return; + return 0; handle_special_frame: if (!dest[5]) { br_stp_handle_bpdu(skb); read_unlock(&br->lock); - return; + return 0; } kfree_skb(skb); read_unlock(&br->lock); + return 0; } diff -Nru a/net/bridge/br_private.h b/net/bridge/br_private.h --- a/net/bridge/br_private.h Fri Sep 20 08:20:43 2002 +++ b/net/bridge/br_private.h Fri Sep 20 08:20:43 2002 @@ -166,7 +166,7 @@ int *ifindices); /* br_input.c */ -extern void br_handle_frame(struct sk_buff *skb); +extern int br_handle_frame(struct sk_buff *skb); /* br_ioctl.c */ extern void br_call_ioctl_atomic(void (*fn)(void)); diff -Nru a/net/bridge/netfilter/Config.help b/net/bridge/netfilter/Config.help --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/Config.help Fri Sep 20 08:20:49 2002 @@ -0,0 +1,105 @@ +CONFIG_BRIDGE_EBT + ebtables is an extendable frame filtering system for the Linux + Ethernet bridge. Its usage and implementation is very similar to that + of iptables. + The difference is that ebtables works on the Link Layer, while iptables + works on the Network Layer. ebtables can filter all frames that come + into contact with a logical bridge device. + Apart from filtering, ebtables also allows MAC source and destination + alterations (we call it MAC SNAT and MAC DNAT) and also provides + functionality for making Linux a brouter. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_T_FILTER + The ebtables filter table is used to define frame filtering rules at + local input, forwarding and local output. See the man page for + ebtables(8). + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_T_NAT + The ebtables nat table is used to define rules that alter the MAC + source address (MAC SNAT) or the MAC destination address (MAC DNAT). + See the man page for ebtables(8). + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_BROUTE + The ebtables broute table is used to define rules that decide between + bridging and routing frames, giving Linux the functionality of a + brouter. See the man page for ebtables(8) and examples on the ebtables + website. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_LOG + This option adds the log target, that you can use in any rule in + any ebtables table. It records the frame header to the syslog. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_IPF + This option adds the IP match, which allows basic IP header field + filtering. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_ARPF + This option adds the ARP match, which allows ARP and RARP header field + filtering. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_VLANF + This option adds the 802.1Q vlan match, which allows the filtering of + 802.1Q vlan fields. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_MARKF + This option adds the mark match, which allows matching frames based on + the 'nfmark' value in the frame. This can be set by the mark target. + This value is the same as the one used in the iptables mark match and + target. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_SNAT + This option adds the MAC SNAT target, which allows altering the MAC + source address of frames. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_DNAT + This option adds the MAC DNAT target, which allows altering the MAC + destination address of frames. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_REDIRECT + This option adds the MAC redirect target, which allows altering the MAC + destination address of a frame to that of the device it arrived on. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + +CONFIG_BRIDGE_EBT_MARK_T + This option adds the mark target, which allows marking frames by + setting the 'nfmark' value in the frame. + This value is the same as the one used in the iptables mark match and + target. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. diff -Nru a/net/bridge/netfilter/Config.in b/net/bridge/netfilter/Config.in --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/Config.in Fri Sep 20 08:20:49 2002 @@ -0,0 +1,17 @@ +# +# Bridge netfilter configuration +# +dep_tristate ' Bridge: ebtables' CONFIG_BRIDGE_NF_EBTABLES $CONFIG_BRIDGE +dep_tristate ' ebt: filter table support' CONFIG_BRIDGE_EBT_T_FILTER $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: nat table support' CONFIG_BRIDGE_EBT_T_NAT $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: broute table support' CONFIG_BRIDGE_EBT_BROUTE $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: log support' CONFIG_BRIDGE_EBT_LOG $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: IP filter support' CONFIG_BRIDGE_EBT_IPF $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: ARP filter support' CONFIG_BRIDGE_EBT_ARPF $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: 802.1Q VLAN filter support (EXPERIMENTAL)' CONFIG_BRIDGE_EBT_VLANF $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: mark filter support' CONFIG_BRIDGE_EBT_MARKF $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: snat target support' CONFIG_BRIDGE_EBT_SNAT $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: dnat target support' CONFIG_BRIDGE_EBT_DNAT $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: redirect target support' CONFIG_BRIDGE_EBT_REDIRECT $CONFIG_BRIDGE_NF_EBTABLES +dep_tristate ' ebt: mark target support' CONFIG_BRIDGE_EBT_MARK_T $CONFIG_BRIDGE_NF_EBTABLES + diff -Nru a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/Makefile Fri Sep 20 08:20:49 2002 @@ -0,0 +1,20 @@ +# +# Makefile for the netfilter modules for Link Layer filtering on a bridge. +# + +export-objs := ebtables.o + +obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o +obj-$(CONFIG_BRIDGE_EBT_T_FILTER) += ebtable_filter.o +obj-$(CONFIG_BRIDGE_EBT_T_NAT) += ebtable_nat.o +obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o +obj-$(CONFIG_BRIDGE_EBT_IPF) += ebt_ip.o +obj-$(CONFIG_BRIDGE_EBT_ARPF) += ebt_arp.o +obj-$(CONFIG_BRIDGE_EBT_VLANF) += ebt_vlan.o +obj-$(CONFIG_BRIDGE_EBT_MARKF) += ebt_mark_m.o +obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o +obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o +obj-$(CONFIG_BRIDGE_EBT_DNAT) += ebt_dnat.o +obj-$(CONFIG_BRIDGE_EBT_REDIRECT) += ebt_redirect.o +obj-$(CONFIG_BRIDGE_EBT_MARK_T) += ebt_mark.o +include $(TOPDIR)/Rules.make diff -Nru a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebt_arp.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,101 @@ +/* + * ebt_arp + * + * Authors: + * Bart De Schuymer + * Tim Gardner + * + * April, 2002 + * + */ + +#include +#include +#include +#include + +static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *data, unsigned int datalen) +{ + struct ebt_arp_info *info = (struct ebt_arp_info *)data; + + if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode != + ((*skb).nh.arph)->ar_op, EBT_ARP_OPCODE)) + return EBT_NOMATCH; + if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype != + ((*skb).nh.arph)->ar_hrd, EBT_ARP_HTYPE)) + return EBT_NOMATCH; + if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype != + ((*skb).nh.arph)->ar_pro, EBT_ARP_PTYPE)) + return EBT_NOMATCH; + + if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) + { + uint32_t arp_len = sizeof(struct arphdr) + + (2 * (((*skb).nh.arph)->ar_hln)) + + (2 * (((*skb).nh.arph)->ar_pln)); + uint32_t dst; + uint32_t src; + + // Make sure the packet is long enough. + if ((((*skb).nh.raw) + arp_len) > (*skb).tail) + return EBT_NOMATCH; + // IPv4 addresses are always 4 bytes. + if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t)) + return EBT_NOMATCH; + + if (info->bitmask & EBT_ARP_SRC_IP) { + memcpy(&src, ((*skb).nh.raw) + sizeof(struct arphdr) + + ((*skb).nh.arph)->ar_hln, sizeof(uint32_t)); + if (FWINV(info->saddr != (src & info->smsk), + EBT_ARP_SRC_IP)) + return EBT_NOMATCH; + } + + if (info->bitmask & EBT_ARP_DST_IP) { + memcpy(&dst, ((*skb).nh.raw)+sizeof(struct arphdr) + + (2*(((*skb).nh.arph)->ar_hln)) + + (((*skb).nh.arph)->ar_pln), sizeof(uint32_t)); + if (FWINV(info->daddr != (dst & info->dmsk), + EBT_ARP_DST_IP)) + return EBT_NOMATCH; + } + } + return EBT_MATCH; +} + +static int ebt_arp_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_arp_info *info = (struct ebt_arp_info *)data; + + if (datalen != sizeof(struct ebt_arp_info)) + return -EINVAL; + if ((e->ethproto != __constant_htons(ETH_P_ARP) && + e->ethproto != __constant_htons(ETH_P_RARP)) || + e->invflags & EBT_IPROTO) + return -EINVAL; + if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK) + return -EINVAL; + return 0; +} + +static struct ebt_match filter_arp = +{ + {NULL, NULL}, EBT_ARP_MATCH, ebt_filter_arp, ebt_arp_check, NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_match(&filter_arp); +} + +static void __exit fini(void) +{ + ebt_unregister_match(&filter_arp); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebt_dnat.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,64 @@ +/* + * ebt_dnat + * + * Authors: + * Bart De Schuymer + * + * June, 2002 + * + */ + +#include +#include +#include +#include + +static int ebt_target_dnat(struct sk_buff **pskb, unsigned int hooknr, + const struct net_device *in, const struct net_device *out, + const void *data, unsigned int datalen) +{ + struct ebt_nat_info *info = (struct ebt_nat_info *)data; + + memcpy(((**pskb).mac.ethernet)->h_dest, info->mac, + ETH_ALEN * sizeof(unsigned char)); + return info->target; +} + +static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_nat_info *info = (struct ebt_nat_info *)data; + + if (BASE_CHAIN && info->target == EBT_RETURN) + return -EINVAL; + CLEAR_BASE_CHAIN_BIT; + if ( (strcmp(tablename, "nat") || + (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) && + (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) + return -EINVAL; + if (datalen != sizeof(struct ebt_nat_info)) + return -EINVAL; + if (INVALID_TARGET) + return -EINVAL; + return 0; +} + +static struct ebt_target dnat = +{ + {NULL, NULL}, EBT_DNAT_TARGET, ebt_target_dnat, ebt_target_dnat_check, + NULL, THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_target(&dnat); +} + +static void __exit fini(void) +{ + ebt_unregister_target(&dnat); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebt_ip.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,72 @@ +/* + * ebt_ip + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + */ + +#include +#include +#include +#include + +static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *data, + unsigned int datalen) +{ + struct ebt_ip_info *info = (struct ebt_ip_info *)data; + + if (info->bitmask & EBT_IP_TOS && + FWINV(info->tos != ((*skb).nh.iph)->tos, EBT_IP_TOS)) + return EBT_NOMATCH; + if (info->bitmask & EBT_IP_PROTO && FWINV(info->protocol != + ((*skb).nh.iph)->protocol, EBT_IP_PROTO)) + return EBT_NOMATCH; + if (info->bitmask & EBT_IP_SOURCE && + FWINV((((*skb).nh.iph)->saddr & info->smsk) != + info->saddr, EBT_IP_SOURCE)) + return EBT_NOMATCH; + if ((info->bitmask & EBT_IP_DEST) && + FWINV((((*skb).nh.iph)->daddr & info->dmsk) != + info->daddr, EBT_IP_DEST)) + return EBT_NOMATCH; + return EBT_MATCH; +} + +static int ebt_ip_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_ip_info *info = (struct ebt_ip_info *)data; + + if (datalen != sizeof(struct ebt_ip_info)) + return -EINVAL; + if (e->ethproto != __constant_htons(ETH_P_IP) || + e->invflags & EBT_IPROTO) + return -EINVAL; + if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK) + return -EINVAL; + return 0; +} + +static struct ebt_match filter_ip = +{ + {NULL, NULL}, EBT_IP_MATCH, ebt_filter_ip, ebt_ip_check, NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_match(&filter_ip); +} + +static void __exit fini(void) +{ + ebt_unregister_match(&filter_ip); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebt_log.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,99 @@ +/* + * ebt_log + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + */ + +#include +#include +#include +#include +#include +#include + +static spinlock_t ebt_log_lock = SPIN_LOCK_UNLOCKED; + +static int ebt_log_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_log_info *info = (struct ebt_log_info *)data; + + if (datalen != sizeof(struct ebt_log_info)) + return -EINVAL; + if (info->bitmask & ~EBT_LOG_MASK) + return -EINVAL; + if (info->loglevel >= 8) + return -EINVAL; + info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0'; + return 0; +} + +static void ebt_log(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *data, unsigned int datalen) +{ + struct ebt_log_info *info = (struct ebt_log_info *)data; + char level_string[4] = "< >"; + level_string[1] = '0' + info->loglevel; + + spin_lock_bh(&ebt_log_lock); + printk(level_string); + printk("%s IN=%s OUT=%s ", info->prefix, in ? in->name : "", + out ? out->name : ""); + + if (skb->dev->hard_header_len) { + int i; + unsigned char *p = (skb->mac.ethernet)->h_source; + + printk("MAC source = "); + for (i = 0; i < ETH_ALEN; i++,p++) + printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':'); + printk("MAC dest = "); + p = (skb->mac.ethernet)->h_dest; + for (i = 0; i < ETH_ALEN; i++,p++) + printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':'); + } + printk("proto = 0x%04x", ntohs(((*skb).mac.ethernet)->h_proto)); + + if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto == + htons(ETH_P_IP)){ + struct iphdr *iph = skb->nh.iph; + printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,", + NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); + printk(" IP tos=0x%02X, IP proto=%d", iph->tos, iph->protocol); + } + + if ((info->bitmask & EBT_LOG_ARP) && + ((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) || + (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) { + struct arphdr * arph = skb->nh.arph; + printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d", + ntohs(arph->ar_hrd), ntohs(arph->ar_pro), + ntohs(arph->ar_op)); + } + printk("\n"); + spin_unlock_bh(&ebt_log_lock); +} + +struct ebt_watcher log = +{ + {NULL, NULL}, EBT_LOG_WATCHER, ebt_log, ebt_log_check, NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_watcher(&log); +} + +static void __exit fini(void) +{ + ebt_unregister_watcher(&log); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebt_mark.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,65 @@ +/* + * ebt_mark + * + * Authors: + * Bart De Schuymer + * + * July, 2002 + * + */ + +// The mark target can be used in any chain +// I believe adding a mangle table just for marking is total overkill +// Marking a frame doesn't really change anything in the frame anyway + +#include +#include +#include + +static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr, + const struct net_device *in, const struct net_device *out, + const void *data, unsigned int datalen) +{ + struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data; + + if ((*pskb)->nfmark != info->mark) { + (*pskb)->nfmark = info->mark; + (*pskb)->nfcache |= NFC_ALTERED; + } + return info->target; +} + +static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data; + + if (datalen != sizeof(struct ebt_mark_t_info)) + return -EINVAL; + if (BASE_CHAIN && info->target == EBT_RETURN) + return -EINVAL; + CLEAR_BASE_CHAIN_BIT; + if (INVALID_TARGET) + return -EINVAL; + return 0; +} + +static struct ebt_target mark_target = +{ + {NULL, NULL}, EBT_MARK_TARGET, ebt_target_mark, + ebt_target_mark_check, NULL, THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_target(&mark_target); +} + +static void __exit fini(void) +{ + ebt_unregister_target(&mark_target); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebt_mark_m.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,60 @@ +/* + * ebt_mark_m + * + * Authors: + * Bart De Schuymer + * + * July, 2002 + * + */ + +#include +#include +#include + +static int ebt_filter_mark(const struct sk_buff *skb, + const struct net_device *in, const struct net_device *out, const void *data, + unsigned int datalen) +{ + struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data; + + if (info->bitmask & EBT_MARK_OR) + return !(!!(skb->nfmark & info->mask) ^ info->invert); + return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert); +} + +static int ebt_mark_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data; + + if (datalen != sizeof(struct ebt_mark_m_info)) + return -EINVAL; + if (info->bitmask & ~EBT_MARK_MASK) + return -EINVAL; + if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND)) + return -EINVAL; + if (!info->bitmask) + return -EINVAL; + return 0; +} + +static struct ebt_match filter_mark = +{ + {NULL, NULL}, EBT_MARK_MATCH, ebt_filter_mark, ebt_mark_check, NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_match(&filter_mark); +} + +static void __exit fini(void) +{ + ebt_unregister_match(&filter_mark); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebt_redirect.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,70 @@ +/* + * ebt_redirect + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + */ + +#include +#include +#include +#include +#include "../br_private.h" + +static int ebt_target_redirect(struct sk_buff **pskb, unsigned int hooknr, + const struct net_device *in, const struct net_device *out, + const void *data, unsigned int datalen) +{ + struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; + + if (hooknr != NF_BR_BROUTING) + memcpy((**pskb).mac.ethernet->h_dest, + in->br_port->br->dev.dev_addr, ETH_ALEN); + else { + memcpy((**pskb).mac.ethernet->h_dest, + in->dev_addr, ETH_ALEN); + (*pskb)->pkt_type = PACKET_HOST; + } + return info->target; +} + +static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; + + if (datalen != sizeof(struct ebt_redirect_info)) + return -EINVAL; + if (BASE_CHAIN && info->target == EBT_RETURN) + return -EINVAL; + CLEAR_BASE_CHAIN_BIT; + if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) && + (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) + return -EINVAL; + if (INVALID_TARGET) + return -EINVAL; + return 0; +} + +static struct ebt_target redirect_target = +{ + {NULL, NULL}, EBT_REDIRECT_TARGET, ebt_target_redirect, + ebt_target_redirect_check, NULL, THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_target(&redirect_target); +} + +static void __exit fini(void) +{ + ebt_unregister_target(&redirect_target); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebt_snat.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,63 @@ +/* + * ebt_snat + * + * Authors: + * Bart De Schuymer + * + * June, 2002 + * + */ + +#include +#include +#include + +static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr, + const struct net_device *in, const struct net_device *out, + const void *data, unsigned int datalen) +{ + struct ebt_nat_info *info = (struct ebt_nat_info *) data; + + memcpy(((**pskb).mac.ethernet)->h_source, info->mac, + ETH_ALEN * sizeof(unsigned char)); + return info->target; +} + +static int ebt_target_snat_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_nat_info *info = (struct ebt_nat_info *) data; + + if (datalen != sizeof(struct ebt_nat_info)) + return -EINVAL; + if (BASE_CHAIN && info->target == EBT_RETURN) + return -EINVAL; + CLEAR_BASE_CHAIN_BIT; + if (strcmp(tablename, "nat")) + return -EINVAL; + if (hookmask & ~(1 << NF_BR_POST_ROUTING)) + return -EINVAL; + if (INVALID_TARGET) + return -EINVAL; + return 0; +} + +static struct ebt_target snat = +{ + {NULL, NULL}, EBT_SNAT_TARGET, ebt_target_snat, ebt_target_snat_check, + NULL, THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_target(&snat); +} + +static void __exit fini(void) +{ + ebt_unregister_target(&snat); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebt_vlan.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,316 @@ +/* + * Description: EBTables 802.1Q match extension kernelspace module. + * Authors: Nick Fedchik + * Bart De Schuymer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +static unsigned char debug; +#define MODULE_VERSION "0.4 (" __DATE__ " " __TIME__ ")" + +MODULE_PARM (debug, "0-1b"); +MODULE_PARM_DESC (debug, "debug=1 is turn on debug messages"); +MODULE_AUTHOR ("Nick Fedchik "); +MODULE_DESCRIPTION ("802.1Q match module (ebtables extension), v" + MODULE_VERSION); +MODULE_LICENSE ("GPL"); + + +#define DEBUG_MSG(...) if (debug) printk (KERN_DEBUG __FILE__ ":" __VA_ARGS__) +#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : "" +#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_ +#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_ +#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return 1; + +/* + * Function description: ebt_filter_vlan() is main engine for + * checking passed 802.1Q frame according to + * the passed extension parameters (in the *data buffer) + * ebt_filter_vlan() is called after successfull check the rule params + * by ebt_check_vlan() function. + * Parameters: + * const struct sk_buff *skb - pointer to passed ethernet frame buffer + * const void *data - pointer to passed extension parameters + * unsigned int datalen - length of passed *data buffer + * const struct net_device *in - + * const struct net_device *out - + * const struct ebt_counter *c - + * Returned values: + * 0 - ok (all rule params matched) + * 1 - miss (rule params not acceptable to the parsed frame) + */ +static int +ebt_filter_vlan (const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *data, + unsigned int datalen) +{ + struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; /* userspace data */ + struct vlan_ethhdr *frame = (struct vlan_ethhdr *) skb->mac.raw; /* Passed tagged frame */ + + unsigned short TCI; /* Whole TCI, given from parsed frame */ + unsigned short id; /* VLAN ID, given from frame TCI */ + unsigned char prio; /* user_priority, given from frame TCI */ + unsigned short encap; /* VLAN encapsulated Type/Length field, given from orig frame */ + + /* + * Tag Control Information (TCI) consists of the following elements: + * - User_priority. This field allows the tagged frame to carry user_priority + * information across Bridged LANs in which individual LAN segments may be unable to signal + * priority information (e.g., 802.3/Ethernet segments). + * The user_priority field is three bits in length, + * interpreted as a binary number. The user_priority is therefore + * capable of representing eight priority levels, 0 through 7. + * The use and interpretation of this field is defined in ISO/IEC 15802-3. + * - Canonical Format Indicator (CFI). This field is used, + * in 802.3/Ethernet, to signal the presence or absence + * of a RIF field, and, in combination with the Non-canonical Format Indicator (NCFI) carried + * in the RIF, to signal the bit order of address information carried in the encapsulated + * frame. The Canonical Format Indicator (CFI) is a single bit flag value. + * - VLAN Identifier (VID). This field uniquely identifies the VLAN to + * which the frame belongs. The twelve-bit VLAN Identifier (VID) field + * uniquely identify the VLAN to which the frame belongs. + * The VID is encoded as an unsigned binary number. + */ + TCI = ntohs (frame->h_vlan_TCI); + id = TCI & 0xFFF; + prio = TCI >> 13; + encap = frame->h_vlan_encapsulated_proto; + + /* + * First step is to check is null VLAN ID present + * in the parsed frame + */ + if (!(id)) { + /* + * Checking VLAN Identifier (VID) + */ + if (GET_BITMASK (EBT_VLAN_ID)) { /* Is VLAN ID parsed? */ + EXIT_ON_MISMATCH (id, EBT_VLAN_ID); + DEBUG_MSG + ("matched rule id=%s%d for frame id=%d\n", + INV_FLAG (EBT_VLAN_ID), info->id, id); + } + } else { + /* + * Checking user_priority + */ + if (GET_BITMASK (EBT_VLAN_PRIO)) { /* Is VLAN user_priority parsed? */ + EXIT_ON_MISMATCH (prio, EBT_VLAN_PRIO); + DEBUG_MSG + ("matched rule prio=%s%d for frame prio=%d\n", + INV_FLAG (EBT_VLAN_PRIO), info->prio, + prio); + } + } + /* + * Checking Encapsulated Proto (Length/Type) field + */ + if (GET_BITMASK (EBT_VLAN_ENCAP)) { /* Is VLAN Encap parsed? */ + EXIT_ON_MISMATCH (encap, EBT_VLAN_ENCAP); + DEBUG_MSG ("matched encap=%s%2.4X for frame encap=%2.4X\n", + INV_FLAG (EBT_VLAN_ENCAP), + ntohs (info->encap), ntohs (encap)); + } + /* + * All possible extension parameters was parsed. + * If rule never returned by missmatch, then all ok. + */ + return 0; +} + +/* + * Function description: ebt_vlan_check() is called when userspace + * delivers the table to the kernel, + * and to check that userspace doesn't give a bad table. + * Parameters: + * const char *tablename - table name string + * unsigned int hooknr - hook number + * const struct ebt_entry *e - ebtables entry basic set + * const void *data - pointer to passed extension parameters + * unsigned int datalen - length of passed *data buffer + * Returned values: + * 0 - ok (all delivered rule params are correct) + * 1 - miss (rule params is out of range, invalid, incompatible, etc.) + */ +static int +ebt_check_vlan (const char *tablename, + unsigned int hooknr, + const struct ebt_entry *e, void *data, + unsigned int datalen) +{ + struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; + + /* + * Parameters buffer overflow check + */ + if (datalen != sizeof (struct ebt_vlan_info)) { + DEBUG_MSG + ("params size %d is not eq to ebt_vlan_info (%d)\n", + datalen, sizeof (struct ebt_vlan_info)); + return -EINVAL; + } + + /* + * Is it 802.1Q frame checked? + */ + if (e->ethproto != __constant_htons (ETH_P_8021Q)) { + DEBUG_MSG ("passed entry proto %2.4X is not 802.1Q (8100)\n", + (unsigned short) ntohs (e->ethproto)); + return -EINVAL; + } + + /* + * Check for bitmask range + * True if even one bit is out of mask + */ + if (info->bitmask & ~EBT_VLAN_MASK) { + DEBUG_MSG ("bitmask %2X is out of mask (%2X)\n", + info->bitmask, EBT_VLAN_MASK); + return -EINVAL; + } + + /* + * Check for inversion flags range + */ + if (info->invflags & ~EBT_VLAN_MASK) { + DEBUG_MSG ("inversion flags %2X is out of mask (%2X)\n", + info->invflags, EBT_VLAN_MASK); + return -EINVAL; + } + + /* + * Reserved VLAN ID (VID) values + * ----------------------------- + * 0 - The null VLAN ID. Indicates that the tag header contains only user_priority information; + * no VLAN identifier is present in the frame. This VID value shall not be + * configured as a PVID, configured in any Filtering Database entry, or used in any + * Management operation. + * + * 1 - The default Port VID (PVID) value used for classifying frames on ingress through a Bridge + * Port. The PVID value can be changed by management on a per-Port basis. + * + * 0x0FFF - Reserved for implementation use. This VID value shall not be configured as a + * PVID or transmitted in a tag header. + * + * The remaining values of VID are available for general use as VLAN identifiers. + * A Bridge may implement the ability to support less than the full range of VID values; + * i.e., for a given implementation, + * an upper limit, N, is defined for the VID values supported, where N is less than or equal to 4094. + * All implementations shall support the use of all VID values in the range 0 through their defined maximum + * VID, N. + * + * For Linux, N = 4094. + */ + if (GET_BITMASK (EBT_VLAN_ID)) { /* when vlan-id param was spec-ed */ + if (!!info->id) { /* if id!=0 => check vid range */ + if (info->id > 4094) { /* check if id > than (0x0FFE) */ + DEBUG_MSG + ("vlan id %d is out of range (1-4094)\n", + info->id); + return -EINVAL; + } + /* + * Note: This is valid VLAN-tagged frame point. + * Any value of user_priority are acceptable, but could be ignored + * according to 802.1Q Std. + */ + } else { + /* + * if id=0 (null VLAN ID) => Check for user_priority range + */ + if (GET_BITMASK (EBT_VLAN_PRIO)) { + if ((unsigned char) info->prio > 7) { + DEBUG_MSG + ("prio %d is out of range (0-7)\n", + info->prio); + return -EINVAL; + } + } + /* + * Note2: This is valid priority-tagged frame point + * with null VID field. + */ + } + } else { /* VLAN Id not set */ + if (GET_BITMASK (EBT_VLAN_PRIO)) { /* But user_priority is set - abnormal! */ + info->id = 0; /* Set null VID (case for Priority-tagged frames) */ + SET_BITMASK (EBT_VLAN_ID); /* and set id flag */ + } + } + /* + * Check for encapsulated proto range - it is possible to be any value for u_short range. + * When relaying a tagged frame between 802.3/Ethernet MACs, + * a Bridge may adjust the padding field such that + * the minimum size of a transmitted tagged frame is 68 octets (7.2). + * if_ether.h: ETH_ZLEN 60 - Min. octets in frame sans FCS + */ + if (GET_BITMASK (EBT_VLAN_ENCAP)) { + if ((unsigned short) ntohs (info->encap) < ETH_ZLEN) { + DEBUG_MSG + ("encap packet length %d is less than minimal %d\n", + ntohs (info->encap), ETH_ZLEN); + return -EINVAL; + } + } + + /* + * Otherwise is all correct + */ + DEBUG_MSG ("802.1Q tagged frame checked (%s table, %d hook)\n", + tablename, hooknr); + return 0; +} + +static struct ebt_match filter_vlan = { + {NULL, NULL}, + EBT_VLAN_MATCH, + ebt_filter_vlan, + ebt_check_vlan, + NULL, + THIS_MODULE +}; + +/* + * Module initialization function. + * Called when module is loaded to kernelspace + */ +static int __init init (void) +{ + DEBUG_MSG ("ebtables 802.1Q extension module v" + MODULE_VERSION "\n"); + DEBUG_MSG ("module debug=%d\n", !!debug); + return ebt_register_match (&filter_vlan); +} + +/* + * Module "finalization" function + * Called when download module from kernelspace + */ +static void __exit fini (void) +{ + ebt_unregister_match (&filter_vlan); +} + +module_init (init); +module_exit (fini); diff -Nru a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebtable_broute.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,78 @@ +/* + * ebtable_broute + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + * This table lets you choose between routing and bridging for frames + * entering on a bridge enslaved nic. This table is traversed before any + * other ebtables table. See net/bridge/br_input.c. + */ + +#include +#include +#include +#include + +// EBT_ACCEPT means the frame will be bridged +// EBT_DROP means the frame will be routed +static struct ebt_entries initial_chain = + {0, "BROUTING", 0, EBT_ACCEPT, 0}; + +static struct ebt_replace initial_table = +{ + "broute", 1 << NF_BR_BROUTING, 0, sizeof(struct ebt_entries), + { [NF_BR_BROUTING]&initial_chain}, 0, NULL, (char *)&initial_chain +}; + +static int check(const struct ebt_table_info *info, unsigned int valid_hooks) +{ + if (valid_hooks & ~(1 << NF_BR_BROUTING)) + return -EINVAL; + return 0; +} + +static struct ebt_table broute_table = +{ + {NULL, NULL}, "broute", &initial_table, 1 << NF_BR_BROUTING, + RW_LOCK_UNLOCKED, check, NULL +}; + +static int ebt_broute(struct sk_buff **pskb) +{ + int ret; + + ret = ebt_do_table(NF_BR_BROUTING, pskb, (*pskb)->dev, NULL, + &broute_table); + if (ret == NF_DROP) + return 1; // route it + return 0; // bridge it +} + +static int __init init(void) +{ + int ret; + + ret = ebt_register_table(&broute_table); + if (ret < 0) + return ret; + br_write_lock_bh(BR_NETPROTO_LOCK); + // see br_input.c + br_should_route_hook = ebt_broute; + br_write_unlock_bh(BR_NETPROTO_LOCK); + return ret; +} + +static void __exit fini(void) +{ + br_write_lock_bh(BR_NETPROTO_LOCK); + br_should_route_hook = NULL; + br_write_unlock_bh(BR_NETPROTO_LOCK); + ebt_unregister_table(&broute_table); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebtable_filter.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,89 @@ +/* + * ebtable_filter + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + */ + +#include +#include + +#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \ + (1 << NF_BR_LOCAL_OUT)) + +static struct ebt_entries initial_chains[] = +{ + {0, "INPUT", 0, EBT_ACCEPT, 0}, + {0, "FORWARD", 0, EBT_ACCEPT, 0}, + {0, "OUTPUT", 0, EBT_ACCEPT, 0} +}; + +static struct ebt_replace initial_table = +{ + "filter", FILTER_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries), + { [NF_BR_LOCAL_IN]&initial_chains[0], [NF_BR_FORWARD]&initial_chains[1], + [NF_BR_LOCAL_OUT]&initial_chains[2] }, 0, NULL, (char *)initial_chains +}; + +static int check(const struct ebt_table_info *info, unsigned int valid_hooks) +{ + if (valid_hooks & ~FILTER_VALID_HOOKS) + return -EINVAL; + return 0; +} + +static struct ebt_table frame_filter = +{ + {NULL, NULL}, "filter", &initial_table, FILTER_VALID_HOOKS, + RW_LOCK_UNLOCKED, check, NULL +}; + +static unsigned int +ebt_hook (unsigned int hook, struct sk_buff **pskb, const struct net_device *in, + const struct net_device *out, int (*okfn)(struct sk_buff *)) +{ + return ebt_do_table(hook, pskb, in, out, &frame_filter); +} + +static struct nf_hook_ops ebt_ops_filter[] = { + { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_IN, + NF_BR_PRI_FILTER_BRIDGED}, + { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_FORWARD, + NF_BR_PRI_FILTER_BRIDGED}, + { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_OUT, + NF_BR_PRI_FILTER_OTHER} +}; + +static int __init init(void) +{ + int i, j, ret; + + ret = ebt_register_table(&frame_filter); + if (ret < 0) + return ret; + for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++) + if ((ret = nf_register_hook(&ebt_ops_filter[i])) < 0) + goto cleanup; + return ret; +cleanup: + for (j = 0; j < i; j++) + nf_unregister_hook(&ebt_ops_filter[j]); + ebt_unregister_table(&frame_filter); + return ret; +} + +static void __exit fini(void) +{ + int i; + + for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++) + nf_unregister_hook(&ebt_ops_filter[i]); + ebt_unregister_table(&frame_filter); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebtable_nat.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,95 @@ +/* + * ebtable_nat + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + */ + +#include +#include +#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \ + (1 << NF_BR_POST_ROUTING)) + +static struct ebt_entries initial_chains[] = +{ + {0, "PREROUTING", 0, EBT_ACCEPT, 0}, + {0, "OUTPUT", 0, EBT_ACCEPT, 0}, + {0, "POSTROUTING", 0, EBT_ACCEPT, 0} +}; + +static struct ebt_replace initial_table = +{ + "nat", NAT_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries), + { [NF_BR_PRE_ROUTING]&initial_chains[0], [NF_BR_LOCAL_OUT]&initial_chains[1], + [NF_BR_POST_ROUTING]&initial_chains[2] }, 0, NULL, (char *)initial_chains +}; + +static int check(const struct ebt_table_info *info, unsigned int valid_hooks) +{ + if (valid_hooks & ~NAT_VALID_HOOKS) + return -EINVAL; + return 0; +} + +static struct ebt_table frame_nat = +{ + {NULL, NULL}, "nat", &initial_table, NAT_VALID_HOOKS, + RW_LOCK_UNLOCKED, check, NULL +}; + +static unsigned int +ebt_nat_dst(unsigned int hook, struct sk_buff **pskb, const struct net_device *in + , const struct net_device *out, int (*okfn)(struct sk_buff *)) +{ + return ebt_do_table(hook, pskb, in, out, &frame_nat); +} + +static unsigned int +ebt_nat_src(unsigned int hook, struct sk_buff **pskb, const struct net_device *in + , const struct net_device *out, int (*okfn)(struct sk_buff *)) +{ + return ebt_do_table(hook, pskb, in, out, &frame_nat); +} + +static struct nf_hook_ops ebt_ops_nat[] = { + { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_LOCAL_OUT, + NF_BR_PRI_NAT_DST_OTHER}, + { { NULL, NULL }, ebt_nat_src, PF_BRIDGE, NF_BR_POST_ROUTING, + NF_BR_PRI_NAT_SRC}, + { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_PRE_ROUTING, + NF_BR_PRI_NAT_DST_BRIDGED}, +}; + +static int __init init(void) +{ + int i, ret, j; + + ret = ebt_register_table(&frame_nat); + if (ret < 0) + return ret; + for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++) + if ((ret = nf_register_hook(&ebt_ops_nat[i])) < 0) + goto cleanup; + return ret; +cleanup: + for (j = 0; j < i; j++) + nf_unregister_hook(&ebt_ops_nat[j]); + ebt_unregister_table(&frame_nat); + return ret; +} + +static void __exit fini(void) +{ + int i; + + for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++) + nf_unregister_hook(&ebt_ops_nat[i]); + ebt_unregister_table(&frame_nat); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bridge/netfilter/ebtables.c Fri Sep 20 08:20:49 2002 @@ -0,0 +1,1484 @@ +/* + * ebtables + * + * Author: + * Bart De Schuymer + * + * ebtables.c,v 2.0, July, 2002 + * + * This code is stongly inspired on the iptables code which is + * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +// used for print_string +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +// needed for logical [in,out]-dev filtering +#include "../br_private.h" + +// list_named_find +#define ASSERT_READ_LOCK(x) +#define ASSERT_WRITE_LOCK(x) +#include + +#if 0 // use this for remote debugging +// Copyright (C) 1998 by Ori Pomerantz +// Print the string to the appropriate tty, the one +// the current task uses +static void print_string(char *str) +{ + struct tty_struct *my_tty; + + /* The tty for the current task */ + my_tty = current->tty; + if (my_tty != NULL) { + (*(my_tty->driver).write)(my_tty, 0, str, strlen(str)); + (*(my_tty->driver).write)(my_tty, 0, "\015\012", 2); + } +} + +#define BUGPRINT(args) print_string(args); +#else +#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\ + "report to author: "format, ## args) +// #define BUGPRINT(format, args...) +#endif +#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\ + ": out of memory: "format, ## args) +// #define MEMPRINT(format, args...) + + + +// Each cpu has its own set of counters, so there is no need for write_lock in +// the softirq +// For reading or updating the counters, the user context needs to +// get a write_lock + +// The size of each set of counters is altered to get cache alignment +#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) +#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter))) +#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \ + COUNTER_OFFSET(n) * cpu)) + + + +static DECLARE_MUTEX(ebt_mutex); +static LIST_HEAD(ebt_tables); +static LIST_HEAD(ebt_targets); +static LIST_HEAD(ebt_matches); +static LIST_HEAD(ebt_watchers); + +static struct ebt_target ebt_standard_target = +{ {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL}; + +static inline int ebt_do_watcher (struct ebt_entry_watcher *w, + const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out) +{ + w->u.watcher->watcher(skb, in, out, w->data, + w->watcher_size); + // watchers don't give a verdict + return 0; +} + +static inline int ebt_do_match (struct ebt_entry_match *m, + const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out) +{ + return m->u.match->match(skb, in, out, m->data, + m->match_size); +} + +static inline int ebt_dev_check(char *entry, const struct net_device *device) +{ + if (*entry == '\0') + return 0; + if (!device) + return 1; + return !!strcmp(entry, device->name); +} + +#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg)) +// process standard matches +static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h, + const struct net_device *in, const struct net_device *out) +{ + int verdict, i; + + if (e->bitmask & EBT_802_3) { + if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO)) + return 1; + } else if (!(e->bitmask & EBT_NOPROTO) && + FWINV2(e->ethproto != h->h_proto, EBT_IPROTO)) + return 1; + + if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN)) + return 1; + if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) + return 1; + if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check( + e->logical_in, &in->br_port->br->dev), EBT_ILOGICALIN)) + return 1; + if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check( + e->logical_out, &out->br_port->br->dev), EBT_ILOGICALOUT)) + return 1; + + if (e->bitmask & EBT_SOURCEMAC) { + verdict = 0; + for (i = 0; i < 6; i++) + verdict |= (h->h_source[i] ^ e->sourcemac[i]) & + e->sourcemsk[i]; + if (FWINV2(verdict != 0, EBT_ISOURCE) ) + return 1; + } + if (e->bitmask & EBT_DESTMAC) { + verdict = 0; + for (i = 0; i < 6; i++) + verdict |= (h->h_dest[i] ^ e->destmac[i]) & + e->destmsk[i]; + if (FWINV2(verdict != 0, EBT_IDEST) ) + return 1; + } + return 0; +} + +// Do some firewalling +unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + struct ebt_table *table) +{ + int i, nentries; + struct ebt_entry *point; + struct ebt_counter *counter_base, *cb_base; + struct ebt_entry_target *t; + int verdict, sp = 0; + struct ebt_chainstack *cs; + struct ebt_entries *chaininfo; + char *base; + struct ebt_table_info *private = table->private; + + read_lock_bh(&table->lock); + cb_base = COUNTER_BASE(private->counters, private->nentries, + smp_processor_id()); + if (private->chainstack) + cs = private->chainstack[smp_processor_id()]; + else + cs = NULL; + chaininfo = private->hook_entry[hook]; + nentries = private->hook_entry[hook]->nentries; + point = (struct ebt_entry *)(private->hook_entry[hook]->data); + counter_base = cb_base + private->hook_entry[hook]->counter_offset; + // base for chain jumps + base = (char *)chaininfo; + i = 0; + while (i < nentries) { + if (ebt_basic_match(point, (**pskb).mac.ethernet, in, out)) + goto letscontinue; + + if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, out) != 0) + goto letscontinue; + + // increase counter + (*(counter_base + i)).pcnt++; + + // these should only watch: not modify, nor tell us + // what to do with the packet + EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, in, + out); + + t = (struct ebt_entry_target *) + (((char *)point) + point->target_offset); + // standard target + if (!t->u.target->target) + verdict = ((struct ebt_standard_target *)t)->verdict; + else + verdict = t->u.target->target(pskb, hook, + in, out, t->data, t->target_size); + if (verdict == EBT_ACCEPT) { + read_unlock_bh(&table->lock); + return NF_ACCEPT; + } + if (verdict == EBT_DROP) { + read_unlock_bh(&table->lock); + return NF_DROP; + } + if (verdict == EBT_RETURN) { +letsreturn: +#ifdef CONFIG_NETFILTER_DEBUG + if (sp == 0) { + BUGPRINT("RETURN on base chain"); + // act like this is EBT_CONTINUE + goto letscontinue; + } +#endif + sp--; + // put all the local variables right + i = cs[sp].n; + chaininfo = cs[sp].chaininfo; + nentries = chaininfo->nentries; + point = cs[sp].e; + counter_base = cb_base + + chaininfo->counter_offset; + continue; + } + if (verdict == EBT_CONTINUE) + goto letscontinue; +#ifdef CONFIG_NETFILTER_DEBUG + if (verdict < 0) { + BUGPRINT("bogus standard verdict\n"); + read_unlock_bh(&table->lock); + return NF_DROP; + } +#endif + // jump to a udc + cs[sp].n = i + 1; + cs[sp].chaininfo = chaininfo; + cs[sp].e = (struct ebt_entry *) + (((char *)point) + point->next_offset); + i = 0; + chaininfo = (struct ebt_entries *) (base + verdict); +#ifdef CONFIG_NETFILTER_DEBUG + if (chaininfo->distinguisher) { + BUGPRINT("jump to non-chain\n"); + read_unlock_bh(&table->lock); + return NF_DROP; + } +#endif + nentries = chaininfo->nentries; + point = (struct ebt_entry *)chaininfo->data; + counter_base = cb_base + chaininfo->counter_offset; + sp++; + continue; +letscontinue: + point = (struct ebt_entry *) + (((char *)point) + point->next_offset); + i++; + } + + // I actually like this :) + if (chaininfo->policy == EBT_RETURN) + goto letsreturn; + if (chaininfo->policy == EBT_ACCEPT) { + read_unlock_bh(&table->lock); + return NF_ACCEPT; + } + read_unlock_bh(&table->lock); + return NF_DROP; +} + +// If it succeeds, returns element and locks mutex +static inline void * +find_inlist_lock_noload(struct list_head *head, const char *name, int *error, + struct semaphore *mutex) +{ + void *ret; + + *error = down_interruptible(mutex); + if (*error != 0) + return NULL; + + ret = list_named_find(head, name); + if (!ret) { + *error = -ENOENT; + up(mutex); + } + return ret; +} + +#ifndef CONFIG_KMOD +#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m)) +#else +static void * +find_inlist_lock(struct list_head *head, const char *name, const char *prefix, + int *error, struct semaphore *mutex) +{ + void *ret; + + ret = find_inlist_lock_noload(head, name, error, mutex); + if (!ret) { + char modulename[EBT_FUNCTION_MAXNAMELEN + strlen(prefix) + 1]; + strcpy(modulename, prefix); + strcat(modulename, name); + request_module(modulename); + ret = find_inlist_lock_noload(head, name, error, mutex); + } + return ret; +} +#endif + +static inline struct ebt_table * +find_table_lock(const char *name, int *error, struct semaphore *mutex) +{ + return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex); +} + +static inline struct ebt_match * +find_match_lock(const char *name, int *error, struct semaphore *mutex) +{ + return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex); +} + +static inline struct ebt_watcher * +find_watcher_lock(const char *name, int *error, struct semaphore *mutex) +{ + return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex); +} + +static inline struct ebt_target * +find_target_lock(const char *name, int *error, struct semaphore *mutex) +{ + return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex); +} + +static inline int +ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e, + const char *name, unsigned int hookmask, unsigned int *cnt) +{ + struct ebt_match *match; + int ret; + + if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) > + ((char *)e) + e->watchers_offset) + return -EINVAL; + match = find_match_lock(m->u.name, &ret, &ebt_mutex); + if (!match) + return ret; + m->u.match = match; + if (match->me) + __MOD_INC_USE_COUNT(match->me); + up(&ebt_mutex); + if (match->check && + match->check(name, hookmask, e, m->data, m->match_size) != 0) { + BUGPRINT("match->check failed\n"); + if (match->me) + __MOD_DEC_USE_COUNT(match->me); + return -EINVAL; + } + (*cnt)++; + return 0; +} + +static inline int +ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e, + const char *name, unsigned int hookmask, unsigned int *cnt) +{ + struct ebt_watcher *watcher; + int ret; + + if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) > + ((char *)e) + e->target_offset) + return -EINVAL; + watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex); + if (!watcher) + return ret; + w->u.watcher = watcher; + if (watcher->me) + __MOD_INC_USE_COUNT(watcher->me); + up(&ebt_mutex); + if (watcher->check && + watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) { + BUGPRINT("watcher->check failed\n"); + if (watcher->me) + __MOD_DEC_USE_COUNT(watcher->me); + return -EINVAL; + } + (*cnt)++; + return 0; +} + +// this one is very careful, as it is the first function +// to parse the userspace data +static inline int +ebt_check_entry_size_and_hooks(struct ebt_entry *e, + struct ebt_table_info *newinfo, char *base, char *limit, + struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt, + unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks) +{ + int i; + + for (i = 0; i < NF_BR_NUMHOOKS; i++) { + if ((valid_hooks & (1 << i)) == 0) + continue; + if ( (char *)hook_entries[i] - base == + (char *)e - newinfo->entries) + break; + } + // beginning of a new chain + // if i == NF_BR_NUMHOOKS it must be a user defined chain + if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) { + if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) != 0) { + // we make userspace set this right, + // so there is no misunderstanding + BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set " + "in distinguisher\n"); + return -EINVAL; + } + // this checks if the previous chain has as many entries + // as it said it has + if (*n != *cnt) { + BUGPRINT("nentries does not equal the nr of entries " + "in the chain\n"); + return -EINVAL; + } + // before we look at the struct, be sure it is not too big + if ((char *)hook_entries[i] + sizeof(struct ebt_entries) + > limit) { + BUGPRINT("entries_size too small\n"); + return -EINVAL; + } + if (((struct ebt_entries *)e)->policy != EBT_DROP && + ((struct ebt_entries *)e)->policy != EBT_ACCEPT) { + // only RETURN from udc + if (i != NF_BR_NUMHOOKS || + ((struct ebt_entries *)e)->policy != EBT_RETURN) { + BUGPRINT("bad policy\n"); + return -EINVAL; + } + } + if (i == NF_BR_NUMHOOKS) // it's a user defined chain + (*udc_cnt)++; + else + newinfo->hook_entry[i] = (struct ebt_entries *)e; + if (((struct ebt_entries *)e)->counter_offset != *totalcnt) { + BUGPRINT("counter_offset != totalcnt"); + return -EINVAL; + } + *n = ((struct ebt_entries *)e)->nentries; + *cnt = 0; + return 0; + } + // a plain old entry, heh + if (sizeof(struct ebt_entry) > e->watchers_offset || + e->watchers_offset > e->target_offset || + e->target_offset >= e->next_offset) { + BUGPRINT("entry offsets not in right order\n"); + return -EINVAL; + } + // this is not checked anywhere else + if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) { + BUGPRINT("target size too small\n"); + return -EINVAL; + } + + (*cnt)++; + (*totalcnt)++; + return 0; +} + +struct ebt_cl_stack +{ + struct ebt_chainstack cs; + int from; + unsigned int hookmask; +}; + +// we need these positions to check that the jumps to a different part of the +// entries is a jump to the beginning of a new chain. +static inline int +ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo, + struct ebt_entries **hook_entries, unsigned int *n, unsigned int valid_hooks, + struct ebt_cl_stack *udc) +{ + int i; + + // we're only interested in chain starts + if (e->bitmask & EBT_ENTRY_OR_ENTRIES) + return 0; + for (i = 0; i < NF_BR_NUMHOOKS; i++) { + if ((valid_hooks & (1 << i)) == 0) + continue; + if (newinfo->hook_entry[i] == (struct ebt_entries *)e) + break; + } + // only care about udc + if (i != NF_BR_NUMHOOKS) + return 0; + + udc[*n].cs.chaininfo = (struct ebt_entries *)e; + // these initialisations are depended on later in check_chainloops() + udc[*n].cs.n = 0; + udc[*n].hookmask = 0; + + (*n)++; + return 0; +} + +static inline int +ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i) +{ + if (i && (*i)-- == 0) + return 1; + if (m->u.match->destroy) + m->u.match->destroy(m->data, m->match_size); + if (m->u.match->me) + __MOD_DEC_USE_COUNT(m->u.match->me); + + return 0; +} + +static inline int +ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i) +{ + if (i && (*i)-- == 0) + return 1; + if (w->u.watcher->destroy) + w->u.watcher->destroy(w->data, w->watcher_size); + if (w->u.watcher->me) + __MOD_DEC_USE_COUNT(w->u.watcher->me); + + return 0; +} + +static inline int +ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt) +{ + struct ebt_entry_target *t; + + if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0) + return 0; + // we're done + if (cnt && (*cnt)-- == 0) + return 1; + EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL); + EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL); + t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); + if (t->u.target->destroy) + t->u.target->destroy(t->data, t->target_size); + if (t->u.target->me) + __MOD_DEC_USE_COUNT(t->u.target->me); + + return 0; +} + +static inline int +ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, + const char *name, unsigned int *cnt, unsigned int valid_hooks, + struct ebt_cl_stack *cl_s, unsigned int udc_cnt) +{ + struct ebt_entry_target *t; + struct ebt_target *target; + unsigned int i, j, hook = 0, hookmask = 0; + int ret; + + // Don't mess with the struct ebt_entries + if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0) + return 0; + + if (e->bitmask & ~EBT_F_MASK) { + BUGPRINT("Unknown flag for bitmask\n"); + return -EINVAL; + } + if (e->invflags & ~EBT_INV_MASK) { + BUGPRINT("Unknown flag for inv bitmask\n"); + return -EINVAL; + } + if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) { + BUGPRINT("NOPROTO & 802_3 not allowed\n"); + return -EINVAL; + } + // what hook do we belong to? + for (i = 0; i < NF_BR_NUMHOOKS; i++) { + if ((valid_hooks & (1 << i)) == 0) + continue; + if ((char *)newinfo->hook_entry[i] < (char *)e) + hook = i; + else + break; + } + // (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on + // a base chain + if (i < NF_BR_NUMHOOKS) + hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); + else { + for (i = 0; i < udc_cnt; i++) + if ((char *)(cl_s[i].cs.chaininfo) > (char *)e) + break; + if (i == 0) + hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); + else + hookmask = cl_s[i - 1].hookmask; + } + i = 0; + ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i); + if (ret != 0) + goto cleanup_matches; + j = 0; + ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j); + if (ret != 0) + goto cleanup_watchers; + t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); + target = find_target_lock(t->u.name, &ret, &ebt_mutex); + if (!target) + goto cleanup_watchers; + if (target->me) + __MOD_INC_USE_COUNT(target->me); + up(&ebt_mutex); + + t->u.target = target; + if (t->u.target == &ebt_standard_target) { + if (e->target_offset + sizeof(struct ebt_standard_target) > + e->next_offset) { + BUGPRINT("Standard target size too big\n"); + ret = -EFAULT; + goto cleanup_watchers; + } + if (((struct ebt_standard_target *)t)->verdict < + -NUM_STANDARD_TARGETS) { + BUGPRINT("Invalid standard target\n"); + ret = -EFAULT; + goto cleanup_watchers; + } + } else if ((e->target_offset + t->target_size + + sizeof(struct ebt_entry_target) > e->next_offset) || + (t->u.target->check && + t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){ + if (t->u.target->me) + __MOD_DEC_USE_COUNT(t->u.target->me); + ret = -EFAULT; + goto cleanup_watchers; + } + (*cnt)++; + return 0; +cleanup_watchers: + EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j); +cleanup_matches: + EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i); + return ret; +} + +// checks for loops and sets the hook mask for udc +// the hook mask for udc tells us from which base chains the udc can be +// accessed. This mask is a parameter to the check() functions of the extensions +int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s, + unsigned int udc_cnt, unsigned int hooknr, char *base) +{ + int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict; + struct ebt_entry *e = (struct ebt_entry *)chain->data; + struct ebt_entry_target *t; + + while (pos < nentries || chain_nr != -1) { + // end of udc, go back one 'recursion' step + if (pos == nentries) { + // put back values of the time when this chain was called + e = cl_s[chain_nr].cs.e; + if (cl_s[chain_nr].from != -1) + nentries = + cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries; + else + nentries = chain->nentries; + pos = cl_s[chain_nr].cs.n; + // make sure we won't see a loop that isn't one + cl_s[chain_nr].cs.n = 0; + chain_nr = cl_s[chain_nr].from; + if (pos == nentries) + continue; + } + t = (struct ebt_entry_target *) + (((char *)e) + e->target_offset); + if (strcmp(t->u.name, EBT_STANDARD_TARGET)) + goto letscontinue; + if (e->target_offset + sizeof(struct ebt_standard_target) > + e->next_offset) { + BUGPRINT("Standard target size too big\n"); + return -1; + } + verdict = ((struct ebt_standard_target *)t)->verdict; + if (verdict >= 0) { // jump to another chain + struct ebt_entries *hlp2 = + (struct ebt_entries *)(base + verdict); + for (i = 0; i < udc_cnt; i++) + if (hlp2 == cl_s[i].cs.chaininfo) + break; + // bad destination or loop + if (i == udc_cnt) { + BUGPRINT("bad destination\n"); + return -1; + } + if (cl_s[i].cs.n) { + BUGPRINT("loop\n"); + return -1; + } + // this can't be 0, so the above test is correct + cl_s[i].cs.n = pos + 1; + pos = 0; + cl_s[i].cs.e = ((void *)e + e->next_offset); + e = (struct ebt_entry *)(hlp2->data); + nentries = hlp2->nentries; + cl_s[i].from = chain_nr; + chain_nr = i; + // this udc is accessible from the base chain for hooknr + cl_s[i].hookmask |= (1 << hooknr); + continue; + } +letscontinue: + e = (void *)e + e->next_offset; + pos++; + } + return 0; +} + +// do the parsing of the table/chains/entries/matches/watchers/targets, heh +static int translate_table(struct ebt_replace *repl, + struct ebt_table_info *newinfo) +{ + unsigned int i, j, k, udc_cnt; + int ret; + struct ebt_cl_stack *cl_s = NULL; // used in the checking for chain loops + + i = 0; + while (i < NF_BR_NUMHOOKS && !(repl->valid_hooks & (1 << i))) + i++; + if (i == NF_BR_NUMHOOKS) { + BUGPRINT("No valid hooks specified\n"); + return -EINVAL; + } + if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) { + BUGPRINT("Chains don't start at beginning\n"); + return -EINVAL; + } + // make sure chains are ordered after each other in same order + // as their corresponding hooks + for (j = i + 1; j < NF_BR_NUMHOOKS; j++) { + if (!(repl->valid_hooks & (1 << j))) + continue; + if ( repl->hook_entry[j] <= repl->hook_entry[i] ) { + BUGPRINT("Hook order must be followed\n"); + return -EINVAL; + } + i = j; + } + + for (i = 0; i < NF_BR_NUMHOOKS; i++) + newinfo->hook_entry[i] = NULL; + + newinfo->entries_size = repl->entries_size; + newinfo->nentries = repl->nentries; + + // do some early checkings and initialize some things + i = 0; // holds the expected nr. of entries for the chain + j = 0; // holds the up to now counted entries for the chain + k = 0; // holds the total nr. of entries, should equal + // newinfo->nentries afterwards + udc_cnt = 0; // will hold the nr. of user defined chains (udc) + ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, + ebt_check_entry_size_and_hooks, newinfo, repl->entries, + repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k, + &udc_cnt, repl->valid_hooks); + + if (ret != 0) + return ret; + + if (i != j) { + BUGPRINT("nentries does not equal the nr of entries in the " + "(last) chain\n"); + return -EINVAL; + } + if (k != newinfo->nentries) { + BUGPRINT("Total nentries is wrong\n"); + return -EINVAL; + } + + // check if all valid hooks have a chain + for (i = 0; i < NF_BR_NUMHOOKS; i++) { + if (newinfo->hook_entry[i] == NULL && + (repl->valid_hooks & (1 << i))) { + BUGPRINT("Valid hook without chain\n"); + return -EINVAL; + } + } + + // Get the location of the udc, put them in an array + // While we're at it, allocate the chainstack + if (udc_cnt) { + // this will get free'd in do_replace()/ebt_register_table() + // if an error occurs + newinfo->chainstack = (struct ebt_chainstack **) + vmalloc(NR_CPUS * sizeof(struct ebt_chainstack)); + if (!newinfo->chainstack) + return -ENOMEM; + for (i = 0; i < NR_CPUS; i++) { + newinfo->chainstack[i] = + vmalloc(udc_cnt * sizeof(struct ebt_chainstack)); + if (!newinfo->chainstack[i]) { + while (i) + vfree(newinfo->chainstack[--i]); + vfree(newinfo->chainstack); + newinfo->chainstack = NULL; + return -ENOMEM; + } + } + + cl_s = (struct ebt_cl_stack *) + vmalloc(udc_cnt * sizeof(struct ebt_cl_stack)); + if (!cl_s) + return -ENOMEM; + i = 0; // the i'th udc + EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, + ebt_get_udc_positions, newinfo, repl->hook_entry, &i, + repl->valid_hooks, cl_s); + // sanity check + if (i != udc_cnt) { + BUGPRINT("i != udc_cnt\n"); + vfree(cl_s); + return -EFAULT; + } + } + + // Check for loops + for (i = 0; i < NF_BR_NUMHOOKS; i++) + if (repl->valid_hooks & (1 << i)) + if (check_chainloops(newinfo->hook_entry[i], + cl_s, udc_cnt, i, newinfo->entries)) { + if (cl_s) + vfree(cl_s); + return -EINVAL; + } + + // we now know the following (along with E=mc²): + // - the nr of entries in each chain is right + // - the size of the allocated space is right + // - all valid hooks have a corresponding chain + // - there are no loops + // - wrong data can still be on the level of a single entry + // - could be there are jumps to places that are not the + // beginning of a chain. This can only occur in chains that + // are not accessible from any base chains, so we don't care. + + // used to know what we need to clean up if something goes wrong + i = 0; + ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, + ebt_check_entry, newinfo, repl->name, &i, repl->valid_hooks, + cl_s, udc_cnt); + if (ret != 0) { + EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, + ebt_cleanup_entry, &i); + } + if (cl_s) + vfree(cl_s); + return ret; +} + +// called under write_lock +static void get_counters(struct ebt_counter *oldcounters, + struct ebt_counter *counters, unsigned int nentries) +{ + int i, cpu; + struct ebt_counter *counter_base; + + // counters of cpu 0 + memcpy(counters, oldcounters, + sizeof(struct ebt_counter) * nentries); + // add other counters to those of cpu 0 + for (cpu = 1; cpu < NR_CPUS; cpu++) { + counter_base = COUNTER_BASE(oldcounters, nentries, cpu); + for (i = 0; i < nentries; i++) + counters[i].pcnt += counter_base[i].pcnt; + } +} + +// replace the table +static int do_replace(void *user, unsigned int len) +{ + int ret, i, countersize; + struct ebt_table_info *newinfo; + struct ebt_replace tmp; + struct ebt_table *t; + struct ebt_counter *counterstmp = NULL; + // used to be able to unlock earlier + struct ebt_table_info *table; + + if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) + return -EFAULT; + + if (len != sizeof(tmp) + tmp.entries_size) { + BUGPRINT("Wrong len argument\n"); + return -EINVAL; + } + + if (tmp.entries_size == 0) { + BUGPRINT("Entries_size never zero\n"); + return -EINVAL; + } + countersize = COUNTER_OFFSET(tmp.nentries) * NR_CPUS; + newinfo = (struct ebt_table_info *) + vmalloc(sizeof(struct ebt_table_info) + countersize); + if (!newinfo) + return -ENOMEM; + + if (countersize) + memset(newinfo->counters, 0, countersize); + + newinfo->entries = (char *)vmalloc(tmp.entries_size); + if (!newinfo->entries) { + ret = -ENOMEM; + goto free_newinfo; + } + if (copy_from_user( + newinfo->entries, tmp.entries, tmp.entries_size) != 0) { + BUGPRINT("Couldn't copy entries from userspace\n"); + ret = -EFAULT; + goto free_entries; + } + + // the user wants counters back + // the check on the size is done later, when we have the lock + if (tmp.num_counters) { + counterstmp = (struct ebt_counter *) + vmalloc(tmp.num_counters * sizeof(struct ebt_counter)); + if (!counterstmp) { + ret = -ENOMEM; + goto free_entries; + } + } + else + counterstmp = NULL; + + // this can get initialized by translate_table() + newinfo->chainstack = NULL; + ret = translate_table(&tmp, newinfo); + + if (ret != 0) + goto free_counterstmp; + + t = find_table_lock(tmp.name, &ret, &ebt_mutex); + if (!t) + goto free_iterate; + + // the table doesn't like it + if (t->check && (ret = t->check(newinfo, tmp.valid_hooks))) + goto free_unlock; + + if (tmp.num_counters && tmp.num_counters != t->private->nentries) { + BUGPRINT("Wrong nr. of counters requested\n"); + ret = -EINVAL; + goto free_unlock; + } + + // we have the mutex lock, so no danger in reading this pointer + table = t->private; + // we need an atomic snapshot of the counters + write_lock_bh(&t->lock); + if (tmp.num_counters) + get_counters(t->private->counters, counterstmp, + t->private->nentries); + + t->private = newinfo; + write_unlock_bh(&t->lock); + up(&ebt_mutex); + // So, a user can change the chains while having messed up her counter + // allocation. Only reason why this is done is because this way the lock + // is held only once, while this doesn't bring the kernel into a + // dangerous state. + if (tmp.num_counters && + copy_to_user(tmp.counters, counterstmp, + tmp.num_counters * sizeof(struct ebt_counter))) { + BUGPRINT("Couldn't copy counters to userspace\n"); + ret = -EFAULT; + } + else + ret = 0; + + // decrease module count and free resources + EBT_ENTRY_ITERATE(table->entries, table->entries_size, + ebt_cleanup_entry, NULL); + + vfree(table->entries); + if (table->chainstack) { + for (i = 0; i < NR_CPUS; i++) + vfree(table->chainstack[i]); + vfree(table->chainstack); + } + vfree(table); + + if (counterstmp) + vfree(counterstmp); + return ret; + +free_unlock: + up(&ebt_mutex); +free_iterate: + EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, + ebt_cleanup_entry, NULL); +free_counterstmp: + if (counterstmp) + vfree(counterstmp); + // can be initialized in translate_table() + if (newinfo->chainstack) { + for (i = 0; i < NR_CPUS; i++) + vfree(newinfo->chainstack[i]); + vfree(newinfo->chainstack); + } +free_entries: + if (newinfo->entries) + vfree(newinfo->entries); +free_newinfo: + if (newinfo) + vfree(newinfo); + return ret; +} + +int ebt_register_target(struct ebt_target *target) +{ + int ret; + + ret = down_interruptible(&ebt_mutex); + if (ret != 0) + return ret; + if (!list_named_insert(&ebt_targets, target)) { + up(&ebt_mutex); + return -EEXIST; + } + up(&ebt_mutex); + MOD_INC_USE_COUNT; + + return 0; +} + +void ebt_unregister_target(struct ebt_target *target) +{ + down(&ebt_mutex); + LIST_DELETE(&ebt_targets, target); + up(&ebt_mutex); + MOD_DEC_USE_COUNT; +} + +int ebt_register_match(struct ebt_match *match) +{ + int ret; + + ret = down_interruptible(&ebt_mutex); + if (ret != 0) + return ret; + if (!list_named_insert(&ebt_matches, match)) { + up(&ebt_mutex); + return -EEXIST; + } + up(&ebt_mutex); + MOD_INC_USE_COUNT; + + return 0; +} + +void ebt_unregister_match(struct ebt_match *match) +{ + down(&ebt_mutex); + LIST_DELETE(&ebt_matches, match); + up(&ebt_mutex); + MOD_DEC_USE_COUNT; +} + +int ebt_register_watcher(struct ebt_watcher *watcher) +{ + int ret; + + ret = down_interruptible(&ebt_mutex); + if (ret != 0) + return ret; + if (!list_named_insert(&ebt_watchers, watcher)) { + up(&ebt_mutex); + return -EEXIST; + } + up(&ebt_mutex); + MOD_INC_USE_COUNT; + + return 0; +} + +void ebt_unregister_watcher(struct ebt_watcher *watcher) +{ + down(&ebt_mutex); + LIST_DELETE(&ebt_watchers, watcher); + up(&ebt_mutex); + MOD_DEC_USE_COUNT; +} + +int ebt_register_table(struct ebt_table *table) +{ + struct ebt_table_info *newinfo; + int ret, i, countersize; + + if (!table || !table->table ||!table->table->entries || + table->table->entries_size == 0 || + table->table->counters || table->private) { + BUGPRINT("Bad table data for ebt_register_table!!!\n"); + return -EINVAL; + } + + countersize = COUNTER_OFFSET(table->table->nentries) * NR_CPUS; + newinfo = (struct ebt_table_info *) + vmalloc(sizeof(struct ebt_table_info) + countersize); + ret = -ENOMEM; + if (!newinfo) + return -ENOMEM; + + newinfo->entries = (char *)vmalloc(table->table->entries_size); + if (!(newinfo->entries)) + goto free_newinfo; + + memcpy(newinfo->entries, table->table->entries, + table->table->entries_size); + + if (countersize) + memset(newinfo->counters, 0, countersize); + + // fill in newinfo and parse the entries + newinfo->chainstack = NULL; + ret = translate_table(table->table, newinfo); + if (ret != 0) { + BUGPRINT("Translate_table failed\n"); + goto free_chainstack; + } + + if (table->check && table->check(newinfo, table->valid_hooks)) { + BUGPRINT("The table doesn't like its own initial data, lol\n"); + return -EINVAL; + } + + table->private = newinfo; + table->lock = RW_LOCK_UNLOCKED; + ret = down_interruptible(&ebt_mutex); + if (ret != 0) + goto free_chainstack; + + if (list_named_find(&ebt_tables, table->name)) { + ret = -EEXIST; + BUGPRINT("Table name already exists\n"); + goto free_unlock; + } + + list_prepend(&ebt_tables, table); + up(&ebt_mutex); + MOD_INC_USE_COUNT; + return 0; +free_unlock: + up(&ebt_mutex); +free_chainstack: + if (newinfo->chainstack) { + for (i = 0; i < NR_CPUS; i++) + vfree(newinfo->chainstack[i]); + vfree(newinfo->chainstack); + } + vfree(newinfo->entries); +free_newinfo: + vfree(newinfo); + return ret; +} + +void ebt_unregister_table(struct ebt_table *table) +{ + int i; + + if (!table) { + BUGPRINT("Request to unregister NULL table!!!\n"); + return; + } + down(&ebt_mutex); + LIST_DELETE(&ebt_tables, table); + up(&ebt_mutex); + EBT_ENTRY_ITERATE(table->private->entries, + table->private->entries_size, ebt_cleanup_entry, NULL); + if (table->private->entries) + vfree(table->private->entries); + if (table->private->chainstack) { + for (i = 0; i < NR_CPUS; i++) + vfree(table->private->chainstack[i]); + vfree(table->private->chainstack); + } + vfree(table->private); + MOD_DEC_USE_COUNT; +} + +// userspace just supplied us with counters +static int update_counters(void *user, unsigned int len) +{ + int i, ret; + struct ebt_counter *tmp; + struct ebt_replace hlp; + struct ebt_table *t; + + if (copy_from_user(&hlp, user, sizeof(hlp))) + return -EFAULT; + + if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter)) + return -EINVAL; + if (hlp.num_counters == 0) + return -EINVAL; + + if ( !(tmp = (struct ebt_counter *) + vmalloc(hlp.num_counters * sizeof(struct ebt_counter))) ){ + MEMPRINT("Update_counters && nomemory\n"); + return -ENOMEM; + } + + t = find_table_lock(hlp.name, &ret, &ebt_mutex); + if (!t) + goto free_tmp; + + if (hlp.num_counters != t->private->nentries) { + BUGPRINT("Wrong nr of counters\n"); + ret = -EINVAL; + goto unlock_mutex; + } + + if ( copy_from_user(tmp, hlp.counters, + hlp.num_counters * sizeof(struct ebt_counter)) ) { + BUGPRINT("Updata_counters && !cfu\n"); + ret = -EFAULT; + goto unlock_mutex; + } + + // we want an atomic add of the counters + write_lock_bh(&t->lock); + + // we add to the counters of the first cpu + for (i = 0; i < hlp.num_counters; i++) + t->private->counters[i].pcnt += tmp[i].pcnt; + + write_unlock_bh(&t->lock); + ret = 0; +unlock_mutex: + up(&ebt_mutex); +free_tmp: + vfree(tmp); + return ret; +} + +static inline int ebt_make_matchname(struct ebt_entry_match *m, + char *base, char *ubase) +{ + char *hlp = ubase - base + (char *)m; + if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN)) + return -EFAULT; + return 0; +} + +static inline int ebt_make_watchername(struct ebt_entry_watcher *w, + char *base, char *ubase) +{ + char *hlp = ubase - base + (char *)w; + if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN)) + return -EFAULT; + return 0; +} + +static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase) +{ + int ret; + char *hlp; + struct ebt_entry_target *t; + + if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0) + return 0; + + hlp = ubase - base + (char *)e + e->target_offset; + t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); + + ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase); + if (ret != 0) + return ret; + ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase); + if (ret != 0) + return ret; + if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN)) + return -EFAULT; + return 0; +} + +// called with ebt_mutex down +static int copy_everything_to_user(struct ebt_table *t, void *user, + int *len, int cmd) +{ + struct ebt_replace tmp; + struct ebt_counter *counterstmp, *oldcounters; + unsigned int entries_size, nentries; + char *entries; + + if (cmd == EBT_SO_GET_ENTRIES) { + entries_size = t->private->entries_size; + nentries = t->private->nentries; + entries = t->private->entries; + oldcounters = t->private->counters; + } else { + entries_size = t->table->entries_size; + nentries = t->table->nentries; + entries = t->table->entries; + oldcounters = t->table->counters; + } + + if (copy_from_user(&tmp, user, sizeof(tmp))) { + BUGPRINT("Cfu didn't work\n"); + return -EFAULT; + } + + if (*len != sizeof(struct ebt_replace) + entries_size + + (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) { + BUGPRINT("Wrong size\n"); + return -EINVAL; + } + + if (tmp.nentries != nentries) { + BUGPRINT("Nentries wrong\n"); + return -EINVAL; + } + + if (tmp.entries_size != entries_size) { + BUGPRINT("Wrong size\n"); + return -EINVAL; + } + + // userspace might not need the counters + if (tmp.num_counters) { + if (tmp.num_counters != nentries) { + BUGPRINT("Num_counters wrong\n"); + return -EINVAL; + } + counterstmp = (struct ebt_counter *) + vmalloc(nentries * sizeof(struct ebt_counter)); + if (!counterstmp) { + MEMPRINT("Couldn't copy counters, out of memory\n"); + return -ENOMEM; + } + write_lock_bh(&t->lock); + get_counters(oldcounters, counterstmp, nentries); + write_unlock_bh(&t->lock); + + if (copy_to_user(tmp.counters, counterstmp, + nentries * sizeof(struct ebt_counter))) { + BUGPRINT("Couldn't copy counters to userspace\n"); + vfree(counterstmp); + return -EFAULT; + } + vfree(counterstmp); + } + + if (copy_to_user(tmp.entries, entries, entries_size)) { + BUGPRINT("Couldn't copy entries to userspace\n"); + return -EFAULT; + } + // set the match/watcher/target names right + return EBT_ENTRY_ITERATE(entries, entries_size, + ebt_make_names, entries, tmp.entries); +} + +static int do_ebt_set_ctl(struct sock *sk, + int cmd, void *user, unsigned int len) +{ + int ret; + + switch(cmd) { + case EBT_SO_SET_ENTRIES: + ret = do_replace(user, len); + break; + case EBT_SO_SET_COUNTERS: + ret = update_counters(user, len); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int do_ebt_get_ctl(struct sock *sk, int cmd, void *user, int *len) +{ + int ret; + struct ebt_replace tmp; + struct ebt_table *t; + + if (copy_from_user(&tmp, user, sizeof(tmp))) + return -EFAULT; + + t = find_table_lock(tmp.name, &ret, &ebt_mutex); + if (!t) + return ret; + + switch(cmd) { + case EBT_SO_GET_INFO: + case EBT_SO_GET_INIT_INFO: + if (*len != sizeof(struct ebt_replace)){ + ret = -EINVAL; + up(&ebt_mutex); + break; + } + if (cmd == EBT_SO_GET_INFO) { + tmp.nentries = t->private->nentries; + tmp.entries_size = t->private->entries_size; + tmp.valid_hooks = t->valid_hooks; + } else { + tmp.nentries = t->table->nentries; + tmp.entries_size = t->table->entries_size; + tmp.valid_hooks = t->table->valid_hooks; + } + up(&ebt_mutex); + if (copy_to_user(user, &tmp, *len) != 0){ + BUGPRINT("c2u Didn't work\n"); + ret = -EFAULT; + break; + } + ret = 0; + break; + + case EBT_SO_GET_ENTRIES: + case EBT_SO_GET_INIT_ENTRIES: + ret = copy_everything_to_user(t, user, len, cmd); + up(&ebt_mutex); + break; + + default: + up(&ebt_mutex); + ret = -EINVAL; + } + + return ret; +} + +static struct nf_sockopt_ops ebt_sockopts = +{ { NULL, NULL }, PF_INET, EBT_BASE_CTL, EBT_SO_SET_MAX + 1, do_ebt_set_ctl, + EBT_BASE_CTL, EBT_SO_GET_MAX + 1, do_ebt_get_ctl, 0, NULL +}; + +static int __init init(void) +{ + int ret; + + down(&ebt_mutex); + list_named_insert(&ebt_targets, &ebt_standard_target); + up(&ebt_mutex); + if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0) + return ret; + + printk("Ebtables v2.0 registered"); + return 0; +} + +static void __exit fini(void) +{ + nf_unregister_sockopt(&ebt_sockopts); + printk("Ebtables v2.0 unregistered"); +} + +EXPORT_SYMBOL(ebt_register_table); +EXPORT_SYMBOL(ebt_unregister_table); +EXPORT_SYMBOL(ebt_register_match); +EXPORT_SYMBOL(ebt_unregister_match); +EXPORT_SYMBOL(ebt_register_watcher); +EXPORT_SYMBOL(ebt_unregister_watcher); +EXPORT_SYMBOL(ebt_register_target); +EXPORT_SYMBOL(ebt_unregister_target); +EXPORT_SYMBOL(ebt_do_table); +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/core/dev.c b/net/core/dev.c --- a/net/core/dev.c Fri Sep 20 08:20:46 2002 +++ b/net/core/dev.c Fri Sep 20 08:20:46 2002 @@ -1397,7 +1397,7 @@ } #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) -void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; +int (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; #endif static __inline__ int handle_bridge(struct sk_buff *skb, @@ -1414,7 +1414,6 @@ } } - br_handle_frame_hook(skb); return ret; } @@ -1475,7 +1474,12 @@ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) if (skb->dev->br_port && br_handle_frame_hook) { - return handle_bridge(skb, pt_prev); + int ret; + + ret = handle_bridge(skb, pt_prev); + if (br_handle_frame_hook(skb) == 0) + return ret; + pt_prev = NULL; } #endif diff -Nru a/net/core/wireless.c b/net/core/wireless.c --- a/net/core/wireless.c Fri Sep 20 08:20:47 2002 +++ b/net/core/wireless.c Fri Sep 20 08:20:47 2002 @@ -33,8 +33,16 @@ * o Propagate events as rtnetlink IFLA_WIRELESS option * o Generate event on selected SET requests * - * v4 - 18.04.01 - Jean II + * v4 - 18.04.02 - Jean II * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 + * + * v5 - 21.06.02 - Jean II + * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup) + * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes + * o Add IWEVCUSTOM for driver specific event/scanning token + * o Turn on WE_STRICT_WRITE by default + kernel warning + * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) + * o Fix off-by-one in test (extra_size <= IFNAMSIZ) */ /***************************** INCLUDES *****************************/ @@ -50,8 +58,9 @@ /**************************** CONSTANTS ****************************/ -/* This will be turned on later on... */ -#undef WE_STRICT_WRITE /* Check write buffer size */ +/* Enough lenience, let's make sure things are proper... */ +#define WE_STRICT_WRITE /* Check write buffer size */ +/* I'll probably drop both the define and kernel message in the next version */ /* Debuging stuff */ #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ @@ -106,7 +115,7 @@ /* SIOCSIWSPY */ { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0}, /* SIOCGIWSPY */ - { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0}, + { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0}, /* -- hole -- */ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, /* -- hole -- */ @@ -176,25 +185,41 @@ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, /* IWEVQUAL */ { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, + /* IWEVCUSTOM */ + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0}, + /* IWEVREGISTERED */ + { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, + /* IWEVEXPIRED */ + { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, }; static const int standard_event_num = (sizeof(standard_event) / sizeof(struct iw_ioctl_description)); /* Size (in bytes) of the various private data types */ -static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; +static const char priv_type_size[] = { + 0, /* IW_PRIV_TYPE_NONE */ + 1, /* IW_PRIV_TYPE_BYTE */ + 1, /* IW_PRIV_TYPE_CHAR */ + 0, /* Not defined */ + sizeof(__u32), /* IW_PRIV_TYPE_INT */ + sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ + sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ + 0, /* Not defined */ +}; /* Size (in bytes) of various events */ static const int event_type_size[] = { - IW_EV_LCP_LEN, + IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ + 0, + IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ 0, - IW_EV_CHAR_LEN, + IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ + IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ + IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ 0, - IW_EV_UINT_LEN, - IW_EV_FREQ_LEN, IW_EV_POINT_LEN, /* Without variable payload */ - IW_EV_PARAM_LEN, - IW_EV_ADDR_LEN, - IW_EV_QUAL_LEN, + IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ + IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ }; /************************ COMMON SUBROUTINES ************************/ @@ -440,8 +465,10 @@ return -EFAULT; #ifdef WE_STRICT_WRITE /* Check if there is enough buffer up there */ - if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1)) + if(iwr->u.data.length < dev->wireless_handlers->num_private_args) { + printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args); return -E2BIG; + } #endif /* WE_STRICT_WRITE */ /* Set the number of available ioctls. */ @@ -471,6 +498,7 @@ const struct iw_ioctl_description * descr; struct iw_request_info info; int ret = -EINVAL; + int user_size = 0; /* Get the description of the IOCTL */ if((cmd - SIOCIWFIRST) >= standard_ioctl_num) @@ -518,11 +546,8 @@ /* Check NULL pointer */ if(iwr->u.data.pointer == NULL) return -EFAULT; -#ifdef WE_STRICT_WRITE - /* Check if there is enough buffer up there */ - if(iwr->u.data.length < descr->max_tokens) - return -E2BIG; -#endif /* WE_STRICT_WRITE */ + /* Save user space buffer size for checking */ + user_size = iwr->u.data.length; } #ifdef WE_IOCTL_DEBUG @@ -559,6 +584,15 @@ /* If we have something to return to the user */ if (!ret && IW_IS_GET(cmd)) { +#ifdef WE_STRICT_WRITE + /* Check if there is enough buffer up there */ + if(user_size < iwr->u.data.length) { + printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length); + kfree(extra); + return -E2BIG; + } +#endif /* WE_STRICT_WRITE */ + err = copy_to_user(iwr->u.data.pointer, extra, iwr->u.data.length * descr->token_size); @@ -646,12 +680,18 @@ /* Compute the size of the set/get arguments */ if(descr != NULL) { if(IW_IS_SET(cmd)) { + int offset = 0; /* For sub-ioctls */ + /* Check for sub-ioctl handler */ + if(descr->name[0] == '\0') + /* Reserve one int for sub-ioctl index */ + offset = sizeof(__u32); + /* Size of set arguments */ extra_size = get_priv_size(descr->set_args); /* Does it fits in iwr ? */ if((descr->set_args & IW_PRIV_SIZE_FIXED) && - (extra_size < IFNAMSIZ)) + ((extra_size + offset) <= IFNAMSIZ)) extra_size = 0; } else { /* Size of set arguments */ @@ -659,7 +699,7 @@ /* Does it fits in iwr ? */ if((descr->get_args & IW_PRIV_SIZE_FIXED) && - (extra_size < IFNAMSIZ)) + (extra_size <= IFNAMSIZ)) extra_size = 0; } } @@ -925,7 +965,7 @@ * The best the driver could do is to log an error message. * We will do it ourselves instead... */ - printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", + printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", dev->name, cmd); return; } diff -Nru a/net/irda/discovery.c b/net/irda/discovery.c --- a/net/irda/discovery.c Fri Sep 20 08:20:43 2002 +++ b/net/irda/discovery.c Fri Sep 20 08:20:43 2002 @@ -61,7 +61,7 @@ /* Set time of first discovery if node is new (see below) */ new->first_timestamp = new->timestamp; - spin_lock_irqsave(&irlmp->log_lock, flags); + spin_lock_irqsave(&cachelog->hb_spinlock, flags); /* * Remove all discoveries of devices that has previously been @@ -95,13 +95,13 @@ /* Insert the new and updated version */ hashbin_insert(cachelog, (irda_queue_t *) new, new->daddr, NULL); - spin_unlock_irqrestore(&irlmp->log_lock, flags); + spin_unlock_irqrestore(&cachelog->hb_spinlock, flags); } /* * Function irlmp_add_discovery_log (cachelog, log) * - * Merge a disovery log into the cachlog. + * Merge a disovery log into the cachelog. * */ void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log) @@ -115,11 +115,17 @@ * discovery, so restart discovery again with just the half timeout * of the normal one. */ + /* Well... It means that there was nobody out there - Jean II */ if (log == NULL) { /* irlmp_start_discovery_timer(irlmp, 150); */ return; } + /* + * Locking : we are the only owner of this discovery log, so + * no need to lock it. + * We just need to lock the global log in irlmp_add_discovery(). + */ discovery = (discovery_t *) hashbin_remove_first(log); while (discovery != NULL) { irlmp_add_discovery(cachelog, discovery); @@ -146,7 +152,7 @@ IRDA_DEBUG(4, __FUNCTION__ "()\n"); - spin_lock_irqsave(&irlmp->log_lock, flags); + spin_lock_irqsave(&log->hb_spinlock, flags); discovery = (discovery_t *) hashbin_get_first(log); while (discovery != NULL) { @@ -169,7 +175,7 @@ } } - spin_unlock_irqrestore(&irlmp->log_lock, flags); + spin_unlock_irqrestore(&log->hb_spinlock, flags); } /* @@ -230,13 +236,13 @@ return NULL; /* Save spin lock - spinlock should be discovery specific */ - spin_lock_irqsave(&irlmp->log_lock, flags); + spin_lock_irqsave(&log->hb_spinlock, flags); /* Create the client specific buffer */ n = HASHBIN_GET_SIZE(log); buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC); if (buffer == NULL) { - spin_unlock_irqrestore(&irlmp->log_lock, flags); + spin_unlock_irqrestore(&log->hb_spinlock, flags); return NULL; } @@ -257,7 +263,7 @@ discovery = (discovery_t *) hashbin_get_next(log); } - spin_unlock_irqrestore(&irlmp->log_lock, flags); + spin_unlock_irqrestore(&log->hb_spinlock, flags); /* Get the actual number of device in the buffer and return */ *pn = i; @@ -276,7 +282,7 @@ unsigned long flags; discovery_t *d; - spin_lock_irqsave(&irlmp->log_lock, flags); + spin_lock_irqsave(&cachelog->hb_spinlock, flags); /* Look at all discoveries for that link */ d = (discovery_t *) hashbin_get_first(cachelog); @@ -288,13 +294,13 @@ if (strcmp(name, d->nickname) == 0) { *saddr = d->saddr; - spin_unlock_irqrestore(&irlmp->log_lock, flags); + spin_unlock_irqrestore(&cachelog->hb_spinlock, flags); return d->daddr; } d = (discovery_t *) hashbin_get_next(cachelog); } - spin_unlock_irqrestore(&irlmp->log_lock, flags); + spin_unlock_irqrestore(&cachelog->hb_spinlock, flags); return 0; } @@ -310,7 +316,7 @@ { discovery_t *discovery; unsigned long flags; - hashbin_t *cachelog = irlmp_get_cachelog(); + hashbin_t *cachelog = irlmp->cachelog; int len = 0; if (!irlmp) @@ -318,7 +324,7 @@ len = sprintf(buf, "IrLMP: Discovery log:\n\n"); - spin_lock_irqsave(&irlmp->log_lock, flags); + spin_lock_irqsave(&cachelog->hb_spinlock, flags); discovery = (discovery_t *) hashbin_get_first(cachelog); while (( discovery != NULL) && (len < length)) { @@ -362,7 +368,7 @@ discovery = (discovery_t *) hashbin_get_next(cachelog); } - spin_unlock_irqrestore(&irlmp->log_lock, flags); + spin_unlock_irqrestore(&cachelog->hb_spinlock, flags); return len; } diff -Nru a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c --- a/net/irda/ircomm/ircomm_core.c Fri Sep 20 08:20:41 2002 +++ b/net/irda/ircomm/ircomm_core.c Fri Sep 20 08:20:41 2002 @@ -61,7 +61,7 @@ int __init ircomm_init(void) { - ircomm = hashbin_new(HB_LOCAL); + ircomm = hashbin_new(HB_LOCK); if (ircomm == NULL) { ERROR(__FUNCTION__ "(), can't allocate hashbin!\n"); return -ENOMEM; @@ -505,11 +505,10 @@ struct ircomm_cb *self; unsigned long flags; - save_flags(flags); - cli(); - len = 0; + spin_lock_irqsave(&ircomm->hb_spinlock, flags); + self = (struct ircomm_cb *) hashbin_get_first(ircomm); while (self != NULL) { ASSERT(self->magic == IRCOMM_MAGIC, break;); @@ -535,7 +534,7 @@ self = (struct ircomm_cb *) hashbin_get_next(ircomm); } - restore_flags(flags); + spin_unlock_irqrestore(&ircomm->hb_spinlock, flags); return len; } diff -Nru a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c --- a/net/irda/ircomm/ircomm_lmp.c Fri Sep 20 08:20:41 2002 +++ b/net/irda/ircomm/ircomm_lmp.c Fri Sep 20 08:20:41 2002 @@ -177,7 +177,7 @@ line = cb->line; - self = (struct ircomm_cb *) hashbin_find(ircomm, line, NULL); + self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL); if (!self) { IRDA_DEBUG(2, __FUNCTION__ "(), didn't find myself\n"); return; diff -Nru a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c --- a/net/irda/ircomm/ircomm_param.c Fri Sep 20 08:20:46 2002 +++ b/net/irda/ircomm/ircomm_param.c Fri Sep 20 08:20:46 2002 @@ -99,6 +99,8 @@ */ int ircomm_param_flush(struct ircomm_tty_cb *self) { + /* we should lock here, but I guess this function is unused... + * Jean II */ if (self->ctrl_skb) { ircomm_control_request(self->ircomm, self->ctrl_skb); self->ctrl_skb = NULL; @@ -132,14 +134,13 @@ if (self->service_type == IRCOMM_3_WIRE_RAW) return 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&self->spinlock, flags); skb = self->ctrl_skb; if (!skb) { skb = dev_alloc_skb(256); if (!skb) { - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); return -ENOMEM; } @@ -154,12 +155,12 @@ &ircomm_param_info); if (count < 0) { WARNING(__FUNCTION__ "(), no room for parameter!\n"); - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); return -1; } skb_put(skb, count); - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); IRDA_DEBUG(2, __FUNCTION__ "(), skb->len=%d\n", skb->len); diff -Nru a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c --- a/net/irda/ircomm/ircomm_tty.c Fri Sep 20 08:20:44 2002 +++ b/net/irda/ircomm/ircomm_tty.c Fri Sep 20 08:20:44 2002 @@ -90,7 +90,7 @@ */ int __init ircomm_tty_init(void) { - ircomm_tty = hashbin_new(HB_LOCAL); + ircomm_tty = hashbin_new(HB_LOCK); if (ircomm_tty == NULL) { ERROR(__FUNCTION__ "(), can't allocate hashbin!\n"); return -ENOMEM; @@ -308,22 +308,25 @@ IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n", __FILE__,__LINE__, tty->driver.name, self->open_count ); - save_flags(flags); cli(); + /* As far as I can see, we protect open_count - Jean II */ + spin_lock_irqsave(&self->spinlock, flags); if (!tty_hung_up_p(filp)) { extra_count = 1; self->open_count--; } - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); self->blocked_open++; while (1) { if (!(self->flags & ASYNC_CALLOUT_ACTIVE) && (tty->termios->c_cflag & CBAUD)) { - save_flags(flags); cli(); + /* Here, we use to lock those two guys, but + * as ircomm_param_request() does it itself, + * I don't see the point (and I see the deadlock). + * Jean II */ self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR; ircomm_param_request(self, IRCOMM_DTE, TRUE); - restore_flags(flags); } current->state = TASK_INTERRUPTIBLE; @@ -361,8 +364,12 @@ __set_current_state(TASK_RUNNING); remove_wait_queue(&self->open_wait, &wait); - if (extra_count) + if (extra_count) { + /* ++ is not atomic, so this should be protected - Jean II */ + spin_lock_irqsave(&self->spinlock, flags); self->open_count++; + spin_unlock_irqrestore(&self->spinlock, flags); + } self->blocked_open--; IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n", @@ -385,6 +392,7 @@ { struct ircomm_tty_cb *self; unsigned int line; + unsigned long flags; int ret; IRDA_DEBUG(2, __FUNCTION__ "()\n"); @@ -397,7 +405,7 @@ } /* Check if instance already exists */ - self = hashbin_find(ircomm_tty, line, NULL); + self = hashbin_lock_find(ircomm_tty, line, NULL); if (!self) { /* No, so make new instance */ self = kmalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL); @@ -423,6 +431,7 @@ init_timer(&self->watchdog_timer); init_waitqueue_head(&self->open_wait); init_waitqueue_head(&self->close_wait); + spin_lock_init(&self->spinlock); /* * Force TTY into raw mode by default which is usually what @@ -435,10 +444,13 @@ /* Insert into hash */ hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL); } + /* ++ is not atomic, so this should be protected - Jean II */ + spin_lock_irqsave(&self->spinlock, flags); self->open_count++; tty->driver_data = self; self->tty = tty; + spin_unlock_irqrestore(&self->spinlock, flags); IRDA_DEBUG(1, __FUNCTION__"(), %s%d, count = %d\n", tty->driver.name, self->line, self->open_count); @@ -526,12 +538,11 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - save_flags(flags); - cli(); + spin_lock_irqsave(&self->spinlock, flags); if (tty_hung_up_p(filp)) { MOD_DEC_USE_COUNT; - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); IRDA_DEBUG(0, __FUNCTION__ "(), returning 1\n"); return; @@ -559,13 +570,19 @@ } if (self->open_count) { MOD_DEC_USE_COUNT; - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); IRDA_DEBUG(0, __FUNCTION__ "(), open count > 0\n"); return; } self->flags |= ASYNC_CLOSING; + /* We need to unlock here (we were unlocking at the end of this + * function), because tty_wait_until_sent() may schedule. + * I don't know if the rest should be locked somehow, + * so someone should check. - Jean II */ + spin_unlock_irqrestore(&self->spinlock, flags); + /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -597,7 +614,6 @@ wake_up_interruptible(&self->close_wait); MOD_DEC_USE_COUNT; - restore_flags(flags); } /* @@ -645,13 +661,12 @@ return; /* Unlink control buffer */ - save_flags(flags); - cli(); + spin_lock_irqsave(&self->spinlock, flags); ctrl_skb = self->ctrl_skb; self->ctrl_skb = NULL; - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); /* Flush control buffer if any */ if (ctrl_skb && self->flow == FLOW_START) @@ -661,13 +676,12 @@ return; /* Unlink transmit buffer */ - save_flags(flags); - cli(); + spin_lock_irqsave(&self->spinlock, flags); skb = self->tx_skb; self->tx_skb = NULL; - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); /* Flush transmit buffer if any */ if (skb) @@ -720,8 +734,7 @@ return len; } - save_flags(flags); - cli(); + spin_lock_irqsave(&self->spinlock, flags); /* Fetch current transmit buffer */ skb = self->tx_skb; @@ -768,7 +781,7 @@ skb = dev_alloc_skb(self->max_data_size+ self->max_header_size); if (!skb) { - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); return -ENOBUFS; } skb_reserve(skb, self->max_header_size); @@ -785,7 +798,7 @@ len += size; } - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); /* * Schedule a new thread which will transmit the frame as soon @@ -824,13 +837,12 @@ (self->max_header_size == IRCOMM_TTY_HDR_UNITIALISED)) ret = 0; else { - save_flags(flags); - cli(); + spin_lock_irqsave(&self->spinlock, flags); if (self->tx_skb) ret = self->max_data_size - self->tx_skb->len; else ret = self->max_data_size; - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); } IRDA_DEBUG(2, __FUNCTION__ "(), ret=%d\n", ret); @@ -946,13 +958,12 @@ ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - save_flags(flags); - cli(); + spin_lock_irqsave(&self->spinlock, flags); if (self->tx_skb) len = self->tx_skb->len; - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); return len; } @@ -969,8 +980,7 @@ if (!(self->flags & ASYNC_INITIALIZED)) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&self->spinlock, flags); del_timer(&self->watchdog_timer); @@ -994,7 +1004,7 @@ } self->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore(&self->spinlock, flags); } /* @@ -1007,6 +1017,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + unsigned long flags; IRDA_DEBUG(0, __FUNCTION__"()\n"); @@ -1019,9 +1030,13 @@ /* ircomm_tty_flush_buffer(tty); */ ircomm_tty_shutdown(self); + /* I guess we need to lock here - Jean II */ + spin_lock_irqsave(&self->spinlock, flags); self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); self->tty = 0; self->open_count = 0; + spin_unlock_irqrestore(&self->spinlock, flags); + wake_up_interruptible(&self->open_wait); } @@ -1362,11 +1377,14 @@ struct ircomm_tty_cb *self; int count = 0, l; off_t begin = 0; + unsigned long flags; + + spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags); self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty); while ((self != NULL) && (count < 4000)) { if (self->magic != IRCOMM_TTY_MAGIC) - return 0; + break; l = ircomm_tty_line_info(self, buf + count); count += l; @@ -1381,6 +1399,8 @@ } *eof = 1; done: + spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags); + if (offset >= count+begin) return 0; *start = buf + (offset-begin); diff -Nru a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c --- a/net/irda/ircomm/ircomm_tty_attach.c Fri Sep 20 08:20:47 2002 +++ b/net/irda/ircomm/ircomm_tty_attach.c Fri Sep 20 08:20:47 2002 @@ -331,6 +331,8 @@ info.daddr = discovery->daddr; info.saddr = discovery->saddr; + /* FIXME. We probably need to use hashbin_find_next(), but we first + * need to ensure that "line" is unique. - Jean II */ self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty); while (self != NULL) { ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); diff -Nru a/net/irda/irda_device.c b/net/irda/irda_device.c --- a/net/irda/irda_device.c Fri Sep 20 08:20:46 2002 +++ b/net/irda/irda_device.c Fri Sep 20 08:20:46 2002 @@ -91,13 +91,13 @@ int __init irda_device_init( void) { - dongles = hashbin_new(HB_GLOBAL); + dongles = hashbin_new(HB_LOCK); if (dongles == NULL) { printk(KERN_WARNING "IrDA: Can't allocate dongles hashbin!\n"); return -ENOMEM; } - tasks = hashbin_new(HB_GLOBAL); + tasks = hashbin_new(HB_LOCK); if (tasks == NULL) { printk(KERN_WARNING "IrDA: Can't allocate tasks hashbin!\n"); return -ENOMEM; @@ -438,7 +438,7 @@ } #endif - if (!(reg = hashbin_find(dongles, type, NULL))) { + if (!(reg = hashbin_lock_find(dongles, type, NULL))) { ERROR("IrDA: Unable to find requested dongle\n"); return NULL; } @@ -477,7 +477,7 @@ int irda_device_register_dongle(struct dongle_reg *new) { /* Check if this dongle has been registred before */ - if (hashbin_find(dongles, new->type, NULL)) { + if (hashbin_lock_find(dongles, new->type, NULL)) { MESSAGE("%s: Dongle already registered\n", __FUNCTION__); return 0; } diff -Nru a/net/irda/iriap.c b/net/irda/iriap.c --- a/net/irda/iriap.c Fri Sep 20 08:20:44 2002 +++ b/net/irda/iriap.c Fri Sep 20 08:20:44 2002 @@ -58,7 +58,7 @@ #endif /* CONFIG_IRDA_DEBUG */ static hashbin_t *iriap = NULL; -static __u32 service_handle; +static void *service_handle; extern char *lmp_reasons[]; @@ -91,11 +91,12 @@ __u16 hints; /* Allocate master array */ - iriap = hashbin_new(HB_LOCAL); + iriap = hashbin_new(HB_LOCK); if (!iriap) return -ENOMEM; - objects = hashbin_new(HB_LOCAL); + /* Object repository - defined in irias_object.c */ + objects = hashbin_new(HB_LOCK); if (!objects) { WARNING("%s: Can't allocate objects hashbin!\n", __FUNCTION__); return -ENOMEM; @@ -182,7 +183,7 @@ init_timer(&self->watchdog_timer); - hashbin_insert(iriap, (irda_queue_t *) self, (int) self, NULL); + hashbin_insert(iriap, (irda_queue_t *) self, (long) self, NULL); /* Initialize state machines */ iriap_next_client_state(self, S_DISCONNECT); @@ -235,7 +236,7 @@ self->lsap = NULL; } - entry = (struct iriap_cb *) hashbin_remove(iriap, (int) self, NULL); + entry = (struct iriap_cb *) hashbin_remove(iriap, (long) self, NULL); ASSERT(entry == self, return;); __iriap_close(self); @@ -973,13 +974,12 @@ ASSERT( objects != NULL, return 0;); - save_flags( flags); - cli(); - len = 0; len += sprintf(buf+len, "LM-IAS Objects:\n"); + spin_lock_irqsave(&objects->hb_spinlock, flags); + /* List all objects */ obj = (struct ias_object *) hashbin_get_first(objects); while ( obj != NULL) { @@ -989,6 +989,11 @@ len += sprintf(buf+len, "id=%d", obj->id); len += sprintf(buf+len, "\n"); + /* Careful for priority inversions here ! + * All other uses of attrib spinlock are independant of + * the object spinlock, so we are safe. Jean II */ + spin_lock(&obj->attribs->hb_spinlock); + /* List all attributes for this object */ attrib = (struct ias_attrib *) hashbin_get_first(obj->attribs); @@ -1025,9 +1030,11 @@ attrib = (struct ias_attrib *) hashbin_get_next(obj->attribs); } + spin_unlock(&obj->attribs->hb_spinlock); + obj = (struct ias_object *) hashbin_get_next(objects); } - restore_flags(flags); + spin_unlock_irqrestore(&objects->hb_spinlock, flags); return len; } diff -Nru a/net/irda/irias_object.c b/net/irda/irias_object.c --- a/net/irda/irias_object.c Fri Sep 20 08:20:41 2002 +++ b/net/irda/irias_object.c Fri Sep 20 08:20:41 2002 @@ -93,7 +93,10 @@ obj->name = strndup(name, IAS_MAX_CLASSNAME); obj->id = id; - obj->attribs = hashbin_new(HB_LOCAL); + /* Locking notes : the attrib spinlock has lower precendence + * than the objects spinlock. Never grap the objects spinlock + * while holding any attrib spinlock (risk of deadlock). Jean II */ + obj->attribs = hashbin_new(HB_LOCK); return obj; } @@ -147,7 +150,7 @@ ASSERT(obj != NULL, return -1;); ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;); - node = hashbin_remove(objects, 0, obj->name); + node = hashbin_remove_this(objects, (irda_queue_t *) obj); if (!node) return 0; /* Already removed */ @@ -172,7 +175,7 @@ ASSERT(attrib != NULL, return -1;); /* Remove attribute from object */ - node = hashbin_remove(obj->attribs, 0, attrib->name); + node = hashbin_remove_this(obj->attribs, (irda_queue_t *) attrib); if (!node) return 0; /* Already removed or non-existent */ @@ -211,7 +214,8 @@ { ASSERT(name != NULL, return NULL;); - return hashbin_find(objects, 0, name); + /* Unsafe (locking), object might change */ + return hashbin_lock_find(objects, 0, name); } /* @@ -228,10 +232,11 @@ ASSERT(obj->magic == IAS_OBJECT_MAGIC, return NULL;); ASSERT(name != NULL, return NULL;); - attrib = hashbin_find(obj->attribs, 0, name); + attrib = hashbin_lock_find(obj->attribs, 0, name); if (attrib == NULL) return NULL; + /* Unsafe (locking), attrib might change */ return attrib; } @@ -267,26 +272,32 @@ { struct ias_object *obj; struct ias_attrib *attrib; + unsigned long flags; /* Find object */ - obj = hashbin_find(objects, 0, obj_name); + obj = hashbin_lock_find(objects, 0, obj_name); if (obj == NULL) { WARNING("%s: Unable to find object: %s\n", __FUNCTION__, obj_name); return -1; } + /* Slightly unsafe (obj might get removed under us) */ + spin_lock_irqsave(&obj->attribs->hb_spinlock, flags); + /* Find attribute */ attrib = hashbin_find(obj->attribs, 0, attrib_name); if (attrib == NULL) { WARNING("%s: Unable to find attribute: %s\n", __FUNCTION__, attrib_name); + spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); return -1; } if ( attrib->value->type != new_value->type) { IRDA_DEBUG( 0, __FUNCTION__ "(), changing value type not allowed!\n"); + spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); return -1; } @@ -297,6 +308,7 @@ attrib->value = new_value; /* Success */ + spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); return 0; } diff -Nru a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c --- a/net/irda/irlan/irlan_common.c Fri Sep 20 08:20:46 2002 +++ b/net/irda/irlan/irlan_common.c Fri Sep 20 08:20:46 2002 @@ -124,7 +124,7 @@ IRDA_DEBUG(0, __FUNCTION__ "()\n"); /* Allocate master structure */ - irlan = hashbin_new(HB_LOCAL); + irlan = hashbin_new(HB_LOCK); /* protect from /proc */ if (irlan == NULL) { printk(KERN_WARNING "IrLAN: Can't allocate hashbin!\n"); return -ENOMEM; @@ -1089,11 +1089,10 @@ unsigned long flags; ASSERT(irlan != NULL, return 0;); - save_flags(flags); - cli(); - len = 0; + spin_lock_irqsave(&irlan->hb_spinlock, flags); + len += sprintf(buf+len, "IrLAN instances:\n"); self = (struct irlan_cb *) hashbin_get_first(irlan); @@ -1129,7 +1128,7 @@ self = (struct irlan_cb *) hashbin_get_next(irlan); } - restore_flags(flags); + spin_unlock_irqrestore(&irlan->hb_spinlock, flags); return len; } diff -Nru a/net/irda/irlap.c b/net/irda/irlap.c --- a/net/irda/irlap.c Fri Sep 20 08:20:47 2002 +++ b/net/irda/irlap.c Fri Sep 20 08:20:47 2002 @@ -80,7 +80,7 @@ int __init irlap_init(void) { /* Allocate master array */ - irlap = hashbin_new(HB_LOCAL); + irlap = hashbin_new(HB_LOCK); if (irlap == NULL) { ERROR("%s: can't allocate irlap hashbin!\n", __FUNCTION__); return -ENOMEM; @@ -139,7 +139,15 @@ skb_queue_head_init(&self->wx_list); /* My unique IrLAP device address! */ - get_random_bytes(&self->saddr, sizeof(self->saddr)); + /* We don't want the broadcast address, neither the NULL address + * (most often used to signify "invalid"), and we don't want an + * address already in use (otherwise connect won't be able + * to select the proper link). - Jean II */ + do { + get_random_bytes(&self->saddr, sizeof(self->saddr)); + } while ((self->saddr == 0x0) || (self->saddr == BROADCAST) || + (hashbin_lock_find(irlap, self->saddr, NULL)) ); + /* Copy to the driver */ memcpy(dev->dev_addr, &self->saddr, 4); init_timer(&self->slot_timer); @@ -522,7 +530,8 @@ self->discovery_log = NULL; } - self->discovery_log= hashbin_new(HB_LOCAL); + /* All operations will occur at predictable time, no need to lock */ + self->discovery_log= hashbin_new(HB_NOLOCK); info.S = discovery->nslots; /* Number of slots */ info.s = 0; /* Current slot */ @@ -1084,15 +1093,14 @@ unsigned long flags; int i = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&irlap->hb_spinlock, flags); len = 0; self = (struct irlap_cb *) hashbin_get_first(irlap); while (self != NULL) { - ASSERT(self != NULL, return -ENODEV;); - ASSERT(self->magic == LAP_MAGIC, return -EBADR;); + ASSERT(self != NULL, break;); + ASSERT(self->magic == LAP_MAGIC, break;); len += sprintf(buf+len, "irlap%d ", i++); len += sprintf(buf+len, "state: %s\n", @@ -1164,7 +1172,7 @@ self = (struct irlap_cb *) hashbin_get_next(irlap); } - restore_flags(flags); + spin_unlock_irqrestore(&irlap->hb_spinlock, flags); return len; } diff -Nru a/net/irda/irlmp.c b/net/irda/irlmp.c --- a/net/irda/irlmp.c Fri Sep 20 08:20:47 2002 +++ b/net/irda/irlmp.c Fri Sep 20 08:20:47 2002 @@ -83,13 +83,13 @@ memset(irlmp, 0, sizeof(struct irlmp_cb)); irlmp->magic = LMP_MAGIC; - spin_lock_init(&irlmp->log_lock); - irlmp->clients = hashbin_new(HB_GLOBAL); - irlmp->services = hashbin_new(HB_GLOBAL); - irlmp->links = hashbin_new(HB_GLOBAL); - irlmp->unconnected_lsaps = hashbin_new(HB_GLOBAL); - irlmp->cachelog = hashbin_new(HB_GLOBAL); + irlmp->clients = hashbin_new(HB_LOCK); + irlmp->services = hashbin_new(HB_LOCK); + irlmp->links = hashbin_new(HB_LOCK); + irlmp->unconnected_lsaps = hashbin_new(HB_LOCK); + irlmp->cachelog = hashbin_new(HB_NOLOCK); + spin_lock_init(&irlmp->cachelog->hb_spinlock); irlmp->free_lsap_sel = 0x10; /* Reserved 0x00-0x0f */ strcpy(sysctl_devname, "Linux"); @@ -177,8 +177,8 @@ self->lsap_state = LSAP_DISCONNECTED; /* Insert into queue of unconnected LSAPs */ - hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self, - NULL); + hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, + (long) self, NULL); return self; } @@ -238,7 +238,7 @@ LM_LAP_DISCONNECT_REQUEST, NULL); } /* Now, remove from the link */ - lsap = hashbin_remove(lap->lsaps, (int) self, NULL); + lsap = hashbin_remove(lap->lsaps, (long) self, NULL); #ifdef CONFIG_IRDA_CACHE_LAST_LSAP lap->cache.valid = FALSE; #endif @@ -246,7 +246,7 @@ self->lap = NULL; /* Check if we found the LSAP! If not then try the unconnected lsaps */ if (!lsap) { - lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self, + lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL); } if (!lsap) { @@ -286,7 +286,7 @@ lap->magic = LMP_LAP_MAGIC; lap->saddr = saddr; lap->daddr = DEV_ADDR_ANY; - lap->lsaps = hashbin_new(HB_GLOBAL); + lap->lsaps = hashbin_new(HB_LOCK); #ifdef CONFIG_IRDA_CACHE_LAST_LSAP lap->cache.valid = FALSE; #endif @@ -347,7 +347,6 @@ struct sk_buff *skb = NULL; struct lap_cb *lap; struct lsap_cb *lsap; - discovery_t *discovery; ASSERT(self != NULL, return -EBADR;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;); @@ -388,6 +387,10 @@ * device with the given daddr */ if ((!saddr) || (saddr == DEV_ADDR_ANY)) { + discovery_t *discovery; + unsigned long flags; + + spin_lock_irqsave(&irlmp->cachelog->hb_spinlock, flags); if (daddr != DEV_ADDR_ANY) discovery = hashbin_find(irlmp->cachelog, daddr, NULL); else { @@ -400,8 +403,9 @@ saddr = discovery->saddr; daddr = discovery->daddr; } + spin_unlock_irqrestore(&irlmp->cachelog->hb_spinlock, flags); } - lap = hashbin_find(irlmp->links, saddr, NULL); + lap = hashbin_lock_find(irlmp->links, saddr, NULL); if (lap == NULL) { IRDA_DEBUG(1, __FUNCTION__ "(), Unable to find a usable link!\n"); return -EHOSTUNREACH; @@ -411,11 +415,8 @@ if (lap->daddr == DEV_ADDR_ANY) lap->daddr = daddr; else if (lap->daddr != daddr) { - struct lsap_cb *any_lsap; - /* Check if some LSAPs are active on this LAP */ - any_lsap = (struct lsap_cb *) hashbin_get_first(lap->lsaps); - if (any_lsap == NULL) { + if (HASHBIN_GET_SIZE(lap->lsaps) == 0) { /* No active connection, but LAP hasn't been * disconnected yet (waiting for timeout in LAP). * Maybe we could give LAP a bit of help in this case. @@ -436,14 +437,15 @@ * Remove LSAP from list of unconnected LSAPs and insert it into the * list of connected LSAPs for the particular link */ - lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self, NULL); + lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL); ASSERT(lsap != NULL, return -1;); ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;); ASSERT(lsap->lap != NULL, return -1;); ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;); - hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (int) self, NULL); + hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (long) self, + NULL); set_bit(0, &self->connected); /* TRUE */ @@ -574,29 +576,41 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance) { struct lsap_cb *new; + unsigned long flags; IRDA_DEBUG(1, __FUNCTION__ "()\n"); + spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); + /* Only allowed to duplicate unconnected LSAP's */ - if (!hashbin_find(irlmp->unconnected_lsaps, (int) orig, NULL)) { + if (!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) { IRDA_DEBUG(0, __FUNCTION__ "(), unable to find LSAP\n"); + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, + flags); return NULL; } + /* Allocate a new instance */ new = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC); if (!new) { IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n"); + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, + flags); return NULL; } /* Dup */ memcpy(new, orig, sizeof(struct lsap_cb)); - new->notify.instance = instance; /* new->lap = orig->lap; => done in the memcpy() */ /* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */ + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); + + /* Not everything is the same */ + new->notify.instance = instance; + init_timer(&new->watchdog_timer); - hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new, (int) new, - NULL); + hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new, + (long) new, NULL); /* Make sure that we invalidate the cache */ #ifdef CONFIG_IRDA_CACHE_LAST_LSAP @@ -646,7 +660,7 @@ ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;); ASSERT(self->lap->lsaps != NULL, return -1;); - lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL); + lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL); #ifdef CONFIG_IRDA_CACHE_LAST_LSAP self->lap->cache.valid = FALSE; #endif @@ -655,8 +669,8 @@ ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;); ASSERT(lsap == self, return -1;); - hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self, - NULL); + hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, + (long) self, NULL); /* Reset some values */ self->dlsap_sel = LSAP_ANY; @@ -699,15 +713,15 @@ ASSERT(self->lap != NULL, return;); ASSERT(self->lap->lsaps != NULL, return;); - lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL); + lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL); #ifdef CONFIG_IRDA_CACHE_LAST_LSAP self->lap->cache.valid = FALSE; #endif ASSERT(lsap != NULL, return;); ASSERT(lsap == self, return;); - hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, (int) lsap, - NULL); + hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, + (long) lsap, NULL); self->dlsap_sel = LSAP_ANY; self->lap = NULL; @@ -886,7 +900,7 @@ */ while ((service = service_log[i++]) != S_END) { IRDA_DEBUG( 4, "service=%02x\n", service); - client = hashbin_find(irlmp->registry, service, NULL); + client = hashbin_lock_find(irlmp->registry, service, NULL); if (entry && entry->discovery_callback) { IRDA_DEBUG( 4, "discovery_callback!\n"); @@ -903,6 +917,7 @@ kfree(service_log); } #endif + /* * Function irlmp_notify_client (log) * @@ -930,6 +945,12 @@ /* * Now, check all discovered devices (if any), and notify client * only about the services that the client is interested in + * Note : most often, we will get called immediately following + * a discovery, so the log is not going to expire. + * On the other hand, comming here through irlmp_discovery_request() + * is *very* problematic - Jean II + * Can't use hashbin_find_next(), key is not unique. I'm running + * out of options :-( - Jean II */ discovery = (discovery_t *) hashbin_get_first(log); while (discovery != NULL) { @@ -956,6 +977,7 @@ void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode) { irlmp_client_t *client; + irlmp_client_t *client_next; IRDA_DEBUG(3, __FUNCTION__ "()\n"); @@ -965,11 +987,12 @@ return; client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); - while (client != NULL) { + while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL, + (void *) &client_next) ) { /* Check if we should notify client */ irlmp_notify_client(client, log, mode); - client = (irlmp_client_t *) hashbin_get_next(irlmp->clients); + client = client_next; } } @@ -987,13 +1010,15 @@ void irlmp_discovery_expiry(discovery_t *expiry) { irlmp_client_t *client; + irlmp_client_t *client_next; IRDA_DEBUG(3, __FUNCTION__ "()\n"); ASSERT(expiry != NULL, return;); client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); - while (client != NULL) { + while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL, + (void *) &client_next) ) { /* Check if we should notify client */ if ((client->expir_callback) && (client->hint_mask & expiry->hints.word & 0x7f7f)) @@ -1001,7 +1026,7 @@ client->priv); /* Next client */ - client = (irlmp_client_t *) hashbin_get_next(irlmp->clients); + client = client_next; } } @@ -1196,11 +1221,9 @@ struct lsap_cb *curr; /* Send status_indication to all LSAPs using this link */ - next = (struct lsap_cb *) hashbin_get_first( self->lsaps); - while (next != NULL ) { - curr = next; - next = (struct lsap_cb *) hashbin_get_next(self->lsaps); - + curr = (struct lsap_cb *) hashbin_get_first( self->lsaps); + while (NULL != hashbin_find_next(self->lsaps, (long) curr, NULL, + (void *) &next) ) { ASSERT(curr->magic == LMP_LSAP_MAGIC, return;); /* * Inform service user if he has requested it @@ -1210,6 +1233,8 @@ link, lock); else IRDA_DEBUG(2, __FUNCTION__ "(), no handler\n"); + + curr = next; } } @@ -1245,29 +1270,15 @@ (IRLAP_GET_TX_QUEUE_LEN(self->irlap) < LAP_HIGH_THRESHOLD)) { /* Try to find the next lsap we should poll. */ next = self->flow_next; - if(next != NULL) { - /* Note that if there is only one LSAP on the LAP - * (most common case), self->flow_next is always NULL, - * so we always avoid this loop. - Jean II */ - IRDA_DEBUG(4, __FUNCTION__ "() : searching my LSAP\n"); - - /* We look again in hashbins, because the lsap - * might have gone away... - Jean II */ - curr = (struct lsap_cb *) hashbin_get_first(self->lsaps); - while((curr != NULL ) && (curr != next)) - curr = (struct lsap_cb *) hashbin_get_next(self->lsaps); - } else - curr = NULL; - /* If we have no lsap, restart from first one */ - if(curr == NULL) - curr = (struct lsap_cb *) hashbin_get_first(self->lsaps); + if(next == NULL) + next = (struct lsap_cb *) hashbin_get_first(self->lsaps); + /* Verify current one and find the next one */ + curr = hashbin_find_next(self->lsaps, (long) next, NULL, + (void *) &self->flow_next); /* Uh-oh... Paranoia */ if(curr == NULL) break; - - /* Next time, we will get the next one (or the first one) */ - self->flow_next = (struct lsap_cb *) hashbin_get_next(self->lsaps); IRDA_DEBUG(4, __FUNCTION__ "() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap)); /* Inform lsap user that it can send one more packet. */ @@ -1414,20 +1425,12 @@ * Register local service with IrLMP * */ -__u32 irlmp_register_service(__u16 hints) +void *irlmp_register_service(__u16 hints) { irlmp_service_t *service; - __u32 handle; IRDA_DEBUG(4, __FUNCTION__ "(), hints = %04x\n", hints); - /* Get a unique handle for this service */ - get_random_bytes(&handle, sizeof(handle)); - while (hashbin_find(irlmp->services, handle, NULL) || !handle) - get_random_bytes(&handle, sizeof(handle)); - - irlmp->hints.word |= hints; - /* Make a new registration */ service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC); if (!service) { @@ -1435,9 +1438,12 @@ return 0; } service->hints = hints; - hashbin_insert(irlmp->services, (irda_queue_t *) service, handle, NULL); + hashbin_insert(irlmp->services, (irda_queue_t *) service, + (long) service, NULL); + + irlmp->hints.word |= hints; - return handle; + return (void *)service; } /* @@ -1447,35 +1453,38 @@ * * Returns: 0 on success, -1 on error */ -int irlmp_unregister_service(__u32 handle) +int irlmp_unregister_service(void *handle) { irlmp_service_t *service; + unsigned long flags; IRDA_DEBUG(4, __FUNCTION__ "()\n"); if (!handle) return -1; - service = hashbin_find(irlmp->services, handle, NULL); + /* Caller may call with invalid handle (it's legal) - Jean II */ + service = hashbin_lock_find(irlmp->services, (long) handle, NULL); if (!service) { IRDA_DEBUG(1, __FUNCTION__ "(), Unknown service!\n"); return -1; } - service = hashbin_remove(irlmp->services, handle, NULL); - if (service) - kfree(service); + hashbin_remove_this(irlmp->services, (irda_queue_t *) service); + kfree(service); /* Remove old hint bits */ irlmp->hints.word = 0; /* Refresh current hint bits */ + spin_lock_irqsave(&irlmp->services->hb_spinlock, flags); service = (irlmp_service_t *) hashbin_get_first(irlmp->services); while (service) { irlmp->hints.word |= service->hints; service = (irlmp_service_t *)hashbin_get_next(irlmp->services); } + spin_unlock_irqrestore(&irlmp->services->hb_spinlock, flags); return 0; } @@ -1488,20 +1497,14 @@ * * Returns: handle > 0 on success, 0 on error */ -__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, +void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, DISCOVERY_CALLBACK1 expir_clb, void *priv) { irlmp_client_t *client; - __u32 handle; IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(irlmp != NULL, return 0;); - /* Get a unique handle for this client */ - get_random_bytes(&handle, sizeof(handle)); - while (hashbin_find(irlmp->clients, handle, NULL) || !handle) - get_random_bytes(&handle, sizeof(handle)); - /* Make a new registration */ client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC); if (!client) { @@ -1515,9 +1518,10 @@ client->expir_callback = expir_clb; client->priv = priv; - hashbin_insert(irlmp->clients, (irda_queue_t *) client, handle, NULL); + hashbin_insert(irlmp->clients, (irda_queue_t *) client, + (long) client, NULL); - return handle; + return (void *) client; } /* @@ -1528,7 +1532,7 @@ * * Returns: 0 on success, -1 on error */ -int irlmp_update_client(__u32 handle, __u16 hint_mask, +int irlmp_update_client(void *handle, __u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, DISCOVERY_CALLBACK1 expir_clb, void *priv) { @@ -1537,7 +1541,7 @@ if (!handle) return -1; - client = hashbin_find(irlmp->clients, handle, NULL); + client = hashbin_lock_find(irlmp->clients, (long) handle, NULL); if (!client) { IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n"); return -1; @@ -1557,7 +1561,7 @@ * Returns: 0 on success, -1 on error * */ -int irlmp_unregister_client(__u32 handle) +int irlmp_unregister_client(void *handle) { struct irlmp_client *client; @@ -1566,16 +1570,16 @@ if (!handle) return -1; - client = hashbin_find(irlmp->clients, handle, NULL); + /* Caller may call with invalid handle (it's legal) - Jean II */ + client = hashbin_lock_find(irlmp->clients, (long) handle, NULL); if (!client) { IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n"); return -1; } IRDA_DEBUG( 4, __FUNCTION__ "(), removing client!\n"); - client = hashbin_remove( irlmp->clients, handle, NULL); - if (client) - kfree(client); + hashbin_remove_this(irlmp->clients, (irda_queue_t *) client); + kfree(client); return 0; } @@ -1589,6 +1593,7 @@ { struct lsap_cb *self; struct lap_cb *lap; + unsigned long flags; ASSERT(irlmp != NULL, return TRUE;); ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;); @@ -1611,10 +1616,16 @@ * every IrLAP connection and check every LSAP assosiated with each * the connection. */ + spin_lock_irqsave(&irlmp->links->hb_spinlock, flags); lap = (struct lap_cb *) hashbin_get_first(irlmp->links); while (lap != NULL) { ASSERT(lap->magic == LMP_LAP_MAGIC, return TRUE;); + /* Careful for priority inversions here ! + * All other uses of attrib spinlock are independant of + * the object spinlock, so we are safe. Jean II */ + spin_lock(&lap->lsaps->hb_spinlock); + self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); while (self != NULL) { ASSERT(self->magic == LMP_LSAP_MAGIC, return TRUE;); @@ -1626,8 +1637,11 @@ } self = (struct lsap_cb*) hashbin_get_next(lap->lsaps); } + spin_unlock(&lap->lsaps->hb_spinlock); + /* Next LAP */ lap = (struct lap_cb *) hashbin_get_next(irlmp->links); } + spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags); return FALSE; } @@ -1736,15 +1750,13 @@ ASSERT(irlmp != NULL, return 0;); - save_flags( flags); - cli(); - len = 0; len += sprintf( buf+len, "Unconnected LSAPs:\n"); + spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); self = (struct lsap_cb *) hashbin_get_first( irlmp->unconnected_lsaps); while (self != NULL) { - ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;); + ASSERT(self->magic == LMP_LSAP_MAGIC, break;); len += sprintf(buf+len, "lsap state: %s, ", irlsap_state[ self->lsap_state]); len += sprintf(buf+len, @@ -1756,9 +1768,10 @@ self = (struct lsap_cb *) hashbin_get_next( irlmp->unconnected_lsaps); } + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); len += sprintf(buf+len, "\nRegistred Link Layers:\n"); - + spin_lock_irqsave(&irlmp->links->hb_spinlock, flags); lap = (struct lap_cb *) hashbin_get_first(irlmp->links); while (lap != NULL) { len += sprintf(buf+len, "lap state: %s, ", @@ -1770,10 +1783,15 @@ HASHBIN_GET_SIZE(lap->lsaps)); len += sprintf(buf+len, "\n"); + /* Careful for priority inversions here ! + * All other uses of attrib spinlock are independant of + * the object spinlock, so we are safe. Jean II */ + spin_lock(&lap->lsaps->hb_spinlock); + len += sprintf(buf+len, "\n Connected LSAPs:\n"); self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); while (self != NULL) { - ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;); + ASSERT(self->magic == LMP_LSAP_MAGIC, break;); len += sprintf(buf+len, " lsap state: %s, ", irlsap_state[ self->lsap_state]); len += sprintf(buf+len, @@ -1785,11 +1803,12 @@ self = (struct lsap_cb *) hashbin_get_next( lap->lsaps); } + spin_unlock(&lap->lsaps->hb_spinlock); len += sprintf(buf+len, "\n"); lap = (struct lap_cb *) hashbin_get_next(irlmp->links); } - restore_flags(flags); + spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags); return len; } diff -Nru a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c --- a/net/irda/irlmp_event.c Fri Sep 20 08:20:43 2002 +++ b/net/irda/irlmp_event.c Fri Sep 20 08:20:43 2002 @@ -207,6 +207,43 @@ irlmp_do_lap_event(self, LM_LAP_IDLE_TIMEOUT, NULL); } +/* + * Send an event on all LSAPs attached to this LAP. + */ +static inline void +irlmp_do_all_lsap_event(hashbin_t * lsap_hashbin, + IRLMP_EVENT event) +{ + struct lsap_cb *lsap; + struct lsap_cb *lsap_next; + + /* Note : this function use the new hashbin_find_next() + * function, instead of the old hashbin_get_next(). + * This make sure that we are always pointing one lsap + * ahead, so that if the current lsap is removed as the + * result of sending the event, we don't care. + * Also, as we store the context ourselves, if an enumeration + * of the same lsap hashbin happens as the result of sending the + * event, we don't care. + * The only problem is if the next lsap is removed. In that case, + * hashbin_find_next() will return NULL and we will abort the + * enumeration. - Jean II */ + + /* Also : we don't accept any skb in input. We can *NOT* pass + * the same skb to multiple clients safely, we would need to + * skb_clone() it. - Jean II */ + + lsap = (struct lsap_cb *) hashbin_get_first(lsap_hashbin); + + while (NULL != hashbin_find_next(lsap_hashbin, + (long) lsap, + NULL, + (void *) &lsap_next) ) { + irlmp_do_lsap_event(lsap, event, NULL); + lsap = lsap_next; + } +} + /********************************************************************* * * LAP connection control states @@ -274,9 +311,6 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, struct sk_buff *skb) { - struct lsap_cb *lsap; - struct lsap_cb *lsap_current; - IRDA_DEBUG(2, __FUNCTION__ "(), event=%s\n", irlmp_event[event]); switch (event) { @@ -290,11 +324,9 @@ /* Just accept connection TODO, this should be fixed */ irlap_connect_response(self->irlap, skb); - lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps); - while (lsap != NULL) { - irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL); - lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps); - } + /* Tell LSAPs that they can start sending data */ + irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM); + /* Note : by the time we get there (LAP retries and co), * the lsaps may already have gone. This avoid getting stuck * forever in LAP_ACTIVE state - Jean II */ @@ -310,11 +342,9 @@ /* For all lsap_ce E Associated do LS_Connect_confirm */ irlmp_next_lap_state(self, LAP_ACTIVE); - lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps); - while (lsap != NULL) { - irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL); - lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps); - } + /* Tell LSAPs that they can start sending data */ + irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM); + /* Note : by the time we get there (LAP retries and co), * the lsaps may already have gone. This avoid getting stuck * forever in LAP_ACTIVE state - Jean II */ @@ -328,18 +358,8 @@ irlmp_next_lap_state(self, LAP_STANDBY); /* Send disconnect event to all LSAPs using this link */ - lsap = (struct lsap_cb *) hashbin_get_first( self->lsaps); - while (lsap != NULL ) { - ASSERT(lsap->magic == LMP_LSAP_MAGIC, return;); - - lsap_current = lsap; - - /* Be sure to stay one item ahead */ - lsap = (struct lsap_cb *) hashbin_get_next(self->lsaps); - irlmp_do_lsap_event(lsap_current, - LM_LAP_DISCONNECT_INDICATION, - NULL); - } + irlmp_do_all_lsap_event(self->lsaps, + LM_LAP_DISCONNECT_INDICATION); break; case LM_LAP_DISCONNECT_REQUEST: IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n"); @@ -368,9 +388,6 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, struct sk_buff *skb) { - struct lsap_cb *lsap; - struct lsap_cb *lsap_current; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); switch (event) { @@ -383,22 +400,11 @@ * notify all LSAPs using this LAP, but that should be safe to * do anyway. */ - lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps); - while (lsap != NULL) { - irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL); - lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps); - } + irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM); /* Needed by connect indication */ - lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps); - while (lsap != NULL) { - lsap_current = lsap; - - /* Be sure to stay one item ahead */ - lsap = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps); - irlmp_do_lsap_event(lsap_current, - LM_LAP_CONNECT_CONFIRM, NULL); - } + irlmp_do_all_lsap_event(irlmp->unconnected_lsaps, + LM_LAP_CONNECT_CONFIRM); /* Keep state */ break; case LM_LAP_DISCONNECT_REQUEST: @@ -447,18 +453,8 @@ /* * Inform all connected LSAP's using this link */ - lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps); - while (lsap != NULL ) { - ASSERT(lsap->magic == LMP_LSAP_MAGIC, return;); - - lsap_current = lsap; - - /* Be sure to stay one item ahead */ - lsap = (struct lsap_cb *) hashbin_get_next(self->lsaps); - irlmp_do_lsap_event(lsap_current, - LM_LAP_DISCONNECT_INDICATION, - NULL); - } + irlmp_do_all_lsap_event(self->lsaps, + LM_LAP_DISCONNECT_INDICATION); /* Force an expiry of the discovery log. * Now that the LAP is free, the system may attempt to @@ -581,15 +577,15 @@ * Bind this LSAP to the IrLAP link where the connect was * received */ - lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self, + lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL); ASSERT(lsap == self, return -1;); ASSERT(self->lap != NULL, return -1;); ASSERT(self->lap->lsaps != NULL, return -1;); - hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (int) self, - NULL); + hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, + (long) self, NULL); irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, self->slsap_sel, CONNECT_CNF, skb); diff -Nru a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c --- a/net/irda/irlmp_frame.c Fri Sep 20 08:20:47 2002 +++ b/net/irda/irlmp_frame.c Fri Sep 20 08:20:47 2002 @@ -210,6 +210,7 @@ __u8 dlsap_sel; /* Destination LSAP address */ __u8 pid; /* Protocol identifier */ __u8 *fp; + unsigned long flags; IRDA_DEBUG(4, __FUNCTION__ "()\n"); @@ -242,6 +243,8 @@ return; } + /* Search the connectionless LSAP */ + spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps); while (lsap != NULL) { /* @@ -255,6 +258,8 @@ } lsap = (struct lsap_cb *) hashbin_get_next(irlmp->unconnected_lsaps); } + spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); + if (lsap) irlmp_connless_data_indication(lsap, skb); else { @@ -374,6 +379,7 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LAP_MAGIC, return;); + /* Add to main log, cleanup */ irlmp_add_discovery(irlmp->cachelog, discovery); /* Just handle it the same way as a discovery confirm, @@ -396,6 +402,7 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LAP_MAGIC, return;); + /* Add to main log, cleanup */ irlmp_add_discovery_log(irlmp->cachelog, log); /* Propagate event to various LSAPs registered for it. @@ -411,6 +418,8 @@ static inline void irlmp_update_cache(struct lap_cb *lap, struct lsap_cb *lsap) { + /* Prevent concurent read to get garbage */ + lap->cache.valid = FALSE; /* Update cache entry */ lap->cache.dlsap_sel = lsap->dlsap_sel; lap->cache.slsap_sel = lsap->slsap_sel; @@ -441,6 +450,7 @@ hashbin_t *queue) { struct lsap_cb *lsap; + unsigned long flags; /* * Optimize for the common case. We assume that the last frame @@ -455,6 +465,9 @@ return (self->cache.lsap); } #endif + + spin_lock_irqsave(&queue->hb_spinlock, flags); + lsap = (struct lsap_cb *) hashbin_get_first(queue); while (lsap != NULL) { /* @@ -465,29 +478,27 @@ */ if ((status == CONNECT_CMD) && (lsap->slsap_sel == slsap_sel) && - (lsap->dlsap_sel == LSAP_ANY)) - { + (lsap->dlsap_sel == LSAP_ANY)) { + /* This is where the dest lsap sel is set on incomming + * lsaps */ lsap->dlsap_sel = dlsap_sel; - -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP - irlmp_update_cache(self, lsap); -#endif - return lsap; + break; } /* * Check if source LSAP and dest LSAP selectors match. */ if ((lsap->slsap_sel == slsap_sel) && (lsap->dlsap_sel == dlsap_sel)) - { -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP - irlmp_update_cache(self, lsap); -#endif - return lsap; - } + break; + lsap = (struct lsap_cb *) hashbin_get_next(queue); } +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP + if(lsap) + irlmp_update_cache(self, lsap); +#endif + spin_unlock_irqrestore(&queue->hb_spinlock, flags); - /* Sorry not found! */ - return NULL; + /* Return what we've found or NULL */ + return lsap; } diff -Nru a/net/irda/irqueue.c b/net/irda/irqueue.c --- a/net/irda/irqueue.c Fri Sep 20 08:20:43 2002 +++ b/net/irda/irqueue.c Fri Sep 20 08:20:43 2002 @@ -34,11 +34,412 @@ * ********************************************************************/ +/* + * NOTE : + * There are various problems with this package : + * o the hash function for ints is pathetic (but could be changed) + * o locking is sometime suspicious (especially during enumeration) + * o most users have only a few elements (== overhead) + * o most users never use seach, so don't benefit from hashing + * Problem already fixed : + * o not 64 bit compliant (most users do hashv = (int) self) + * o hashbin_remove() is broken => use hashbin_remove_this() + * I think most users would be better served by a simple linked list + * (like include/linux/list.h) with a global spinlock per list. + * Jean II + */ + +/* + * Notes on the concurent access to hashbin and other SMP issues + * ------------------------------------------------------------- + * Hashbins are very often in the IrDA stack a global repository of + * information, and therefore used in a very asynchronous manner following + * various events (driver calls, timers, user calls...). + * Therefore, very often it is highly important to consider the + * management of concurent access to the hashbin and how to guarantee the + * consistency of the operations on it. + * + * First, we need to define the objective of locking : + * 1) Protect user data (content pointed by the hashbin) + * 2) Protect hashbin structure itself (linked list in each bin) + * + * OLD LOCKING + * ----------- + * + * The previous locking strategy, either HB_LOCAL or HB_GLOBAL were + * both inadequate in *both* aspect. + * o HB_GLOBAL was using a spinlock for each bin (local locking). + * o HB_LOCAL was disabling irq on *all* CPUs, so use a single + * global semaphore. + * The problems were : + * A) Global irq disabling is no longer supported by the kernel + * B) No protection for the hashbin struct global data + * o hashbin_delete() + * o hb_current + * C) No protection for user data in some cases + * + * A) HB_LOCAL use global irq disabling, so doesn't work on kernel + * 2.5.X. Even when it is supported (kernel 2.4.X and earlier), its + * performance is not satisfactory on SMP setups. Most hashbins were + * HB_LOCAL, so (A) definitely need fixing. + * B) HB_LOCAL could be modified to fix (B). However, because HB_GLOBAL + * lock only the individual bins, it will never be able to lock the + * global data, so can't do (B). + * C) Some functions return pointer to data that is still in the + * hashbin : + * o hashbin_find() + * o hashbin_get_first() + * o hashbin_get_next() + * As the data is still in the hashbin, it may be changed or free'd + * while the caller is examinimg the data. In those case, locking can't + * be done within the hashbin, but must include use of the data within + * the caller. + * The caller can easily do this with HB_LOCAL (just disable irqs). + * However, this is impossible with HB_GLOBAL because the caller has no + * way to know the proper bin, so don't know which spinlock to use. + * + * Quick summary : can no longer use HB_LOCAL, and HB_GLOBAL is + * fundamentally broken and will never work. + * + * NEW LOCKING + * ----------- + * + * To fix those problems, I've introduce a few changes in the + * hashbin locking : + * 1) New HB_LOCK scheme + * 2) hashbin->hb_spinlock + * 3) New hashbin usage policy + * + * HB_LOCK : + * ------- + * HB_LOCK is a locking scheme intermediate between the old HB_LOCAL + * and HB_GLOBAL. It uses a single spinlock to protect the whole content + * of the hashbin. As it is a single spinlock, it can protect the global + * data of the hashbin and not only the bins themselves. + * HB_LOCK can only protect some of the hashbin calls, so it only lock + * call that can be made 100% safe and leave other call unprotected. + * HB_LOCK in theory is slower than HB_GLOBAL, but as the hashbin + * content is always small contention is not high, so it doesn't matter + * much. HB_LOCK is probably faster than HB_LOCAL. + * + * hashbin->hb_spinlock : + * -------------------- + * The spinlock that HB_LOCK uses is available for caller, so that + * the caller can protect unprotected calls (see below). + * If the caller want to do entirely its own locking (HB_NOLOCK), he + * can do so and may use safely this spinlock. + * Locking is done like this : + * spin_lock_irqsave(&hashbin->hb_spinlock, flags); + * Releasing the lock : + * spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + * + * Safe & Protected calls : + * ---------------------- + * The following calls are safe or protected via HB_LOCK : + * o hashbin_new() -> safe + * o hashbin_delete() + * o hashbin_insert() + * o hashbin_remove_first() + * o hashbin_remove() + * o hashbin_remove_this() + * o HASHBIN_GET_SIZE() -> atomic + * + * The following calls only protect the hashbin itself : + * o hashbin_lock_find() + * o hashbin_find_next() + * + * Unprotected calls : + * ----------------- + * The following calls need to be protected by the caller : + * o hashbin_find() + * o hashbin_get_first() + * o hashbin_get_next() + * + * Locking Policy : + * -------------- + * If the hashbin is used only in a single thread of execution + * (explicitely or implicitely), you can use HB_NOLOCK + * If the calling module already provide concurent access protection, + * you may use HB_NOLOCK. + * + * In all other cases, you need to use HB_LOCK and lock the hashbin + * everytime before calling one of the unprotected calls. You also must + * use the pointer returned by the unprotected call within the locked + * region. + * + * Extra care for enumeration : + * -------------------------- + * hashbin_get_first() and hashbin_get_next() use the hashbin to + * store the current position, in hb_current. + * As long as the hashbin remains locked, this is safe. If you unlock + * the hashbin, the current position may change if anybody else modify + * or enumerate the hashbin. + * Summary : do the full enumeration while locked. + * + * Alternatively, you may use hashbin_find_next(). But, this will + * be slower, is more complex to use and doesn't protect the hashbin + * content. So, care is needed here as well. + * + * Other issues : + * ------------ + * I believe that we are overdoing it by using spin_lock_irqsave() + * and we should use only spin_lock_bh() or similar. But, I don't have + * the balls to try it out. + * Don't believe that because hashbin are now (somewhat) SMP safe + * that the rest of the code is. Higher layers tend to be safest, + * but LAP and LMP would need some serious dedicated love. + * + * Jean II + */ + #include #include -static irda_queue_t *dequeue_general( irda_queue_t **queue, irda_queue_t* element); -static __u32 hash( char* name); +/************************ QUEUE SUBROUTINES ************************/ + +/* + * Hashbin + */ +#define GET_HASHBIN(x) ( x & HASHBIN_MASK ) + +/* + * Function hash (name) + * + * This function hash the input string 'name' using the ELF hash + * function for strings. + */ +static __u32 hash( char* name) +{ + __u32 h = 0; + __u32 g; + + while(*name) { + h = (h<<4) + *name++; + if ((g = (h & 0xf0000000))) + h ^=g>>24; + h &=~g; + } + return h; +} + +/* + * Function enqueue_first (queue, proc) + * + * Insert item first in queue. + * + */ +static void enqueue_first(irda_queue_t **queue, irda_queue_t* element) +{ + + IRDA_DEBUG( 4, __FUNCTION__ "()\n"); + + /* + * Check if queue is empty. + */ + if ( *queue == NULL ) { + /* + * Queue is empty. Insert one element into the queue. + */ + element->q_next = element->q_prev = *queue = element; + + } else { + /* + * Queue is not empty. Insert element into front of queue. + */ + element->q_next = (*queue); + (*queue)->q_prev->q_next = element; + element->q_prev = (*queue)->q_prev; + (*queue)->q_prev = element; + (*queue) = element; + } +} + +#ifdef HASHBIN_UNUSED +/* + * Function enqueue_last (queue, proc) + * + * Insert item into end of queue. + * + */ +static void __enqueue_last( irda_queue_t **queue, irda_queue_t* element) +{ + IRDA_DEBUG( 4, __FUNCTION__ "()\n"); + + /* + * Check if queue is empty. + */ + if ( *queue == NULL ) { + /* + * Queue is empty. Insert one element into the queue. + */ + element->q_next = element->q_prev = *queue = element; + + } else { + /* + * Queue is not empty. Insert element into end of queue. + */ + element->q_prev = (*queue)->q_prev; + element->q_prev->q_next = element; + (*queue)->q_prev = element; + element->q_next = *queue; + } +} + +static inline void enqueue_last( irda_queue_t **queue, irda_queue_t* element) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + __enqueue_last( queue, element); + + restore_flags(flags); +} + +/* + * Function enqueue_queue (queue, list) + * + * Insert a queue (list) into the start of the first queue + * + */ +static void enqueue_queue( irda_queue_t** queue, irda_queue_t** list ) +{ + irda_queue_t* tmp; + + /* + * Check if queue is empty + */ + if ( *queue ) { + (*list)->q_prev->q_next = (*queue); + (*queue)->q_prev->q_next = (*list); + tmp = (*list)->q_prev; + (*list)->q_prev = (*queue)->q_prev; + (*queue)->q_prev = tmp; + } else { + *queue = (*list); + } + + (*list) = NULL; +} + +/* + * Function enqueue_second (queue, proc) + * + * Insert item behind head of queue. + * + */ +static void enqueue_second(irda_queue_t **queue, irda_queue_t* element) +{ + IRDA_DEBUG( 0, "enqueue_second()\n"); + + /* + * Check if queue is empty. + */ + if ( *queue == NULL ) { + /* + * Queue is empty. Insert one element into the queue. + */ + element->q_next = element->q_prev = *queue = element; + + } else { + /* + * Queue is not empty. Insert element into .. + */ + element->q_prev = (*queue); + (*queue)->q_next->q_prev = element; + element->q_next = (*queue)->q_next; + (*queue)->q_next = element; + } +} +#endif /* HASHBIN_UNUSED */ + +/* + * Function dequeue (queue) + * + * Remove first entry in queue + * + */ +static irda_queue_t *dequeue_first(irda_queue_t **queue) +{ + irda_queue_t *ret; + + IRDA_DEBUG( 4, "dequeue_first()\n"); + + /* + * Set return value + */ + ret = *queue; + + if ( *queue == NULL ) { + /* + * Queue was empty. + */ + } else if ( (*queue)->q_next == *queue ) { + /* + * Queue only contained a single element. It will now be + * empty. + */ + *queue = NULL; + } else { + /* + * Queue contained several element. Remove the first one. + */ + (*queue)->q_prev->q_next = (*queue)->q_next; + (*queue)->q_next->q_prev = (*queue)->q_prev; + *queue = (*queue)->q_next; + } + + /* + * Return the removed entry (or NULL of queue was empty). + */ + return ret; +} + +/* + * Function dequeue_general (queue, element) + * + * + */ +static irda_queue_t *dequeue_general(irda_queue_t **queue, irda_queue_t* element) +{ + irda_queue_t *ret; + + IRDA_DEBUG( 4, "dequeue_general()\n"); + + /* + * Set return value + */ + ret = *queue; + + if ( *queue == NULL ) { + /* + * Queue was empty. + */ + } else if ( (*queue)->q_next == *queue ) { + /* + * Queue only contained a single element. It will now be + * empty. + */ + *queue = NULL; + + } else { + /* + * Remove specific element. + */ + element->q_prev->q_next = element->q_next; + element->q_next->q_prev = element->q_prev; + if ( (*queue) == element) + (*queue) = element->q_next; + } + + /* + * Return the removed entry (or NULL of queue was empty). + */ + return ret; +} + +/************************ HASHBIN MANAGEMENT ************************/ /* * Function hashbin_create ( type, name ) @@ -49,7 +450,6 @@ hashbin_t *hashbin_new(int type) { hashbin_t* hashbin; - int i; /* * Allocate new hashbin @@ -64,14 +464,17 @@ memset(hashbin, 0, sizeof(hashbin_t)); hashbin->hb_type = type; hashbin->magic = HB_MAGIC; + //hashbin->hb_current = NULL; /* Make sure all spinlock's are unlocked */ - for (i=0;ihb_mutex[i] = SPIN_LOCK_UNLOCKED; - + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_init(&hashbin->hb_spinlock); + } + return hashbin; } +#ifdef HASHBIN_UNUSED /* * Function hashbin_clear (hashbin, free_func) * @@ -102,7 +505,7 @@ return 0; } - +#endif /* HASHBIN_UNUSED */ /* * Function hashbin_delete (hashbin, free_func) @@ -114,11 +517,17 @@ int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func) { irda_queue_t* queue; + unsigned long flags = 0; int i; ASSERT(hashbin != NULL, return -1;); ASSERT(hashbin->magic == HB_MAGIC, return -1;); + /* Synchronize */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + } + /* * Free the entries in the hashbin, TODO: use hashbin_clear when * it has been shown to work @@ -133,22 +542,32 @@ } } + /* Cleanup local data */ + hashbin->hb_current = NULL; + hashbin->magic = ~HB_MAGIC; + + /* Release lock */ + if ( hashbin->hb_type & HB_LOCK) { + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + } + /* * Free the hashbin structure */ - hashbin->magic = ~HB_MAGIC; kfree(hashbin); return 0; } +/********************* HASHBIN LIST OPERATIONS *********************/ + /* * Function hashbin_insert (hashbin, entry, name) * * Insert an entry into the hashbin * */ -void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, __u32 hashv, char* name) +void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv, char* name) { unsigned long flags = 0; int bin; @@ -166,12 +585,8 @@ bin = GET_HASHBIN( hashv ); /* Synchronize */ - if ( hashbin->hb_type & HB_GLOBAL ) { - spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags); - - } else if ( hashbin->hb_type & HB_LOCAL ) { - save_flags(flags); - cli(); + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_irqsave(&hashbin->hb_spinlock, flags); } /* Default is no-lock */ /* @@ -194,102 +609,61 @@ hashbin->hb_size++; /* Release lock */ - if ( hashbin->hb_type & HB_GLOBAL) { - - spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags); - - } else if ( hashbin->hb_type & HB_LOCAL) { - restore_flags( flags); - } + if ( hashbin->hb_type & HB_LOCK ) { + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ } -/* - * Function hashbin_find (hashbin, hashv, name) +/* + * Function hashbin_remove_first (hashbin) * - * Find item with the given hashv or name + * Remove first entry of the hashbin * + * Note : this function no longer use hashbin_remove(), but does things + * similar to hashbin_remove_this(), so can be considered safe. + * Jean II */ -void* hashbin_find( hashbin_t* hashbin, __u32 hashv, char* name ) +void *hashbin_remove_first( hashbin_t *hashbin) { - int bin, found = FALSE; unsigned long flags = 0; - irda_queue_t* entry; - - IRDA_DEBUG( 4, "hashbin_find()\n"); - - ASSERT( hashbin != NULL, return NULL;); - ASSERT( hashbin->magic == HB_MAGIC, return NULL;); + irda_queue_t *entry = NULL; - /* - * Locate hashbin - */ - if ( name ) - hashv = hash( name ); - bin = GET_HASHBIN( hashv ); - /* Synchronize */ - if ( hashbin->hb_type & HB_GLOBAL ) { - spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags); - - } else if ( hashbin->hb_type & HB_LOCAL ) { - save_flags(flags); - cli(); + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_irqsave(&hashbin->hb_spinlock, flags); } /* Default is no-lock */ - - /* - * Search for entry - */ - entry = hashbin->hb_queue[ bin]; - if ( entry ) { - do { - /* - * Check for key - */ - if ( entry->q_hash == hashv ) { - /* - * Name compare too? - */ - if ( name ) { - if ( strcmp( entry->q_name, name ) == 0 ) { - found = TRUE; - break; - } - } else { - found = TRUE; - break; - } - } - entry = entry->q_next; - } while ( entry != hashbin->hb_queue[ bin ] ); - } - - /* Release lock */ - if ( hashbin->hb_type & HB_GLOBAL) { - spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags); - - } else if ( hashbin->hb_type & HB_LOCAL) { - restore_flags( flags); - } - - if ( found ) - return entry; - else - return NULL; -} -void *hashbin_remove_first( hashbin_t *hashbin) -{ - unsigned long flags; - irda_queue_t *entry = NULL; + entry = hashbin_get_first( hashbin); + if ( entry != NULL) { + int bin; + long hashv; + /* + * Locate hashbin + */ + hashv = entry->q_hash; + bin = GET_HASHBIN( hashv ); - save_flags(flags); - cli(); + /* + * Dequeue the entry... + */ + dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ], + (irda_queue_t*) entry ); + hashbin->hb_size--; + entry->q_next = NULL; + entry->q_prev = NULL; - entry = hashbin_get_first( hashbin); - if ( entry != NULL) - hashbin_remove( hashbin, entry->q_hash, NULL); + /* + * Check if this item is the currently selected item, and in + * that case we must reset hb_current + */ + if ( entry == hashbin->hb_current) + hashbin->hb_current = NULL; + } - restore_flags( flags); + /* Release lock */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ return entry; } @@ -300,8 +674,16 @@ * * Remove entry with the given name * + * The use of this function is highly discouraged, because the whole + * concept behind hashbin_remove() is broken. In many cases, it's not + * possible to guarantee the unicity of the index (either hashv or name), + * leading to removing the WRONG entry. + * The only simple safe use is : + * hashbin_remove(hasbin, (int) self, NULL); + * In other case, you must think hard to guarantee unicity of the index. + * Jean II */ -void* hashbin_remove( hashbin_t* hashbin, __u32 hashv, char* name) +void* hashbin_remove( hashbin_t* hashbin, long hashv, char* name) { int bin, found = FALSE; unsigned long flags = 0; @@ -320,12 +702,8 @@ bin = GET_HASHBIN( hashv ); /* Synchronize */ - if ( hashbin->hb_type & HB_GLOBAL ) { - spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags); - - } else if ( hashbin->hb_type & HB_LOCAL ) { - save_flags(flags); - cli(); + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_irqsave(&hashbin->hb_spinlock, flags); } /* Default is no-lock */ /* @@ -373,12 +751,9 @@ } /* Release lock */ - if ( hashbin->hb_type & HB_GLOBAL) { - spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags); - - } else if ( hashbin->hb_type & HB_LOCAL) { - restore_flags( flags); - } + if ( hashbin->hb_type & HB_LOCK ) { + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ /* Return */ @@ -390,7 +765,7 @@ } /* - * Function hashbin_remove (hashbin, hashv, name) + * Function hashbin_remove_this (hashbin, entry) * * Remove entry with the given name * @@ -404,7 +779,7 @@ { unsigned long flags = 0; int bin; - __u32 hashv; + long hashv; IRDA_DEBUG( 4, __FUNCTION__ "()\n"); @@ -412,6 +787,11 @@ ASSERT( hashbin->magic == HB_MAGIC, return NULL;); ASSERT( entry != NULL, return NULL;); + /* Synchronize */ + if ( hashbin->hb_type & HB_LOCK ) { + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ + /* Check if valid and not already removed... */ if((entry->q_next == NULL) || (entry->q_prev == NULL)) return NULL; @@ -422,15 +802,6 @@ hashv = entry->q_hash; bin = GET_HASHBIN( hashv ); - /* Synchronize */ - if ( hashbin->hb_type & HB_GLOBAL ) { - spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags); - - } else if ( hashbin->hb_type & HB_LOCAL ) { - save_flags(flags); - cli(); - } /* Default is no-lock */ - /* * Dequeue the entry... */ @@ -448,13 +819,132 @@ hashbin->hb_current = NULL; /* Release lock */ - if ( hashbin->hb_type & HB_GLOBAL) { - spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags); + if ( hashbin->hb_type & HB_LOCK ) { + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + } /* Default is no-lock */ + + return entry; +} + +/*********************** HASHBIN ENUMERATION ***********************/ + +/* + * Function hashbin_common_find (hashbin, hashv, name) + * + * Find item with the given hashv or name + * + */ +void* hashbin_find( hashbin_t* hashbin, long hashv, char* name ) +{ + int bin; + irda_queue_t* entry; - } else if ( hashbin->hb_type & HB_LOCAL) { - restore_flags( flags); + IRDA_DEBUG( 4, "hashbin_find()\n"); + + ASSERT( hashbin != NULL, return NULL;); + ASSERT( hashbin->magic == HB_MAGIC, return NULL;); + + /* + * Locate hashbin + */ + if ( name ) + hashv = hash( name ); + bin = GET_HASHBIN( hashv ); + + /* + * Search for entry + */ + entry = hashbin->hb_queue[ bin]; + if ( entry ) { + do { + /* + * Check for key + */ + if ( entry->q_hash == hashv ) { + /* + * Name compare too? + */ + if ( name ) { + if ( strcmp( entry->q_name, name ) == 0 ) { + return entry; + } + } else { + return entry; + } + } + entry = entry->q_next; + } while ( entry != hashbin->hb_queue[ bin ] ); } + return NULL; +} + +/* + * Function hashbin_lock_find (hashbin, hashv, name) + * + * Find item with the given hashv or name + * + * Same, but with spinlock protection... + * I call it safe, but it's only safe with respect to the hashbin, not its + * content. - Jean II + */ +void* hashbin_lock_find( hashbin_t* hashbin, long hashv, char* name ) +{ + unsigned long flags = 0; + irda_queue_t* entry; + + /* Synchronize */ + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + + /* + * Search for entry + */ + entry = (irda_queue_t* ) hashbin_find( hashbin, hashv, name ); + + /* Release lock */ + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + + return entry; +} + +/* + * Function hashbin_find (hashbin, hashv, name, pnext) + * + * Find an item with the given hashv or name, and its successor + * + * This function allow to do concurent enumerations without the + * need to lock over the whole session, because the caller keep the + * context of the search. On the other hand, it might fail and return + * NULL if the entry is removed. - Jean II + */ +void* hashbin_find_next( hashbin_t* hashbin, long hashv, char* name, + void ** pnext) +{ + unsigned long flags = 0; + irda_queue_t* entry; + + /* Synchronize */ + spin_lock_irqsave(&hashbin->hb_spinlock, flags); + + /* + * Search for current entry + * This allow to check if the current item is still in the + * hashbin or has been removed. + */ + entry = (irda_queue_t* ) hashbin_find( hashbin, hashv, name ); + + /* + * Trick hashbin_get_next() to return what we want + */ + if(entry) { + hashbin->hb_current = entry; + *pnext = hashbin_get_next( hashbin ); + } else + *pnext = NULL; + + /* Release lock */ + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); + return entry; } @@ -496,6 +986,8 @@ * be started by a call to hashbin_get_first(). The function returns * NULL when all items have been traversed * + * The context of the search is stored within the hashbin, so you must + * protect yourself from concurent enumerations. - Jean II */ irda_queue_t *hashbin_get_next( hashbin_t *hashbin) { @@ -542,241 +1034,4 @@ } } return NULL; -} - -/* - * Function enqueue_last (queue, proc) - * - * Insert item into end of queue. - * - */ -static void __enqueue_last( irda_queue_t **queue, irda_queue_t* element) -{ - IRDA_DEBUG( 4, __FUNCTION__ "()\n"); - - /* - * Check if queue is empty. - */ - if ( *queue == NULL ) { - /* - * Queue is empty. Insert one element into the queue. - */ - element->q_next = element->q_prev = *queue = element; - - } else { - /* - * Queue is not empty. Insert element into end of queue. - */ - element->q_prev = (*queue)->q_prev; - element->q_prev->q_next = element; - (*queue)->q_prev = element; - element->q_next = *queue; - } -} - -inline void enqueue_last( irda_queue_t **queue, irda_queue_t* element) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - __enqueue_last( queue, element); - - restore_flags(flags); -} - -/* - * Function enqueue_first (queue, proc) - * - * Insert item first in queue. - * - */ -void enqueue_first(irda_queue_t **queue, irda_queue_t* element) -{ - - IRDA_DEBUG( 4, __FUNCTION__ "()\n"); - - /* - * Check if queue is empty. - */ - if ( *queue == NULL ) { - /* - * Queue is empty. Insert one element into the queue. - */ - element->q_next = element->q_prev = *queue = element; - - } else { - /* - * Queue is not empty. Insert element into front of queue. - */ - element->q_next = (*queue); - (*queue)->q_prev->q_next = element; - element->q_prev = (*queue)->q_prev; - (*queue)->q_prev = element; - (*queue) = element; - } -} - -/* - * Function enqueue_queue (queue, list) - * - * Insert a queue (list) into the start of the first queue - * - */ -void enqueue_queue( irda_queue_t** queue, irda_queue_t** list ) -{ - irda_queue_t* tmp; - - /* - * Check if queue is empty - */ - if ( *queue ) { - (*list)->q_prev->q_next = (*queue); - (*queue)->q_prev->q_next = (*list); - tmp = (*list)->q_prev; - (*list)->q_prev = (*queue)->q_prev; - (*queue)->q_prev = tmp; - } else { - *queue = (*list); - } - - (*list) = NULL; -} - -/* - * Function enqueue_second (queue, proc) - * - * Insert item behind head of queue. - * - */ -#if 0 -static void enqueue_second(irda_queue_t **queue, irda_queue_t* element) -{ - IRDA_DEBUG( 0, "enqueue_second()\n"); - - /* - * Check if queue is empty. - */ - if ( *queue == NULL ) { - /* - * Queue is empty. Insert one element into the queue. - */ - element->q_next = element->q_prev = *queue = element; - - } else { - /* - * Queue is not empty. Insert element into .. - */ - element->q_prev = (*queue); - (*queue)->q_next->q_prev = element; - element->q_next = (*queue)->q_next; - (*queue)->q_next = element; - } -} -#endif - -/* - * Function dequeue (queue) - * - * Remove first entry in queue - * - */ -irda_queue_t *dequeue_first(irda_queue_t **queue) -{ - irda_queue_t *ret; - - IRDA_DEBUG( 4, "dequeue_first()\n"); - - /* - * Set return value - */ - ret = *queue; - - if ( *queue == NULL ) { - /* - * Queue was empty. - */ - } else if ( (*queue)->q_next == *queue ) { - /* - * Queue only contained a single element. It will now be - * empty. - */ - *queue = NULL; - } else { - /* - * Queue contained several element. Remove the first one. - */ - (*queue)->q_prev->q_next = (*queue)->q_next; - (*queue)->q_next->q_prev = (*queue)->q_prev; - *queue = (*queue)->q_next; - } - - /* - * Return the removed entry (or NULL of queue was empty). - */ - return ret; -} - -/* - * Function dequeue_general (queue, element) - * - * - */ -static irda_queue_t *dequeue_general(irda_queue_t **queue, irda_queue_t* element) -{ - irda_queue_t *ret; - - IRDA_DEBUG( 4, "dequeue_general()\n"); - - /* - * Set return value - */ - ret = *queue; - - if ( *queue == NULL ) { - /* - * Queue was empty. - */ - } else if ( (*queue)->q_next == *queue ) { - /* - * Queue only contained a single element. It will now be - * empty. - */ - *queue = NULL; - - } else { - /* - * Remove specific element. - */ - element->q_prev->q_next = element->q_next; - element->q_next->q_prev = element->q_prev; - if ( (*queue) == element) - (*queue) = element->q_next; - } - - /* - * Return the removed entry (or NULL of queue was empty). - */ - return ret; -} - -/* - * Function hash (name) - * - * This function hash the input string 'name' using the ELF hash - * function for strings. - */ -static __u32 hash( char* name) -{ - __u32 h = 0; - __u32 g; - - while(*name) { - h = (h<<4) + *name++; - if ((g = (h & 0xf0000000))) - h ^=g>>24; - h &=~g; - } - return h; } diff -Nru a/net/irda/irsyms.c b/net/irda/irsyms.c --- a/net/irda/irsyms.c Fri Sep 20 08:20:47 2002 +++ b/net/irda/irsyms.c Fri Sep 20 08:20:47 2002 @@ -132,12 +132,14 @@ EXPORT_SYMBOL(lmp_reasons); /* Queue */ -EXPORT_SYMBOL(hashbin_find); EXPORT_SYMBOL(hashbin_new); EXPORT_SYMBOL(hashbin_insert); EXPORT_SYMBOL(hashbin_delete); EXPORT_SYMBOL(hashbin_remove); EXPORT_SYMBOL(hashbin_remove_this); +EXPORT_SYMBOL(hashbin_find); +EXPORT_SYMBOL(hashbin_lock_find); +EXPORT_SYMBOL(hashbin_find_next); EXPORT_SYMBOL(hashbin_get_next); EXPORT_SYMBOL(hashbin_get_first); @@ -328,7 +330,8 @@ * On the other hand, it needs to be initialised *after* the basic * networking, the /proc/net filesystem and sysctl module. Those are * currently initialised in .../init/main.c (before initcalls). - * Also, it needs to be initialised *after* the random number generator. + * Also, IrDA drivers needs to be initialised *after* the random number + * generator (main stack and higher layer init don't need it anymore). * * Jean II */ diff -Nru a/net/irda/irttp.c b/net/irda/irttp.c --- a/net/irda/irttp.c Fri Sep 20 08:20:47 2002 +++ b/net/irda/irttp.c Fri Sep 20 08:20:47 2002 @@ -91,7 +91,7 @@ irttp->magic = TTP_MAGIC; - irttp->tsaps = hashbin_new(HB_LOCAL); + irttp->tsaps = hashbin_new(HB_LOCK); if (!irttp->tsaps) { ERROR("%s: can't allocate IrTTP hashbin!\n", __FUNCTION__); return -ENOMEM; @@ -433,7 +433,7 @@ self->notify = *notify; self->lsap = lsap; - hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (int) self, NULL); + hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (long) self, NULL); if (credit > TTP_RX_MAX_CREDIT) self->initial_credit = TTP_RX_MAX_CREDIT; @@ -503,7 +503,7 @@ return 0; /* Will be back! */ } - tsap = hashbin_remove(irttp->tsaps, (int) self, NULL); + tsap = hashbin_remove(irttp->tsaps, (long) self, NULL); ASSERT(tsap == self, return -1;); @@ -1365,31 +1365,44 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance) { struct tsap_cb *new; + unsigned long flags; IRDA_DEBUG(1, __FUNCTION__ "()\n"); + /* Protect our access to the old tsap instance */ + spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags); + + /* Find the old instance */ if (!hashbin_find(irttp->tsaps, (int) orig, NULL)) { IRDA_DEBUG(0, __FUNCTION__ "(), unable to find TSAP\n"); + spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); return NULL; } + + /* Allocate a new instance */ new = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC); if (!new) { IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n"); + spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); return NULL; } /* Dup */ memcpy(new, orig, sizeof(struct tsap_cb)); - new->notify.instance = instance; - new->lsap = irlmp_dup(orig->lsap, new); + + /* We don't need the old instance any more */ + spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); /* Not everything should be copied */ + new->notify.instance = instance; + new->lsap = irlmp_dup(orig->lsap, new); init_timer(&new->todo_timer); skb_queue_head_init(&new->rx_queue); skb_queue_head_init(&new->tx_queue); skb_queue_head_init(&new->rx_fragments); - hashbin_insert(irttp->tsaps, (irda_queue_t *) new, (int) new, NULL); + /* This is locked */ + hashbin_insert(irttp->tsaps, (irda_queue_t *) new, (long) new, NULL); return new; } @@ -1723,8 +1736,8 @@ len = 0; - save_flags(flags); - cli(); + /* Protect our access to the tsap list */ + spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags); self = (struct tsap_cb *) hashbin_get_first(irttp->tsaps); while (self != NULL) { @@ -1770,7 +1783,7 @@ self = (struct tsap_cb *) hashbin_get_next(irttp->tsaps); } - restore_flags(flags); + spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); return len; } diff -Nru a/net/llc/llc_actn.c b/net/llc/llc_actn.c --- a/net/llc/llc_actn.c Fri Sep 20 08:20:43 2002 +++ b/net/llc/llc_actn.c Fri Sep 20 08:20:43 2002 @@ -24,16 +24,10 @@ #include #include -static void llc_station_ack_tmr_callback(unsigned long timeout_data); - int llc_station_ac_start_ack_timer(struct llc_station *station, struct sk_buff *skb) { - del_timer(&station->ack_timer); - station->ack_timer.expires = jiffies + LLC_ACK_TIME * HZ; - station->ack_timer.data = (unsigned long)station; - station->ack_timer.function = llc_station_ack_tmr_callback; - add_timer(&station->ack_timer); + mod_timer(&station->ack_timer, jiffies + LLC_ACK_TIME * HZ); return 0; } @@ -130,7 +124,7 @@ return 0; } -static void llc_station_ack_tmr_callback(unsigned long timeout_data) +void llc_station_ack_tmr_cb(unsigned long timeout_data) { struct llc_station *station = (struct llc_station *)timeout_data; struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); diff -Nru a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c --- a/net/llc/llc_c_ac.c Fri Sep 20 08:20:48 2002 +++ b/net/llc/llc_c_ac.c Fri Sep 20 08:20:48 2002 @@ -28,10 +28,6 @@ #include #include -static void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data); -static void llc_conn_ack_tmr_cb(unsigned long timeout_data); -static void llc_conn_rej_tmr_cb(unsigned long timeout_data); -static void llc_conn_busy_tmr_cb(unsigned long timeout_data); static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb); static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb); static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *ev); @@ -664,11 +660,8 @@ if (!llc->remote_busy_flag) { llc->remote_busy_flag = 1; - llc->busy_state_timer.timer.expires = jiffies + - llc->busy_state_timer.expire * HZ; - llc->busy_state_timer.timer.data = (unsigned long)sk; - llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb; - add_timer(&llc->busy_state_timer.timer); + mod_timer(&llc->busy_state_timer.timer, + jiffies + llc->busy_state_timer.expire * HZ); } return 0; } @@ -905,12 +898,8 @@ struct llc_opt *llc = llc_sk(sk); llc->p_flag = 1; - del_timer(&llc->pf_cycle_timer.timer); - llc->pf_cycle_timer.timer.expires = jiffies + - llc->pf_cycle_timer.expire * HZ; - llc->pf_cycle_timer.timer.data = (unsigned long)sk; - llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb; - add_timer(&llc->pf_cycle_timer.timer); + mod_timer(&llc->pf_cycle_timer.timer, + jiffies + llc->pf_cycle_timer.expire * HZ); return 0; } @@ -1181,11 +1170,7 @@ { struct llc_opt *llc = llc_sk(sk); - del_timer(&llc->ack_timer.timer); - llc->ack_timer.timer.expires = jiffies + llc->ack_timer.expire * HZ; - llc->ack_timer.timer.data = (unsigned long)sk; - llc->ack_timer.timer.function = llc_conn_ack_tmr_cb; - add_timer(&llc->ack_timer.timer); + mod_timer(&llc->ack_timer.timer, jiffies + llc->ack_timer.expire * HZ); return 0; } @@ -1193,12 +1178,8 @@ { struct llc_opt *llc = llc_sk(sk); - del_timer(&llc->rej_sent_timer.timer); - llc->rej_sent_timer.timer.expires = jiffies + - llc->rej_sent_timer.expire * HZ; - llc->rej_sent_timer.timer.data = (unsigned long)sk; - llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb; - add_timer(&llc->rej_sent_timer.timer); + mod_timer(&llc->rej_sent_timer.timer, + jiffies + llc->rej_sent_timer.expire * HZ); return 0; } @@ -1207,13 +1188,9 @@ { struct llc_opt *llc = llc_sk(sk); - if (!timer_pending(&llc->ack_timer.timer)) { - llc->ack_timer.timer.expires = jiffies + - llc->ack_timer.expire * HZ; - llc->ack_timer.timer.data = (unsigned long)sk; - llc->ack_timer.timer.function = llc_conn_ack_tmr_cb; - add_timer(&llc->ack_timer.timer); - } + if (!timer_pending(&llc->ack_timer.timer)) + mod_timer(&llc->ack_timer.timer, + jiffies + llc->ack_timer.expire * HZ); return 0; } @@ -1260,13 +1237,9 @@ llc->failed_data_req = 0; llc_conn_ac_data_confirm(sk, skb); } - if (unacked) { - llc->ack_timer.timer.expires = jiffies + - llc->ack_timer.expire * HZ; - llc->ack_timer.timer.data = (unsigned long)sk; - llc->ack_timer.timer.function = llc_conn_ack_tmr_cb; - add_timer(&llc->ack_timer.timer); - } + if (unacked) + mod_timer(&llc->ack_timer.timer, + jiffies + llc->ack_timer.expire * HZ); } else if (llc->failed_data_req) { llc_pdu_decode_pf_bit(skb, &fbit); if (fbit == 1) { @@ -1413,7 +1386,7 @@ bh_unlock_sock(sk); } -static void llc_conn_busy_tmr_cb(unsigned long timeout_data) +void llc_conn_busy_tmr_cb(unsigned long timeout_data) { struct sock *sk = (struct sock *)timeout_data; struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); @@ -1445,7 +1418,7 @@ bh_unlock_sock(sk); } -static void llc_conn_rej_tmr_cb(unsigned long timeout_data) +void llc_conn_rej_tmr_cb(unsigned long timeout_data) { struct sock *sk = (struct sock *)timeout_data; struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); diff -Nru a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c --- a/net/llc/llc_c_ev.c Fri Sep 20 08:20:41 2002 +++ b/net/llc/llc_c_ev.c Fri Sep 20 08:20:41 2002 @@ -194,7 +194,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + return llc_conn_space(sk, skb) && + !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && !LLC_I_PF_IS_0(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -203,7 +204,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + return llc_conn_space(sk, skb) && + !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && !LLC_I_PF_IS_1(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -250,7 +252,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + return llc_conn_space(sk, skb) && + !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && !LLC_I_PF_IS_0(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -268,7 +271,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + return llc_conn_space(sk, skb) && + !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -423,7 +427,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + return llc_conn_space(sk, skb) && + !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && !LLC_S_PF_IS_0(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; } @@ -432,7 +437,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + return llc_conn_space(sk, skb) && + !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && !LLC_S_PF_IS_1(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; } diff -Nru a/net/llc/llc_main.c b/net/llc/llc_main.c --- a/net/llc/llc_main.c Fri Sep 20 08:20:44 2002 +++ b/net/llc/llc_main.c Fri Sep 20 08:20:44 2002 @@ -184,19 +184,32 @@ goto out; memset(llc, 0, sizeof(*llc)); rc = 0; - llc->sk = sk; - llc->state = LLC_CONN_STATE_ADM; - llc->inc_cntr = llc->dec_cntr = 2; - llc->dec_step = llc->connect_step = 1; - llc->ack_timer.expire = LLC_ACK_TIME; - llc->pf_cycle_timer.expire = LLC_P_TIME; - llc->rej_sent_timer.expire = LLC_REJ_TIME; - llc->busy_state_timer.expire = LLC_BUSY_TIME; - llc->n2 = 2; /* max retransmit */ - llc->k = 2; /* tx win size, will adjust dynam */ - llc->rw = 128; /* rx win size (opt and equal to - * tx_win of remote LLC) - */ + + llc->sk = sk; + llc->state = LLC_CONN_STATE_ADM; + llc->inc_cntr = llc->dec_cntr = 2; + llc->dec_step = llc->connect_step = 1; + + llc->ack_timer.expire = LLC_ACK_TIME; + llc->ack_timer.timer.data = (unsigned long)sk; + llc->ack_timer.timer.function = llc_conn_ack_tmr_cb; + + llc->pf_cycle_timer.expire = LLC_P_TIME; + llc->pf_cycle_timer.timer.data = (unsigned long)sk; + llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb; + + llc->rej_sent_timer.expire = LLC_REJ_TIME; + llc->rej_sent_timer.timer.data = (unsigned long)sk; + llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb; + + llc->busy_state_timer.expire = LLC_BUSY_TIME; + llc->busy_state_timer.timer.data = (unsigned long)sk; + llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb; + + llc->n2 = 2; /* max retransmit */ + llc->k = 2; /* tx win size, will adjust dynam */ + llc->rw = 128; /* rx win size (opt and equal to + * tx_win of remote LLC) */ skb_queue_head_init(&llc->pdu_unack_q); sk->backlog_rcv = llc_backlog_rcv; llc_sk(sk) = llc; @@ -534,6 +547,21 @@ return skb; } +static char *llc_conn_state_names[] = { + [LLC_CONN_STATE_ADM] = "adm", + [LLC_CONN_STATE_SETUP] = "setup", + [LLC_CONN_STATE_NORMAL] = "normal", + [LLC_CONN_STATE_BUSY] = "busy", + [LLC_CONN_STATE_REJ] = "rej", + [LLC_CONN_STATE_AWAIT] = "await", + [LLC_CONN_STATE_AWAIT_BUSY] = "await_busy", + [LLC_CONN_STATE_AWAIT_REJ] = "await_rej", + [LLC_CONN_STATE_D_CONN] = "d_conn", + [LLC_CONN_STATE_RESET] = "reset", + [LLC_CONN_STATE_ERROR] = "error", + [LLC_CONN_STATE_TEMP] = "temp", +}; + static int llc_proc_get_info(char *bf, char **start, off_t offset, int length) { struct llc_opt *llc; @@ -546,19 +574,34 @@ struct llc_sap *sap = list_entry(sap_entry, struct llc_sap, node); - len += sprintf(bf + len, "lsap=%d\n", sap->laddr.lsap); + len += sprintf(bf + len, "lsap=%02X\n", sap->laddr.lsap); spin_lock_bh(&sap->sk_list.lock); if (list_empty(&sap->sk_list.list)) { len += sprintf(bf + len, "no connections\n"); goto unlock; } - len += sprintf(bf + len, - "connection list:\nstate retr txwin rxwin\n"); + len += sprintf(bf + len, "connection list:\n" + "dsap state retr txw rxw " + "pf ff sf df rs cs " + "tack tpfc trs tbs blog busr\n"); list_for_each(llc_entry, &sap->sk_list.list) { llc = list_entry(llc_entry, struct llc_opt, node); - len += sprintf(bf + len, " %-5d%-5d%-6d%-5d\n", - llc->state, llc->retry_count, llc->k, - llc->rw); + len += sprintf(bf + len, " %02X %-10s %3d %3d %3d " + "%2d %2d %2d " + "%2d %2d %2d " + "%4d %4d %3d %3d %4d %4d\n", + llc->daddr.lsap, + llc_conn_state_names[llc->state], + llc->retry_count, llc->k, llc->rw, + llc->p_flag, llc->f_flag, llc->s_flag, + llc->data_flag, llc->remote_busy_flag, + llc->cause_flag, + timer_pending(&llc->ack_timer.timer), + timer_pending(&llc->pf_cycle_timer.timer), + timer_pending(&llc->rej_sent_timer.timer), + timer_pending(&llc->busy_state_timer.timer), + !!llc->sk->backlog.tail, + llc->sk->lock.users); } unlock: spin_unlock_bh(&sap->sk_list.lock); @@ -608,6 +651,9 @@ skb_queue_head_init(&llc_main_station.mac_pdu_q); skb_queue_head_init(&llc_main_station.ev_q.list); spin_lock_init(&llc_main_station.ev_q.lock); + llc_main_station.ack_timer.data = (unsigned long)&llc_main_station; + llc_main_station.ack_timer.function = llc_station_ack_tmr_cb; + skb = alloc_skb(0, GFP_ATOMIC); if (!skb) goto err; diff -Nru a/net/llc/llc_sock.c b/net/llc/llc_sock.c --- a/net/llc/llc_sock.c Fri Sep 20 08:20:41 2002 +++ b/net/llc/llc_sock.c Fri Sep 20 08:20:41 2002 @@ -360,11 +360,11 @@ llc->laddr.lsap, llc->daddr.lsap); if (!llc_send_disc(sk)) llc_ui_wait_for_disc(sk, sk->rcvtimeo); - release_sock(sk); if (!sk->zapped) { llc_sap_unassign_sock(llc->sap, sk); llc_ui_remove_socket(sk); } + release_sock(sk); if (llc->sap && list_empty(&llc->sap->sk_list.list)) llc_sap_close(llc->sap); sock_put(sk); @@ -484,10 +484,10 @@ llc->daddr.lsap = addr->sllc_dsap; memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN); memcpy(&llc->addr, addr, sizeof(llc->addr)); - rc = sk->zapped = 0; llc_ui_insert_socket(sk); /* assign new connection to it's SAP */ llc_sap_assign_sock(sap, sk); + rc = sk->zapped = 0; out: return rc; } @@ -878,18 +878,22 @@ if (!skb) /* shutdown */ goto out; copied = skb->len; - if (copied > size) { + if (copied > size) copied = size; - msg->msg_flags |= MSG_TRUNC; - } rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (rc) goto dgram_free; + if (skb->len > copied) { + skb_pull(skb, copied); + skb_queue_head(&sk->receive_queue, skb); + } if (uaddr) memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); msg->msg_namelen = sizeof(*uaddr); + if (!skb->list) { dgram_free: - kfree_skb(skb); + kfree_skb(skb); + } out: release_sock(sk); return rc ? : copied; @@ -915,7 +919,7 @@ int noblock = flags & MSG_DONTWAIT; struct net_device *dev; struct sk_buff *skb; - int rc = -EINVAL, size = 0; + int rc = -EINVAL, size = 0, copied = 0, hdrlen; dprintk("%s: sending from %02X to %02X\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap); lock_sock(sk); @@ -943,20 +947,28 @@ goto release; } else dev = llc->dev; - size = dev->hard_header_len + len + llc_ui_header_len(sk, addr); - rc = -EMSGSIZE; + hdrlen = dev->hard_header_len + llc_ui_header_len(sk, addr); + size = hdrlen + len; if (size > dev->mtu) - goto release; + size = dev->mtu; + copied = size - hdrlen; + release_sock(sk); skb = sock_alloc_send_skb(sk, size, noblock, &rc); + lock_sock(sk); if (!skb) goto release; skb->sk = sk; skb->dev = dev; skb->protocol = llc_proto_type(addr->sllc_arphrd); - skb_reserve(skb, dev->hard_header_len + llc_ui_header_len(sk, addr)); - rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); + skb_reserve(skb, hdrlen); + rc = memcpy_fromiovec(skb_put(skb, copied), msg->msg_iov, copied); if (rc) goto out; + if (sk->type == SOCK_DGRAM || addr->sllc_ua) { + llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_dmac, + addr->sllc_dsap); + goto out; + } if (addr->sllc_test) { llc_build_and_send_test_pkt(llc->sap, skb, addr->sllc_dmac, addr->sllc_dsap); @@ -967,11 +979,6 @@ addr->sllc_dsap); goto out; } - if (sk->type == SOCK_DGRAM || addr->sllc_ua) { - llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_dmac, - addr->sllc_dsap); - goto out; - } rc = -ENOPROTOOPT; if (!(sk->type == SOCK_STREAM && !addr->sllc_ua)) goto out; @@ -986,7 +993,7 @@ dprintk("%s: failed sending from %02X to %02X: %d\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc); release_sock(sk); - return rc ? : len; + return rc ? : copied; } /** diff -Nru a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c --- a/net/netrom/af_netrom.c Fri Sep 20 08:20:46 2002 +++ b/net/netrom/af_netrom.c Fri Sep 20 08:20:46 2002 @@ -1,38 +1,13 @@ /* - * NET/ROM release 007 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * NET/ROM 001 Jonathan(G4KLX) Cloned from the AX25 code. - * NET/ROM 002 Darryl(G7LED) Fixes and address enhancement. - * Jonathan(G4KLX) Complete bind re-think. - * Alan(GW4PTS) Trivial tweaks into new format. - * NET/ROM 003 Jonathan(G4KLX) Added G8BPQ extensions. - * Added NET/ROM routing ioctl. - * Darryl(G7LED) Fix autobinding (on connect). - * Fixed nr_release(), set TCP_CLOSE, wakeup app - * context, THEN make the sock dead. - * Circuit ID check before allocating it on - * a connection. - * Alan(GW4PTS) sendmsg/recvmsg only. Fixed connect clear bug - * inherited from AX.25 - * NET/ROM 004 Jonathan(G4KLX) Converted to module. - * NET/ROM 005 Jonathan(G4KLX) Linux 2.1 - * Alan(GW4PTS) Started POSIXisms - * NET/ROM 006 Alan(GW4PTS) Brought in line with the ANK changes - * Jonathan(G4KLX) Removed hdrincl. - * NET/ROM 007 Jonathan(G4KLX) New timer architecture. - * Implemented Idle timer. - * Arnaldo C. Melo s/suser/capable/, micro cleanups + * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk) */ - #include #include #include @@ -82,7 +57,8 @@ static unsigned short circuit = 0x101; -static struct sock *volatile nr_list; +static struct sock *nr_list; +static spinlock_t nr_list_lock; static struct proto_ops nr_proto_ops; @@ -123,27 +99,26 @@ static void nr_remove_socket(struct sock *sk) { struct sock *s; - unsigned long flags; - save_flags(flags); cli(); + spin_lock_bh(&nr_list_lock); if ((s = nr_list) == sk) { nr_list = s->next; - restore_flags(flags); + spin_unlock_bh(&nr_list_lock); return; } while (s != NULL && s->next != NULL) { if (s->next == sk) { s->next = sk->next; - restore_flags(flags); + spin_unlock_bh(&nr_list_lock); return; } s = s->next; } - restore_flags(flags); + spin_unlock_bh(&nr_list_lock); } /* @@ -153,10 +128,12 @@ { struct sock *s; + spin_lock_bh(&nr_list_lock); for (s = nr_list; s != NULL; s = s->next) { if (nr_sk(s)->device == dev) nr_disconnect(s, ENETUNREACH); } + spin_unlock_bh(&nr_list_lock); } /* @@ -180,14 +157,10 @@ */ static void nr_insert_socket(struct sock *sk) { - unsigned long flags; - - save_flags(flags); cli(); - + spin_lock_bh(&nr_list_lock); sk->next = nr_list; nr_list = sk; - - restore_flags(flags); + spin_unlock_bh(&nr_list_lock); } /* @@ -196,21 +169,18 @@ */ static struct sock *nr_find_listener(ax25_address *addr) { - unsigned long flags; struct sock *s; - save_flags(flags); - cli(); - + spin_lock_bh(&nr_list_lock); for (s = nr_list; s != NULL; s = s->next) { if (!ax25cmp(&nr_sk(s)->source_addr, addr) && s->state == TCP_LISTEN) { - restore_flags(flags); + spin_unlock_bh(&nr_list_lock); return s; } } + spin_unlock_bh(&nr_list_lock); - restore_flags(flags); return NULL; } @@ -220,21 +190,17 @@ static struct sock *nr_find_socket(unsigned char index, unsigned char id) { struct sock *s; - unsigned long flags; - - save_flags(flags); - cli(); + spin_lock_bh(&nr_list_lock); for (s = nr_list; s != NULL; s = s->next) { nr_cb *nr = nr_sk(s); if (nr->my_index == index && nr->my_id == id) { - restore_flags(flags); + spin_unlock_bh(&nr_list_lock); return s; } } - - restore_flags(flags); + spin_unlock_bh(&nr_list_lock); return NULL; } @@ -242,25 +208,22 @@ /* * Find a connected NET/ROM socket given their circuit IDs. */ -static struct sock *nr_find_peer(unsigned char index, unsigned char id, ax25_address *dest) +static struct sock *nr_find_peer(unsigned char index, unsigned char id, + ax25_address *dest) { struct sock *s; - unsigned long flags; - - save_flags(flags); - cli(); + spin_lock_bh(&nr_list_lock); for (s = nr_list; s != NULL; s = s->next) { nr_cb *nr = nr_sk(s); if (nr->your_index == index && nr->your_id == id && !ax25cmp(&nr->dest_addr, dest)) { - restore_flags(flags); + spin_unlock_bh(&nr_list_lock); return s; } } - - restore_flags(flags); + spin_unlock_bh(&nr_list_lock); return NULL; } @@ -301,17 +264,16 @@ } /* - * This is called from user mode and the timers. Thus it protects itself against - * interrupt users but doesn't worry about being called during work. - * Once it is removed from the queue no interrupt or bottom half will - * touch it and we are (fairly 8-) ) safe. + * This is called from user mode and the timers. Thus it protects itself + * against interrupt users but doesn't worry about being called during + * work. Once it is removed from the queue no interrupt or bottom half + * will touch it and we are (fairly 8-) ) safe. */ -void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer */ +void nr_destroy_socket(struct sock *sk) { struct sk_buff *skb; - unsigned long flags; - save_flags(flags); cli(); + nr_remove_socket(sk); nr_stop_heartbeat(sk); nr_stop_t1timer(sk); @@ -319,7 +281,6 @@ nr_stop_t4timer(sk); nr_stop_idletimer(sk); - nr_remove_socket(sk); nr_clear_queues(sk); /* Flush the queues */ while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { @@ -342,8 +303,6 @@ } else { nr_free_sock(sk); } - - restore_flags(flags); } /* @@ -368,38 +327,38 @@ return -EFAULT; switch (optname) { - case NETROM_T1: - if (opt < 1) - return -EINVAL; - nr->t1 = opt * HZ; - return 0; - - case NETROM_T2: - if (opt < 1) - return -EINVAL; - nr->t2 = opt * HZ; - return 0; - - case NETROM_N2: - if (opt < 1 || opt > 31) - return -EINVAL; - nr->n2 = opt; - return 0; - - case NETROM_T4: - if (opt < 1) - return -EINVAL; - nr->t4 = opt * HZ; - return 0; - - case NETROM_IDLE: - if (opt < 0) - return -EINVAL; - nr->idle = opt * 60 * HZ; - return 0; + case NETROM_T1: + if (opt < 1) + return -EINVAL; + nr->t1 = opt * HZ; + return 0; + + case NETROM_T2: + if (opt < 1) + return -EINVAL; + nr->t2 = opt * HZ; + return 0; - default: - return -ENOPROTOOPT; + case NETROM_N2: + if (opt < 1 || opt > 31) + return -EINVAL; + nr->n2 = opt; + return 0; + + case NETROM_T4: + if (opt < 1) + return -EINVAL; + nr->t4 = opt * HZ; + return 0; + + case NETROM_IDLE: + if (opt < 0) + return -EINVAL; + nr->idle = opt * 60 * HZ; + return 0; + + default: + return -ENOPROTOOPT; } } @@ -421,28 +380,28 @@ return -EINVAL; switch (optname) { - case NETROM_T1: - val = nr->t1 / HZ; - break; - - case NETROM_T2: - val = nr->t2 / HZ; - break; - - case NETROM_N2: - val = nr->n2; - break; - - case NETROM_T4: - val = nr->t4 / HZ; - break; - - case NETROM_IDLE: - val = nr->idle / (60 * HZ); - break; + case NETROM_T1: + val = nr->t1 / HZ; + break; + + case NETROM_T2: + val = nr->t2 / HZ; + break; + + case NETROM_N2: + val = nr->n2; + break; + + case NETROM_T4: + val = nr->t4 / HZ; + break; + + case NETROM_IDLE: + val = nr->idle / (60 * HZ); + break; - default: - return -ENOPROTOOPT; + default: + return -ENOPROTOOPT; } len = min_t(unsigned int, len, sizeof(int)); @@ -567,34 +526,33 @@ nr = nr_sk(sk); switch (nr->state) { - - case NR_STATE_0: - case NR_STATE_1: - case NR_STATE_2: - nr_disconnect(sk, 0); - nr_destroy_socket(sk); - break; - - case NR_STATE_3: - nr_clear_queues(sk); - nr->n2count = 0; - nr_write_internal(sk, NR_DISCREQ); - nr_start_t1timer(sk); - nr_stop_t2timer(sk); - nr_stop_t4timer(sk); - nr_stop_idletimer(sk); - nr->state = NR_STATE_2; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; - sk->destroy = 1; - sk->socket = NULL; - break; - - default: - sk->socket = NULL; - break; + case NR_STATE_0: + case NR_STATE_1: + case NR_STATE_2: + nr_disconnect(sk, 0); + nr_destroy_socket(sk); + break; + + case NR_STATE_3: + nr_clear_queues(sk); + nr->n2count = 0; + nr_write_internal(sk, NR_DISCREQ); + nr_start_t1timer(sk); + nr_stop_t2timer(sk); + nr_stop_t4timer(sk); + nr_stop_idletimer(sk); + nr->state = NR_STATE_2; + sk->state = TCP_CLOSE; + sk->shutdown |= SEND_SHUTDOWN; + sk->state_change(sk); + sk->dead = 1; + sk->destroy = 1; + sk->socket = NULL; + break; + + default: + sk->socket = NULL; + break; } sock->sk = NULL; @@ -732,78 +690,98 @@ if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) return -EINPROGRESS; - cli(); /* To avoid races on the sleep */ - /* - * A Connect Ack with Choke or timeout or failed routing will go to closed. + * A Connect Ack with Choke or timeout or failed routing will go to + * closed. */ - while (sk->state == TCP_SYN_SENT) { - interruptible_sleep_on(sk->sleep); - if (signal_pending(current)) { - sti(); + if (sk->state == TCP_SYN_SENT) { + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue(sk->sleep, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + if (sk->state != TCP_SYN_SENT) + break; + if (!signal_pending(tsk)) { + schedule(); + continue; + } return -ERESTARTSYS; } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep, &wait); } if (sk->state != TCP_ESTABLISHED) { - sti(); sock->state = SS_UNCONNECTED; return sock_error(sk); /* Always set at this point */ } sock->state = SS_CONNECTED; - sti(); - return 0; } static int nr_accept(struct socket *sock, struct socket *newsock, int flags) { - struct sock *sk; - struct sock *newsk; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); struct sk_buff *skb; + struct sock *newsk; + struct sock *sk; + int err = 0; if ((sk = sock->sk) == NULL) return -EINVAL; - if (sk->type != SOCK_SEQPACKET) - return -EOPNOTSUPP; + lock_sock(sk); + if (sk->type != SOCK_SEQPACKET) { + err = -EOPNOTSUPP; + goto out; + } - if (sk->state != TCP_LISTEN) - return -EINVAL; + if (sk->state != TCP_LISTEN) { + err = -EINVAL; + goto out; + } /* * The write queue this time is holding sockets ready to use * hooked into the SABM we saved */ - do { - cli(); - if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) { - if (flags & O_NONBLOCK) { - sti(); - return -EWOULDBLOCK; - } - interruptible_sleep_on(sk->sleep); - if (signal_pending(current)) { - sti(); - return -ERESTARTSYS; - } + add_wait_queue(sk->sleep, &wait); + for (;;) { + skb = skb_dequeue(&sk->receive_queue); + if (skb) + break; + + current->state = TASK_INTERRUPTIBLE; + release_sock(sk); + if (flags & O_NONBLOCK) + return -EWOULDBLOCK; + if (!signal_pending(tsk)) { + schedule(); + lock_sock(sk); + continue; } - } while (skb == NULL); + return -ERESTARTSYS; + } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep, &wait); newsk = skb->sk; newsk->pair = NULL; newsk->socket = newsock; newsk->sleep = &newsock->wait; - sti(); /* Now attach up the new socket */ kfree_skb(skb); sk->ack_backlog--; newsock->sk = newsk; - return 0; +out: + return err; } static int nr_getname(struct socket *sock, struct sockaddr *uaddr, @@ -1127,54 +1105,53 @@ struct sock *sk = sock->sk; switch (cmd) { - case TIOCOUTQ: { - long amount; - amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); - if (amount < 0) - amount = 0; - return put_user(amount, (int *)arg); - } - - case TIOCINQ: { - struct sk_buff *skb; - long amount = 0L; - /* These two are safe on a single CPU system as only user tasks fiddle here */ - if ((skb = skb_peek(&sk->receive_queue)) != NULL) - amount = skb->len; - return put_user(amount, (int *)arg); + case TIOCOUTQ: { + long amount; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + if (amount < 0) + amount = 0; + return put_user(amount, (int *)arg); + } + + case TIOCINQ: { + struct sk_buff *skb; + long amount = 0L; + /* These two are safe on a single CPU system as only user tasks fiddle here */ + if ((skb = skb_peek(&sk->receive_queue)) != NULL) + amount = skb->len; + return put_user(amount, (int *)arg); + } + + case SIOCGSTAMP: + if (sk != NULL) { + if (sk->stamp.tv_sec == 0) + return -ENOENT; + return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; } + return -EINVAL; - case SIOCGSTAMP: - if (sk != NULL) { - if (sk->stamp.tv_sec == 0) - return -ENOENT; - return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; - } - return -EINVAL; - - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - return -EINVAL; + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + return -EINVAL; - case SIOCADDRT: - case SIOCDELRT: - case SIOCNRDECOBS: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - return nr_rt_ioctl(cmd, (void *)arg); + case SIOCADDRT: + case SIOCDELRT: + case SIOCNRDECOBS: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + return nr_rt_ioctl(cmd, (void *)arg); - default: - return dev_ioctl(cmd, (void *)arg); + default: + return dev_ioctl(cmd, (void *)arg); } - /*NOTREACHED*/ return 0; } @@ -1187,7 +1164,7 @@ off_t pos = 0; off_t begin = 0; - cli(); + spin_lock_bh(&nr_list_lock); len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode\n"); @@ -1240,47 +1217,45 @@ break; } - sti(); + spin_unlock_bh(&nr_list_lock); *start = buffer + (offset - begin); len -= (offset - begin); - if (len > length) len = length; + if (len > length) + len = length; - return(len); -} + return len; +} static struct net_proto_family nr_family_ops = { - .family = PF_NETROM, - .create = nr_create, + .family = PF_NETROM, + .create = nr_create, }; -static struct proto_ops SOCKOPS_WRAPPED(nr_proto_ops) = { - .family = PF_NETROM, +static struct proto_ops nr_proto_ops = { + .family = PF_NETROM, - .release = nr_release, - .bind = nr_bind, - .connect = nr_connect, - .socketpair = sock_no_socketpair, - .accept = nr_accept, - .getname = nr_getname, - .poll = datagram_poll, - .ioctl = nr_ioctl, - .listen = nr_listen, - .shutdown = sock_no_shutdown, - .setsockopt = nr_setsockopt, - .getsockopt = nr_getsockopt, - .sendmsg = nr_sendmsg, - .recvmsg = nr_recvmsg, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, + .release = nr_release, + .bind = nr_bind, + .connect = nr_connect, + .socketpair = sock_no_socketpair, + .accept = nr_accept, + .getname = nr_getname, + .poll = datagram_poll, + .ioctl = nr_ioctl, + .listen = nr_listen, + .shutdown = sock_no_shutdown, + .setsockopt = nr_setsockopt, + .getsockopt = nr_getsockopt, + .sendmsg = nr_sendmsg, + .recvmsg = nr_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, }; -#include -SOCKOPS_WRAP(nr_proto, PF_NETROM); - static struct notifier_block nr_dev_notifier = { - .notifier_call =nr_device_event, + .notifier_call = nr_device_event, }; static struct net_device *dev_nr; diff -Nru a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c --- a/net/netrom/nr_dev.c Fri Sep 20 08:20:47 2002 +++ b/net/netrom/nr_dev.c Fri Sep 20 08:20:47 2002 @@ -1,23 +1,11 @@ /* - * NET/ROM release 007 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * NET/ROM 001 Jonathan(G4KLX) Cloned from loopback.c - * NET/ROM 002 Steve Whitehouse(GW7RRM) fixed the set_mac_address - * NET/ROM 003 Jonathan(G4KLX) Put nr_rebuild_header into line with - * ax25_rebuild_header - * NET/ROM 004 Jonathan(G4KLX) Callsign registration with AX.25. - * NET/ROM 006 Hans(PE1AYX) Fixed interface to IP layer. + * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #define __NO_VERSION__ #include @@ -115,7 +103,7 @@ kfree_skb(skb); len = skbn->len; - + if (!nr_route_frame(skbn, NULL)) { kfree_skb(skbn); stats->tx_errors++; diff -Nru a/net/netrom/nr_in.c b/net/netrom/nr_in.c --- a/net/netrom/nr_in.c Fri Sep 20 08:20:44 2002 +++ b/net/netrom/nr_in.c Fri Sep 20 08:20:44 2002 @@ -1,29 +1,12 @@ /* - * NET/ROM release 007 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; - * - * History - * NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_in.c - * NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragment reception. - * Darryl(G7LED) Added missing INFO with NAK case, optimized - * INFOACK handling, removed reconnect on error. - * NET/ROM 006 Jonathan(G4KLX) Hdrincl removal changes. - * NET/ROM 007 Jonathan(G4KLX) New timer architecture. + * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk) */ - #include #include #include @@ -77,7 +60,7 @@ kfree_skb(skbo); } - nr->fraglen = 0; + nr->fraglen = 0; } return sock_queue_rcv_skb(sk, skbn); @@ -88,36 +71,36 @@ * The handling of the timer(s) is in file nr_timer.c. * Handling of state 0 and connection release is in netrom.c. */ -static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) +static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, + int frametype) { switch (frametype) { + case NR_CONNACK: { + nr_cb *nr = nr_sk(sk); - case NR_CONNACK: { - nr_cb *nr = nr_sk(sk); - - nr_stop_t1timer(sk); - nr_start_idletimer(sk); - nr->your_index = skb->data[17]; - nr->your_id = skb->data[18]; - nr->vs = 0; - nr->va = 0; - nr->vr = 0; - nr->vl = 0; - nr->state = NR_STATE_3; - nr->n2count = 0; - nr->window = skb->data[20]; - sk->state = TCP_ESTABLISHED; - if (!sk->dead) - sk->state_change(sk); - break; - } + nr_stop_t1timer(sk); + nr_start_idletimer(sk); + nr->your_index = skb->data[17]; + nr->your_id = skb->data[18]; + nr->vs = 0; + nr->va = 0; + nr->vr = 0; + nr->vl = 0; + nr->state = NR_STATE_3; + nr->n2count = 0; + nr->window = skb->data[20]; + sk->state = TCP_ESTABLISHED; + if (!sk->dead) + sk->state_change(sk); + break; + } - case NR_CONNACK | NR_CHOKE_FLAG: - nr_disconnect(sk, ECONNREFUSED); - break; + case NR_CONNACK | NR_CHOKE_FLAG: + nr_disconnect(sk, ECONNREFUSED); + break; - default: - break; + default: + break; } return 0; @@ -128,23 +111,23 @@ * The handling of the timer(s) is in file nr_timer.c * Handling of state 0 and connection release is in netrom.c. */ -static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype) +static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, + int frametype) { switch (frametype) { + case NR_CONNACK | NR_CHOKE_FLAG: + nr_disconnect(sk, ECONNRESET); + break; + + case NR_DISCREQ: + nr_write_internal(sk, NR_DISCACK); + + case NR_DISCACK: + nr_disconnect(sk, 0); + break; - case NR_CONNACK | NR_CHOKE_FLAG: - nr_disconnect(sk, ECONNRESET); - break; - - case NR_DISCREQ: - nr_write_internal(sk, NR_DISCACK); - - case NR_DISCACK: - nr_disconnect(sk, 0); - break; - - default: - break; + default: + break; } return 0; @@ -168,35 +151,62 @@ ns = skb->data[17]; switch (frametype) { - - case NR_CONNREQ: - nr_write_internal(sk, NR_CONNACK); - break; - - case NR_DISCREQ: - nr_write_internal(sk, NR_DISCACK); - nr_disconnect(sk, 0); - break; - - case NR_CONNACK | NR_CHOKE_FLAG: - case NR_DISCACK: - nr_disconnect(sk, ECONNRESET); + case NR_CONNREQ: + nr_write_internal(sk, NR_CONNACK); + break; + + case NR_DISCREQ: + nr_write_internal(sk, NR_DISCACK); + nr_disconnect(sk, 0); + break; + + case NR_CONNACK | NR_CHOKE_FLAG: + case NR_DISCACK: + nr_disconnect(sk, ECONNRESET); + break; + + case NR_INFOACK: + case NR_INFOACK | NR_CHOKE_FLAG: + case NR_INFOACK | NR_NAK_FLAG: + case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG: + if (frametype & NR_CHOKE_FLAG) { + nrom->condition |= NR_COND_PEER_RX_BUSY; + nr_start_t4timer(sk); + } else { + nrom->condition &= ~NR_COND_PEER_RX_BUSY; + nr_stop_t4timer(sk); + } + if (!nr_validate_nr(sk, nr)) { break; - - case NR_INFOACK: - case NR_INFOACK | NR_CHOKE_FLAG: - case NR_INFOACK | NR_NAK_FLAG: - case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG: - if (frametype & NR_CHOKE_FLAG) { - nrom->condition |= NR_COND_PEER_RX_BUSY; - nr_start_t4timer(sk); + } + if (frametype & NR_NAK_FLAG) { + nr_frames_acked(sk, nr); + nr_send_nak_frame(sk); + } else { + if (nrom->condition & NR_COND_PEER_RX_BUSY) { + nr_frames_acked(sk, nr); } else { - nrom->condition &= ~NR_COND_PEER_RX_BUSY; - nr_stop_t4timer(sk); - } - if (!nr_validate_nr(sk, nr)) { - break; + nr_check_iframes_acked(sk, nr); } + } + break; + + case NR_INFO: + case NR_INFO | NR_NAK_FLAG: + case NR_INFO | NR_CHOKE_FLAG: + case NR_INFO | NR_MORE_FLAG: + case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG: + case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG: + case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG: + case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG: + if (frametype & NR_CHOKE_FLAG) { + nrom->condition |= NR_COND_PEER_RX_BUSY; + nr_start_t4timer(sk); + } else { + nrom->condition &= ~NR_COND_PEER_RX_BUSY; + nr_stop_t4timer(sk); + } + if (nr_validate_nr(sk, nr)) { if (frametype & NR_NAK_FLAG) { nr_frames_acked(sk, nr); nr_send_nak_frame(sk); @@ -207,76 +217,48 @@ nr_check_iframes_acked(sk, nr); } } - break; - - case NR_INFO: - case NR_INFO | NR_NAK_FLAG: - case NR_INFO | NR_CHOKE_FLAG: - case NR_INFO | NR_MORE_FLAG: - case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG: - case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG: - case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG: - case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG: - if (frametype & NR_CHOKE_FLAG) { - nrom->condition |= NR_COND_PEER_RX_BUSY; - nr_start_t4timer(sk); - } else { - nrom->condition &= ~NR_COND_PEER_RX_BUSY; - nr_stop_t4timer(sk); - } - if (nr_validate_nr(sk, nr)) { - if (frametype & NR_NAK_FLAG) { - nr_frames_acked(sk, nr); - nr_send_nak_frame(sk); - } else { - if (nrom->condition & NR_COND_PEER_RX_BUSY) { - nr_frames_acked(sk, nr); + } + queued = 1; + skb_queue_head(&nrom->reseq_queue, skb); + if (nrom->condition & NR_COND_OWN_RX_BUSY) + break; + skb_queue_head_init(&temp_queue); + do { + save_vr = nrom->vr; + while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) { + ns = skbn->data[17]; + if (ns == nrom->vr) { + if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) { + nrom->vr = (nrom->vr + 1) % NR_MODULUS; } else { - nr_check_iframes_acked(sk, nr); - } - } - } - queued = 1; - skb_queue_head(&nrom->reseq_queue, skb); - if (nrom->condition & NR_COND_OWN_RX_BUSY) - break; - skb_queue_head_init(&temp_queue); - do { - save_vr = nrom->vr; - while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) { - ns = skbn->data[17]; - if (ns == nrom->vr) { - if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) { - nrom->vr = (nrom->vr + 1) % NR_MODULUS; - } else { - nrom->condition |= NR_COND_OWN_RX_BUSY; - skb_queue_tail(&temp_queue, skbn); - } - } else if (nr_in_rx_window(sk, ns)) { + nrom->condition |= NR_COND_OWN_RX_BUSY; skb_queue_tail(&temp_queue, skbn); - } else { - kfree_skb(skbn); } - } - while ((skbn = skb_dequeue(&temp_queue)) != NULL) { - skb_queue_tail(&nrom->reseq_queue, skbn); - } - } while (save_vr != nrom->vr); - /* - * Window is full, ack it immediately. - */ - if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) { - nr_enquiry_response(sk); - } else { - if (!(nrom->condition & NR_COND_ACK_PENDING)) { - nrom->condition |= NR_COND_ACK_PENDING; - nr_start_t2timer(sk); + } else if (nr_in_rx_window(sk, ns)) { + skb_queue_tail(&temp_queue, skbn); + } else { + kfree_skb(skbn); } } - break; + while ((skbn = skb_dequeue(&temp_queue)) != NULL) { + skb_queue_tail(&nrom->reseq_queue, skbn); + } + } while (save_vr != nrom->vr); + /* + * Window is full, ack it immediately. + */ + if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) { + nr_enquiry_response(sk); + } else { + if (!(nrom->condition & NR_COND_ACK_PENDING)) { + nrom->condition |= NR_COND_ACK_PENDING; + nr_start_t2timer(sk); + } + } + break; - default: - break; + default: + break; } return queued; @@ -294,15 +276,15 @@ frametype = skb->data[19]; switch (nr->state) { - case NR_STATE_1: - queued = nr_state1_machine(sk, skb, frametype); - break; - case NR_STATE_2: - queued = nr_state2_machine(sk, skb, frametype); - break; - case NR_STATE_3: - queued = nr_state3_machine(sk, skb, frametype); - break; + case NR_STATE_1: + queued = nr_state1_machine(sk, skb, frametype); + break; + case NR_STATE_2: + queued = nr_state2_machine(sk, skb, frametype); + break; + case NR_STATE_3: + queued = nr_state3_machine(sk, skb, frametype); + break; } nr_kick(sk); diff -Nru a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c --- a/net/netrom/nr_loopback.c Fri Sep 20 08:20:47 2002 +++ b/net/netrom/nr_loopback.c Fri Sep 20 08:20:47 2002 @@ -1,20 +1,11 @@ /* - * NET/ROM release 007 - * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * NET/ROM 007 Tomi(OH2BNS) Created this file. - * Small change in nr_loopback_queue(). + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * + * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi) */ - #include #include #include diff -Nru a/net/netrom/nr_out.c b/net/netrom/nr_out.c --- a/net/netrom/nr_out.c Fri Sep 20 08:20:46 2002 +++ b/net/netrom/nr_out.c Fri Sep 20 08:20:46 2002 @@ -1,21 +1,12 @@ /* - * NET/ROM release 007 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_out.c - * NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragmentation. - * Darryl(G7LED) Fixed NAK, to give out correct reponse. - * NET/ROM 007 Jonathan(G4KLX) New timer architecture. + * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk) */ - #include #include #include @@ -85,7 +76,7 @@ nr_kick(sk); } -/* +/* * This procedure is passed a buffer descriptor for an iframe. It builds * the rest of the control part of the frame and then writes it out. */ @@ -104,7 +95,7 @@ nr_start_idletimer(sk); - nr_transmit_buffer(sk, skb); + nr_transmit_buffer(sk, skb); } void nr_send_nak_frame(struct sock *sk) @@ -196,7 +187,7 @@ void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb) { - nr_cb *nr = nr; + nr_cb *nr = nr_sk(sk); unsigned char *dptr; /* diff -Nru a/net/netrom/nr_route.c b/net/netrom/nr_route.c --- a/net/netrom/nr_route.c Fri Sep 20 08:20:48 2002 +++ b/net/netrom/nr_route.c Fri Sep 20 08:20:48 2002 @@ -1,26 +1,13 @@ /* - * NET/ROM release 007 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * NET/ROM 001 Jonathan(G4KLX) First attempt. - * NET/ROM 003 Jonathan(G4KLX) Use SIOCADDRT/SIOCDELRT ioctl values - * for NET/ROM routes. - * Use '*' for a blank mnemonic in /proc/net/nr_nodes. - * Change default quality for new neighbour when same - * as node callsign. - * Alan Cox(GW4PTS) Added the firewall hooks. - * NET/ROM 006 Jonathan(G4KLX) Added the setting of digipeated neighbours. - * Tomi(OH2BNS) Routing quality and link failure changes. + * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi) */ - #include #include #include @@ -47,12 +34,15 @@ #include #include #include +#include #include static unsigned int nr_neigh_no = 1; static struct nr_node *nr_node_list; +static spinlock_t nr_node_lock; static struct nr_neigh *nr_neigh_list; +static spinlock_t nr_neigh_lock; static void nr_remove_neigh(struct nr_neigh *); @@ -66,7 +56,6 @@ struct nr_node *nr_node; struct nr_neigh *nr_neigh; struct nr_route nr_route; - unsigned long flags; int i, found; if (nr_dev_get(nr) != NULL) /* Can't add routes to ourself */ @@ -124,13 +113,10 @@ memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi)); } - save_flags(flags); - cli(); - + spin_lock_bh(&nr_neigh_lock); nr_neigh->next = nr_neigh_list; nr_neigh_list = nr_neigh; - - restore_flags(flags); + spin_unlock_bh(&nr_neigh_lock); } if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked) @@ -150,13 +136,10 @@ nr_node->routes[0].obs_count = obs_count; nr_node->routes[0].neighbour = nr_neigh; - save_flags(flags); - cli(); - + spin_lock_bh(&nr_node_lock); nr_node->next = nr_node_list; nr_node_list = nr_node; - - restore_flags(flags); + spin_unlock_bh(&nr_node_lock); nr_neigh->count++; @@ -207,40 +190,49 @@ /* Now re-sort the routes in quality order */ switch (nr_node->count) { - case 3: - if (nr_node->routes[1].quality > nr_node->routes[0].quality) { - switch (nr_node->which) { - case 0: nr_node->which = 1; break; - case 1: nr_node->which = 0; break; - default: break; - } - nr_route = nr_node->routes[0]; - nr_node->routes[0] = nr_node->routes[1]; - nr_node->routes[1] = nr_route; + case 3: + if (nr_node->routes[1].quality > nr_node->routes[0].quality) { + switch (nr_node->which) { + case 0: nr_node->which = 1; break; + case 1: nr_node->which = 0; break; + default: break; } - if (nr_node->routes[2].quality > nr_node->routes[1].quality) { - switch (nr_node->which) { - case 1: nr_node->which = 2; break; - case 2: nr_node->which = 1; break; - default: break; - } - nr_route = nr_node->routes[1]; - nr_node->routes[1] = nr_node->routes[2]; - nr_node->routes[2] = nr_route; + nr_route = nr_node->routes[0]; + nr_node->routes[0] = nr_node->routes[1]; + nr_node->routes[1] = nr_route; + } + if (nr_node->routes[2].quality > nr_node->routes[1].quality) { + switch (nr_node->which) { + case 1: nr_node->which = 2; + break; + + case 2: nr_node->which = 1; + break; + + default: + break; } - case 2: - if (nr_node->routes[1].quality > nr_node->routes[0].quality) { - switch (nr_node->which) { - case 0: nr_node->which = 1; break; - case 1: nr_node->which = 0; break; - default: break; - } - nr_route = nr_node->routes[0]; - nr_node->routes[0] = nr_node->routes[1]; - nr_node->routes[1] = nr_route; + nr_route = nr_node->routes[1]; + nr_node->routes[1] = nr_node->routes[2]; + nr_node->routes[2] = nr_route; + } + case 2: + if (nr_node->routes[1].quality > nr_node->routes[0].quality) { + switch (nr_node->which) { + case 0: nr_node->which = 1; + break; + + case 1: nr_node->which = 0; + break; + + default: break; } - case 1: - break; + nr_route = nr_node->routes[0]; + nr_node->routes[0] = nr_node->routes[1]; + nr_node->routes[1] = nr_route; + } + case 1: + break; } for (i = 0; i < nr_node->count; i++) { @@ -257,14 +249,11 @@ static void nr_remove_node(struct nr_node *nr_node) { struct nr_node *s; - unsigned long flags; - - save_flags(flags); - cli(); + spin_lock_bh(&nr_node_lock); if ((s = nr_node_list) == nr_node) { nr_node_list = nr_node->next; - restore_flags(flags); + spin_unlock_bh(&nr_node_lock); kfree(nr_node); return; } @@ -272,7 +261,7 @@ while (s != NULL && s->next != NULL) { if (s->next == nr_node) { s->next = nr_node->next; - restore_flags(flags); + spin_unlock_bh(&nr_node_lock); kfree(nr_node); return; } @@ -280,20 +269,17 @@ s = s->next; } - restore_flags(flags); + spin_unlock_bh(&nr_node_lock); } static void nr_remove_neigh(struct nr_neigh *nr_neigh) { struct nr_neigh *s; - unsigned long flags; - - save_flags(flags); - cli(); + spin_lock_bh(&nr_neigh_lock); if ((s = nr_neigh_list) == nr_neigh) { nr_neigh_list = nr_neigh->next; - restore_flags(flags); + spin_unlock_bh(&nr_neigh_lock); if (nr_neigh->digipeat != NULL) kfree(nr_neigh->digipeat); kfree(nr_neigh); @@ -303,7 +289,7 @@ while (s != NULL && s->next != NULL) { if (s->next == nr_neigh) { s->next = nr_neigh->next; - restore_flags(flags); + spin_unlock_bh(&nr_neigh_lock); if (nr_neigh->digipeat != NULL) kfree(nr_neigh->digipeat); kfree(nr_neigh); @@ -312,8 +298,7 @@ s = s->next; } - - restore_flags(flags); + spin_unlock_bh(&nr_neigh_lock); } /* @@ -330,13 +315,15 @@ if (ax25cmp(callsign, &nr_node->callsign) == 0) break; - if (nr_node == NULL) return -EINVAL; + if (nr_node == NULL) + return -EINVAL; for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) break; - if (nr_neigh == NULL) return -EINVAL; + if (nr_neigh == NULL) + return -EINVAL; for (i = 0; i < nr_node->count; i++) { if (nr_node->routes[i].neighbour == nr_neigh) { @@ -351,12 +338,12 @@ nr_remove_node(nr_node); } else { switch (i) { - case 0: - nr_node->routes[0] = nr_node->routes[1]; - case 1: - nr_node->routes[1] = nr_node->routes[2]; - case 2: - break; + case 0: + nr_node->routes[0] = nr_node->routes[1]; + case 1: + nr_node->routes[1] = nr_node->routes[2]; + case 2: + break; } } @@ -373,7 +360,6 @@ static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality) { struct nr_neigh *nr_neigh; - unsigned long flags; for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) { if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) { @@ -404,15 +390,12 @@ memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi)); } - save_flags(flags); - cli(); - + spin_lock_bh(&nr_neigh_lock); nr_neigh->next = nr_neigh_list; nr_neigh_list = nr_neigh; + spin_unlock_bh(&nr_neigh_lock); - restore_flags(flags); - - return 0; + return 0; } /* @@ -457,7 +440,6 @@ for (i = 0; i < s->count; i++) { switch (s->routes[i].obs_count) { - case 0: /* A locked entry */ break; @@ -520,12 +502,12 @@ t->count--; switch (i) { - case 0: - t->routes[0] = t->routes[1]; - case 1: - t->routes[1] = t->routes[2]; - case 2: - break; + case 0: + t->routes[0] = t->routes[1]; + case 1: + t->routes[1] = t->routes[2]; + case 2: + break; } } } @@ -622,51 +604,50 @@ struct net_device *dev; switch (cmd) { + case SIOCADDRT: + if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) + return -EFAULT; + if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL) + return -EINVAL; + if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) + return -EINVAL; + switch (nr_route.type) { + case NETROM_NODE: + return nr_add_node(&nr_route.callsign, + nr_route.mnemonic, + &nr_route.neighbour, + nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters), + dev, nr_route.quality, + nr_route.obs_count); + case NETROM_NEIGH: + return nr_add_neigh(&nr_route.callsign, + nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters), + dev, nr_route.quality); + default: + return -EINVAL; + } - case SIOCADDRT: - if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) - return -EFAULT; - if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL) - return -EINVAL; - if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) - return -EINVAL; - switch (nr_route.type) { - case NETROM_NODE: - return nr_add_node(&nr_route.callsign, - nr_route.mnemonic, - &nr_route.neighbour, - nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters), - dev, nr_route.quality, - nr_route.obs_count); - case NETROM_NEIGH: - return nr_add_neigh(&nr_route.callsign, - nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters), - dev, nr_route.quality); - default: - return -EINVAL; - } - - case SIOCDELRT: - if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) - return -EFAULT; - if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL) - return -EINVAL; - switch (nr_route.type) { - case NETROM_NODE: - return nr_del_node(&nr_route.callsign, - &nr_route.neighbour, dev); - case NETROM_NEIGH: - return nr_del_neigh(&nr_route.callsign, - dev, nr_route.quality); - default: - return -EINVAL; - } - - case SIOCNRDECOBS: - return nr_dec_obs(); - + case SIOCDELRT: + if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) + return -EFAULT; + if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL) + return -EINVAL; + switch (nr_route.type) { + case NETROM_NODE: + return nr_del_node(&nr_route.callsign, + &nr_route.neighbour, dev); + case NETROM_NEIGH: + return nr_del_neigh(&nr_route.callsign, + dev, nr_route.quality); default: return -EINVAL; + } + + case SIOCNRDECOBS: + return nr_dec_obs(); + + default: + return -EINVAL; } return 0; @@ -758,8 +739,7 @@ off_t begin = 0; int i; - cli(); - + spin_lock_bh(&nr_node_lock); len += sprintf(buffer, "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n"); for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) { @@ -767,7 +747,7 @@ ax2asc(&nr_node->callsign), (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic, nr_node->which + 1, - nr_node->count); + nr_node->count); for (i = 0; i < nr_node->count; i++) { len += sprintf(buffer + len, " %3d %d %05d", @@ -788,8 +768,7 @@ if (pos > offset + length) break; } - - sti(); + spin_unlock_bh(&nr_node_lock); *start = buffer + (offset - begin); len -= (offset - begin); @@ -797,7 +776,7 @@ if (len > length) len = length; return len; -} +} int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length) { @@ -807,8 +786,7 @@ off_t begin = 0; int i; - cli(); - + spin_lock_bh(&nr_neigh_lock); len += sprintf(buffer, "addr callsign dev qual lock count failed digipeaters\n"); for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) { @@ -839,7 +817,7 @@ break; } - sti(); + spin_unlock_bh(&nr_neigh_lock); *start = buffer + (offset - begin); len -= (offset - begin); @@ -847,7 +825,7 @@ if (len > length) len = length; return len; -} +} /* * Free all memory associated with the nodes and routes lists. diff -Nru a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c --- a/net/netrom/nr_subr.c Fri Sep 20 08:20:49 2002 +++ b/net/netrom/nr_subr.c Fri Sep 20 08:20:49 2002 @@ -1,20 +1,11 @@ /* - * NET/ROM release 007 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_subr.c - * NET/ROM 003 Jonathan(G4KLX) Added G8BPQ NET/ROM extensions. - * NET/ROM 007 Jonathan(G4KLX) New timer architecture. + * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include @@ -125,7 +116,7 @@ return 0; } -/* +/* * This routine is called when the HDLC layer internally generates a * control frame. */ @@ -139,19 +130,19 @@ len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN; switch (frametype & 0x0F) { - case NR_CONNREQ: - len += 17; - break; - case NR_CONNACK: - len += (nr->bpqext) ? 2 : 1; - break; - case NR_DISCREQ: - case NR_DISCACK: - case NR_INFOACK: - break; - default: - printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype); - return; + case NR_CONNREQ: + len += 17; + break; + case NR_CONNACK: + len += (nr->bpqext) ? 2 : 1; + break; + case NR_DISCREQ: + case NR_DISCACK: + case NR_INFOACK: + break; + default: + printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype); + return; } if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) @@ -161,59 +152,58 @@ * Space for AX.25 and NET/ROM network header */ skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN); - + dptr = skb_put(skb, skb_tailroom(skb)); switch (frametype & 0x0F) { - - case NR_CONNREQ: - timeout = nr->t1 / HZ; - *dptr++ = nr->my_index; - *dptr++ = nr->my_id; - *dptr++ = 0; - *dptr++ = 0; - *dptr++ = frametype; - *dptr++ = nr->window; - memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN); - dptr[6] &= ~AX25_CBIT; - dptr[6] &= ~AX25_EBIT; - dptr[6] |= AX25_SSSID_SPARE; - dptr += AX25_ADDR_LEN; - memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN); - dptr[6] &= ~AX25_CBIT; - dptr[6] &= ~AX25_EBIT; - dptr[6] |= AX25_SSSID_SPARE; - dptr += AX25_ADDR_LEN; - *dptr++ = timeout % 256; - *dptr++ = timeout / 256; - break; - - case NR_CONNACK: - *dptr++ = nr->your_index; - *dptr++ = nr->your_id; - *dptr++ = nr->my_index; - *dptr++ = nr->my_id; - *dptr++ = frametype; - *dptr++ = nr->window; - if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser; - break; - - case NR_DISCREQ: - case NR_DISCACK: - *dptr++ = nr->your_index; - *dptr++ = nr->your_id; - *dptr++ = 0; - *dptr++ = 0; - *dptr++ = frametype; - break; - - case NR_INFOACK: - *dptr++ = nr->your_index; - *dptr++ = nr->your_id; - *dptr++ = 0; - *dptr++ = nr->vr; - *dptr++ = frametype; - break; + case NR_CONNREQ: + timeout = nr->t1 / HZ; + *dptr++ = nr->my_index; + *dptr++ = nr->my_id; + *dptr++ = 0; + *dptr++ = 0; + *dptr++ = frametype; + *dptr++ = nr->window; + memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN); + dptr[6] &= ~AX25_CBIT; + dptr[6] &= ~AX25_EBIT; + dptr[6] |= AX25_SSSID_SPARE; + dptr += AX25_ADDR_LEN; + memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN); + dptr[6] &= ~AX25_CBIT; + dptr[6] &= ~AX25_EBIT; + dptr[6] |= AX25_SSSID_SPARE; + dptr += AX25_ADDR_LEN; + *dptr++ = timeout % 256; + *dptr++ = timeout / 256; + break; + + case NR_CONNACK: + *dptr++ = nr->your_index; + *dptr++ = nr->your_id; + *dptr++ = nr->my_index; + *dptr++ = nr->my_id; + *dptr++ = frametype; + *dptr++ = nr->window; + if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser; + break; + + case NR_DISCREQ: + case NR_DISCACK: + *dptr++ = nr->your_index; + *dptr++ = nr->your_id; + *dptr++ = 0; + *dptr++ = 0; + *dptr++ = frametype; + break; + + case NR_INFOACK: + *dptr++ = nr->your_index; + *dptr++ = nr->your_id; + *dptr++ = 0; + *dptr++ = nr->vr; + *dptr++ = frametype; + break; } nr_transmit_buffer(sk, skb); @@ -243,7 +233,7 @@ dptr[6] &= ~AX25_EBIT; dptr[6] |= AX25_SSSID_SPARE; dptr += AX25_ADDR_LEN; - + memcpy(dptr, skb->data + 0, AX25_ADDR_LEN); dptr[6] &= ~AX25_CBIT; dptr[6] |= AX25_EBIT; diff -Nru a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c --- a/net/netrom/nr_timer.c Fri Sep 20 08:20:47 2002 +++ b/net/netrom/nr_timer.c Fri Sep 20 08:20:47 2002 @@ -1,20 +1,12 @@ /* - * NET/ROM release 007 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_timer.c - * NET/ROM 007 Jonathan(G4KLX) New timer architecture. - * Implemented idle timer. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org) */ - #include #include #include @@ -144,33 +136,34 @@ struct sock *sk = (struct sock *)param; nr_cb *nr = nr_sk(sk); + bh_lock_sock(sk); switch (nr->state) { - - case NR_STATE_0: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) { - nr_destroy_socket(sk); - return; - } - break; - - case NR_STATE_3: - /* - * Check for the state of the receive buffer. - */ - if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && - (nr->condition & NR_COND_OWN_RX_BUSY)) { - nr->condition &= ~NR_COND_OWN_RX_BUSY; - nr->condition &= ~NR_COND_ACK_PENDING; - nr->vl = nr->vr; - nr_write_internal(sk, NR_INFOACK); - break; - } + case NR_STATE_0: + /* Magic here: If we listen() and a new link dies before it + is accepted() it isn't 'dead' so doesn't get removed. */ + if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) { + nr_destroy_socket(sk); + return; + } + break; + + case NR_STATE_3: + /* + * Check for the state of the receive buffer. + */ + if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && + (nr->condition & NR_COND_OWN_RX_BUSY)) { + nr->condition &= ~NR_COND_OWN_RX_BUSY; + nr->condition &= ~NR_COND_ACK_PENDING; + nr->vl = nr->vr; + nr_write_internal(sk, NR_INFOACK); break; + } + break; } nr_start_heartbeat(sk); + bh_unlock_sock(sk); } static void nr_t2timer_expiry(unsigned long param) @@ -178,17 +171,21 @@ struct sock *sk = (struct sock *)param; nr_cb *nr = nr_sk(sk); + bh_lock_sock(sk); if (nr->condition & NR_COND_ACK_PENDING) { nr->condition &= ~NR_COND_ACK_PENDING; nr_enquiry_response(sk); } + bh_unlock_sock(sk); } static void nr_t4timer_expiry(unsigned long param) { struct sock *sk = (struct sock *)param; + bh_lock_sock(sk); nr_sk(sk)->condition &= ~NR_COND_PEER_RX_BUSY; + bh_unlock_sock(sk); } static void nr_idletimer_expiry(unsigned long param) @@ -196,6 +193,8 @@ struct sock *sk = (struct sock *)param; nr_cb *nr = nr_sk(sk); + bh_lock_sock(sk); + nr_clear_queues(sk); nr->n2count = 0; @@ -214,6 +213,7 @@ sk->state_change(sk); sk->dead = 1; + bh_unlock_sock(sk); } static void nr_t1timer_expiry(unsigned long param) @@ -221,38 +221,39 @@ struct sock *sk = (struct sock *)param; nr_cb *nr = nr_sk(sk); + bh_lock_sock(sk); switch (nr->state) { - - case NR_STATE_1: - if (nr->n2count == nr->n2) { - nr_disconnect(sk, ETIMEDOUT); - return; - } else { - nr->n2count++; - nr_write_internal(sk, NR_CONNREQ); - } - break; - - case NR_STATE_2: - if (nr->n2count == nr->n2) { - nr_disconnect(sk, ETIMEDOUT); - return; - } else { - nr->n2count++; - nr_write_internal(sk, NR_DISCREQ); - } - break; - - case NR_STATE_3: - if (nr->n2count == nr->n2) { - nr_disconnect(sk, ETIMEDOUT); - return; - } else { - nr->n2count++; - nr_requeue_frames(sk); - } - break; + case NR_STATE_1: + if (nr->n2count == nr->n2) { + nr_disconnect(sk, ETIMEDOUT); + return; + } else { + nr->n2count++; + nr_write_internal(sk, NR_CONNREQ); + } + break; + + case NR_STATE_2: + if (nr->n2count == nr->n2) { + nr_disconnect(sk, ETIMEDOUT); + return; + } else { + nr->n2count++; + nr_write_internal(sk, NR_DISCREQ); + } + break; + + case NR_STATE_3: + if (nr->n2count == nr->n2) { + nr_disconnect(sk, ETIMEDOUT); + return; + } else { + nr->n2count++; + nr_requeue_frames(sk); + } + break; } nr_start_t1timer(sk); + bh_unlock_sock(sk); } diff -Nru a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c --- a/net/netrom/sysctl_net_netrom.c Fri Sep 20 08:20:43 2002 +++ b/net/netrom/sysctl_net_netrom.c Fri Sep 20 08:20:43 2002 @@ -1,10 +1,11 @@ -/* -*- linux-c -*- - * sysctl_net_netrom.c: sysctl interface to net NET/ROM subsystem. +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * Begun April 1, 1996, Mike Shaver. - * Added /proc/sys/net/netrom directory entry (empty =) ). [MS] + * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com) */ - #include #include #include diff -Nru a/net/rose/af_rose.c b/net/rose/af_rose.c --- a/net/rose/af_rose.c Fri Sep 20 08:20:46 2002 +++ b/net/rose/af_rose.c Fri Sep 20 08:20:46 2002 @@ -1,29 +1,14 @@ /* - * ROSE release 003 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * ROSE 001 Jonathan(G4KLX) Cloned from af_netrom.c. - * Alan(GW4PTS) Hacked up for newer API stuff - * Terry (VK2KTJ) Added support for variable length - * address masks. - * ROSE 002 Jonathan(G4KLX) Changed hdrincl to qbitincl. - * Added random number facilities entry. - * Variable number of ROSE devices. - * ROSE 003 Jonathan(G4KLX) New timer architecture. - * Implemented idle timer. - * Added use count to neighbour. - * Tomi(OH2BNS) Fixed rose_getname(). - * Arnaldo C. Melo s/suser/capable/ + micro cleanups + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) + * Copyright (C) Terry Dawson VK2KTJ (terry@animats.net) + * Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi) */ - #include #include #include @@ -33,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +33,7 @@ #include #include #include -#include /* For TIOCINQ/OUTQ */ +#include #include #include #include @@ -71,6 +57,7 @@ int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE; static struct sock *rose_list; +static spinlock_t rose_list_lock = SPIN_LOCK_UNLOCKED; static struct proto_ops rose_proto_ops; @@ -173,27 +160,24 @@ static void rose_remove_socket(struct sock *sk) { struct sock *s; - unsigned long flags; - - save_flags(flags); cli(); + spin_lock_bh(&rose_list_lock); if ((s = rose_list) == sk) { rose_list = s->next; - restore_flags(flags); + spin_unlock_bh(&rose_list_lock); return; } while (s != NULL && s->next != NULL) { if (s->next == sk) { s->next = sk->next; - restore_flags(flags); + spin_unlock_bh(&rose_list_lock); return; } s = s->next; } - - restore_flags(flags); + spin_unlock_bh(&rose_list_lock); } /* @@ -204,6 +188,7 @@ { struct sock *s; + spin_lock_bh(&rose_list_lock); for (s = rose_list; s != NULL; s = s->next) { rose_cb *rose = rose_sk(s); @@ -213,6 +198,7 @@ rose->neighbour = NULL; } } + spin_unlock_bh(&rose_list_lock); } /* @@ -221,7 +207,8 @@ static void rose_kill_by_device(struct net_device *dev) { struct sock *s; - + + spin_lock_bh(&rose_list_lock); for (s = rose_list; s != NULL; s = s->next) { rose_cb *rose = rose_sk(s); @@ -231,12 +218,14 @@ rose->device = NULL; } } + spin_unlock_bh(&rose_list_lock); } /* * Handle device status changes. */ -static int rose_device_event(struct notifier_block *this, unsigned long event, void *ptr) +static int rose_device_event(struct notifier_block *this, unsigned long event, + void *ptr) { struct net_device *dev = (struct net_device *)ptr; @@ -244,13 +233,13 @@ return NOTIFY_DONE; switch (dev->type) { - case ARPHRD_ROSE: - rose_kill_by_device(dev); - break; - case ARPHRD_AX25: - rose_link_device_down(dev); - rose_rt_device_down(dev); - break; + case ARPHRD_ROSE: + rose_kill_by_device(dev); + break; + case ARPHRD_AX25: + rose_link_device_down(dev); + rose_rt_device_down(dev); + break; } return NOTIFY_DONE; @@ -261,14 +250,11 @@ */ static void rose_insert_socket(struct sock *sk) { - unsigned long flags; - - save_flags(flags); cli(); + spin_lock_bh(&rose_list_lock); sk->next = rose_list; rose_list = sk; - - restore_flags(flags); + spin_unlock_bh(&rose_list_lock); } /* @@ -277,18 +263,16 @@ */ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call) { - unsigned long flags; struct sock *s; - save_flags(flags); cli(); - + spin_lock_bh(&rose_list_lock); for (s = rose_list; s != NULL; s = s->next) { rose_cb *rose = rose_sk(s); if (!rosecmp(&rose->source_addr, addr) && !ax25cmp(&rose->source_call, call) && !rose->source_ndigis && s->state == TCP_LISTEN) { - restore_flags(flags); + spin_unlock_bh(&rose_list_lock); return s; } } @@ -299,12 +283,12 @@ if (!rosecmp(&rose->source_addr, addr) && !ax25cmp(&rose->source_call, &null_ax25_address) && s->state == TCP_LISTEN) { - restore_flags(flags); + spin_unlock_bh(&rose_list_lock); return s; } } + spin_unlock_bh(&rose_list_lock); - restore_flags(flags); return NULL; } @@ -314,20 +298,17 @@ struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh) { struct sock *s; - unsigned long flags; - - save_flags(flags); cli(); + spin_lock_bh(&rose_list_lock); for (s = rose_list; s != NULL; s = s->next) { rose_cb *rose = rose_sk(s); if (rose->lci == lci && rose->neighbour == neigh) { - restore_flags(flags); + spin_unlock_bh(&rose_list_lock); return s; } } - - restore_flags(flags); + spin_unlock_bh(&rose_list_lock); return NULL; } @@ -366,23 +347,20 @@ } /* - * This is called from user mode and the timers. Thus it protects itself against - * interrupt users but doesn't worry about being called during work. - * Once it is removed from the queue no interrupt or bottom half will - * touch it and we are (fairly 8-) ) safe. + * This is called from user mode and the timers. Thus it protects itself + * against interrupt users but doesn't worry about being called during + * work. Once it is removed from the queue no interrupt or bottom half + * will touch it and we are (fairly 8-) ) safe. */ -void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the timer */ +void rose_destroy_socket(struct sock *sk) { struct sk_buff *skb; - unsigned long flags; - - save_flags(flags); cli(); + rose_remove_socket(sk); rose_stop_heartbeat(sk); rose_stop_idletimer(sk); rose_stop_timer(sk); - rose_remove_socket(sk); rose_clear_queues(sk); /* Flush the queues */ while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { @@ -405,8 +383,6 @@ } else { rose_free_sock(sk); } - - restore_flags(flags); } /* @@ -431,46 +407,46 @@ return -EFAULT; switch (optname) { - case ROSE_DEFER: - rose->defer = opt ? 1 : 0; - return 0; - - case ROSE_T1: - if (opt < 1) - return -EINVAL; - rose->t1 = opt * HZ; - return 0; - - case ROSE_T2: - if (opt < 1) - return -EINVAL; - rose->t2 = opt * HZ; - return 0; - - case ROSE_T3: - if (opt < 1) - return -EINVAL; - rose->t3 = opt * HZ; - return 0; - - case ROSE_HOLDBACK: - if (opt < 1) - return -EINVAL; - rose->hb = opt * HZ; - return 0; - - case ROSE_IDLE: - if (opt < 0) - return -EINVAL; - rose->idle = opt * 60 * HZ; - return 0; - - case ROSE_QBITINCL: - rose->qbitincl = opt ? 1 : 0; - return 0; + case ROSE_DEFER: + rose->defer = opt ? 1 : 0; + return 0; + + case ROSE_T1: + if (opt < 1) + return -EINVAL; + rose->t1 = opt * HZ; + return 0; + + case ROSE_T2: + if (opt < 1) + return -EINVAL; + rose->t2 = opt * HZ; + return 0; + + case ROSE_T3: + if (opt < 1) + return -EINVAL; + rose->t3 = opt * HZ; + return 0; + + case ROSE_HOLDBACK: + if (opt < 1) + return -EINVAL; + rose->hb = opt * HZ; + return 0; + + case ROSE_IDLE: + if (opt < 0) + return -EINVAL; + rose->idle = opt * 60 * HZ; + return 0; - default: - return -ENOPROTOOPT; + case ROSE_QBITINCL: + rose->qbitincl = opt ? 1 : 0; + return 0; + + default: + return -ENOPROTOOPT; } } @@ -484,44 +460,44 @@ if (level != SOL_ROSE) return -ENOPROTOOPT; - + if (get_user(len, optlen)) return -EFAULT; if (len < 0) return -EINVAL; - - switch (optname) { - case ROSE_DEFER: - val = rose->defer; - break; - case ROSE_T1: - val = rose->t1 / HZ; - break; - - case ROSE_T2: - val = rose->t2 / HZ; - break; - - case ROSE_T3: - val = rose->t3 / HZ; - break; - - case ROSE_HOLDBACK: - val = rose->hb / HZ; - break; - - case ROSE_IDLE: - val = rose->idle / (60 * HZ); - break; - - case ROSE_QBITINCL: - val = rose->qbitincl; - break; + switch (optname) { + case ROSE_DEFER: + val = rose->defer; + break; + + case ROSE_T1: + val = rose->t1 / HZ; + break; + + case ROSE_T2: + val = rose->t2 / HZ; + break; + + case ROSE_T3: + val = rose->t3 / HZ; + break; + + case ROSE_HOLDBACK: + val = rose->hb / HZ; + break; + + case ROSE_IDLE: + val = rose->idle / (60 * HZ); + break; + + case ROSE_QBITINCL: + val = rose->qbitincl; + break; - default: - return -ENOPROTOOPT; + default: + return -ENOPROTOOPT; } len = min_t(unsigned int, len, sizeof(int)); @@ -565,7 +541,7 @@ rose = rose_sk(sk); sock_init_data(sock, sk); - + skb_queue_head_init(&rose->ack_queue); #ifdef M_BIT skb_queue_head_init(&rose->frag_queue); @@ -647,39 +623,38 @@ rose = rose_sk(sk); switch (rose->state) { + case ROSE_STATE_0: + rose_disconnect(sk, 0, -1, -1); + rose_destroy_socket(sk); + break; + + case ROSE_STATE_2: + rose->neighbour->use--; + rose_disconnect(sk, 0, -1, -1); + rose_destroy_socket(sk); + break; + + case ROSE_STATE_1: + case ROSE_STATE_3: + case ROSE_STATE_4: + case ROSE_STATE_5: + rose_clear_queues(sk); + rose_stop_idletimer(sk); + rose_write_internal(sk, ROSE_CLEAR_REQUEST); + rose_start_t3timer(sk); + rose->state = ROSE_STATE_2; + sk->state = TCP_CLOSE; + sk->shutdown |= SEND_SHUTDOWN; + sk->state_change(sk); + sk->dead = 1; + sk->destroy = 1; + break; - case ROSE_STATE_0: - rose_disconnect(sk, 0, -1, -1); - rose_destroy_socket(sk); - break; - - case ROSE_STATE_2: - rose->neighbour->use--; - rose_disconnect(sk, 0, -1, -1); - rose_destroy_socket(sk); - break; - - case ROSE_STATE_1: - case ROSE_STATE_3: - case ROSE_STATE_4: - case ROSE_STATE_5: - rose_clear_queues(sk); - rose_stop_idletimer(sk); - rose_write_internal(sk, ROSE_CLEAR_REQUEST); - rose_start_t3timer(sk); - rose->state = ROSE_STATE_2; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; - sk->destroy = 1; - break; - - default: - break; + default: + break; } - sock->sk = NULL; + sock->sk = NULL; sk->socket = NULL; /* Not used, but we should do this. **/ return 0; @@ -813,7 +788,7 @@ rose->dest_addr = addr->srose_addr; rose->dest_call = addr->srose_call; - rose->rand = ((int)rose & 0xFFFF) + rose->lci; + rose->rand = ((long)rose & 0xFFFF) + rose->lci; rose->dest_ndigis = addr->srose_ndigis; if (addr_len == sizeof(struct full_sockaddr_rose)) { @@ -842,71 +817,90 @@ if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) return -EINPROGRESS; - cli(); /* To avoid races on the sleep */ - /* - * A Connect Ack with Choke or timeout or failed routing will go to closed. + * A Connect Ack with Choke or timeout or failed routing will go to + * closed. */ - while (sk->state == TCP_SYN_SENT) { - interruptible_sleep_on(sk->sleep); - if (signal_pending(current)) { - sti(); + if (sk->state == TCP_SYN_SENT) { + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue(sk->sleep, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + if (sk->state != TCP_SYN_SENT) + break; + if (!signal_pending(tsk)) { + schedule(); + continue; + } return -ERESTARTSYS; } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep, &wait); } if (sk->state != TCP_ESTABLISHED) { - sti(); sock->state = SS_UNCONNECTED; return sock_error(sk); /* Always set at this point */ } sock->state = SS_CONNECTED; - sti(); - return 0; } static int rose_accept(struct socket *sock, struct socket *newsock, int flags) { - struct sock *sk; - struct sock *newsk; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); struct sk_buff *skb; + struct sock *newsk; + struct sock *sk; + int err = 0; if ((sk = sock->sk) == NULL) return -EINVAL; - if (sk->type != SOCK_SEQPACKET) - return -EOPNOTSUPP; + lock_sock(sk); + if (sk->type != SOCK_SEQPACKET) { + err = -EOPNOTSUPP; + goto out; + } - if (sk->state != TCP_LISTEN) - return -EINVAL; + if (sk->state != TCP_LISTEN) { + err = -EINVAL; + goto out; + } /* * The write queue this time is holding sockets ready to use * hooked into the SABM we saved */ - do { - cli(); - if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) { - if (flags & O_NONBLOCK) { - sti(); - return -EWOULDBLOCK; - } - interruptible_sleep_on(sk->sleep); - if (signal_pending(current)) { - sti(); - return -ERESTARTSYS; - } + add_wait_queue(sk->sleep, &wait); + for (;;) { + skb = skb_dequeue(&sk->receive_queue); + if (skb) + break; + + current->state = TASK_INTERRUPTIBLE; + release_sock(sk); + if (flags & O_NONBLOCK) + return -EWOULDBLOCK; + if (!signal_pending(tsk)) { + schedule(); + lock_sock(sk); + continue; } - } while (skb == NULL); + return -ERESTARTSYS; + } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep, &wait); newsk = skb->sk; newsk->pair = NULL; newsk->socket = newsock; newsk->sleep = &newsock->wait; - sti(); /* Now attach up the new socket */ skb->sk = NULL; @@ -914,7 +908,10 @@ sk->ack_backlog--; newsock->sk = newsk; - return 0; +out: + release_sock(sk); + + return err; } static int rose_getname(struct socket *sock, struct sockaddr *uaddr, @@ -961,7 +958,7 @@ * skb->data points to the rose frame start */ memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); - + len = (((skb->data[3] >> 4) & 0x0F) + 1) / 2; len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2; if (!rose_parse_facilities(skb->data + len + 4, &facilities)) { @@ -1028,7 +1025,7 @@ return 1; } -static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len, +static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) { struct sock *sk = sock->sk; @@ -1131,7 +1128,7 @@ SOCK_DEBUG(sk, "ROSE: Built header.\n"); SOCK_DEBUG(sk, "ROSE: Transmitting buffer\n"); - + if (sk->state != TCP_ESTABLISHED) { kfree_skb(skb); return -ENOTCONN; @@ -1144,7 +1141,7 @@ struct sk_buff *skbn; int frontlen; int lg; - + /* Save a copy of the Header */ memcpy(header, skb->data, ROSE_MIN_LEN); skb_pull(skb, ROSE_MIN_LEN); @@ -1173,10 +1170,10 @@ if (skb->len > 0) skbn->data[2] |= M_BIT; - + skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */ } - + skb->free = 1; kfree_skb(skb, FREE_WRITE); } else { @@ -1192,7 +1189,7 @@ } -static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size, +static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) { struct sock *sk = sock->sk; @@ -1264,96 +1261,96 @@ rose_cb *rose = rose_sk(sk); switch (cmd) { - case TIOCOUTQ: { - long amount; - amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); - if (amount < 0) - amount = 0; - return put_user(amount, (unsigned int *)arg); + case TIOCOUTQ: { + long amount; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + if (amount < 0) + amount = 0; + return put_user(amount, (unsigned int *)arg); + } + + case TIOCINQ: { + struct sk_buff *skb; + long amount = 0L; + /* These two are safe on a single CPU system as only user tasks fiddle here */ + if ((skb = skb_peek(&sk->receive_queue)) != NULL) + amount = skb->len; + return put_user(amount, (unsigned int *)arg); + } + + case SIOCGSTAMP: + if (sk != NULL) { + if (sk->stamp.tv_sec == 0) + return -ENOENT; + return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; } + return -EINVAL; - case TIOCINQ: { - struct sk_buff *skb; - long amount = 0L; - /* These two are safe on a single CPU system as only user tasks fiddle here */ - if ((skb = skb_peek(&sk->receive_queue)) != NULL) - amount = skb->len; - return put_user(amount, (unsigned int *)arg); - } + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + return -EINVAL; - case SIOCGSTAMP: - if (sk != NULL) { - if (sk->stamp.tv_sec == 0) - return -ENOENT; - return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; - } - return -EINVAL; + case SIOCADDRT: + case SIOCDELRT: + case SIOCRSCLRRT: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + return rose_rt_ioctl(cmd, (void *)arg); + + case SIOCRSGCAUSE: { + struct rose_cause_struct rose_cause; + rose_cause.cause = rose->cause; + rose_cause.diagnostic = rose->diagnostic; + return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0; + } + + case SIOCRSSCAUSE: { + struct rose_cause_struct rose_cause; + if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct))) + return -EFAULT; + rose->cause = rose_cause.cause; + rose->diagnostic = rose_cause.diagnostic; + return 0; + } - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - return -EINVAL; + case SIOCRSSL2CALL: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) + ax25_listen_release(&rose_callsign, NULL); + if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address))) + return -EFAULT; + if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) + ax25_listen_register(&rose_callsign, NULL); + return 0; - case SIOCADDRT: - case SIOCDELRT: - case SIOCRSCLRRT: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - return rose_rt_ioctl(cmd, (void *)arg); - - case SIOCRSGCAUSE: { - struct rose_cause_struct rose_cause; - rose_cause.cause = rose->cause; - rose_cause.diagnostic = rose->diagnostic; - return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0; - } + case SIOCRSGL2CALL: + return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0; - case SIOCRSSCAUSE: { - struct rose_cause_struct rose_cause; - if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct))) - return -EFAULT; - rose->cause = rose_cause.cause; - rose->diagnostic = rose_cause.diagnostic; - return 0; + case SIOCRSACCEPT: + if (rose->state == ROSE_STATE_5) { + rose_write_internal(sk, ROSE_CALL_ACCEPTED); + rose_start_idletimer(sk); + rose->condition = 0x00; + rose->vs = 0; + rose->va = 0; + rose->vr = 0; + rose->vl = 0; + rose->state = ROSE_STATE_3; } + return 0; - case SIOCRSSL2CALL: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) - ax25_listen_release(&rose_callsign, NULL); - if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address))) - return -EFAULT; - if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) - ax25_listen_register(&rose_callsign, NULL); - return 0; - - case SIOCRSGL2CALL: - return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0; - - case SIOCRSACCEPT: - if (rose->state == ROSE_STATE_5) { - rose_write_internal(sk, ROSE_CALL_ACCEPTED); - rose_start_idletimer(sk); - rose->condition = 0x00; - rose->vs = 0; - rose->va = 0; - rose->vr = 0; - rose->vl = 0; - rose->state = ROSE_STATE_3; - } - return 0; - - default: - return dev_ioctl(cmd, (void *)arg); + default: + return dev_ioctl(cmd, (void *)arg); } - /*NOTREACHED*/ return 0; } @@ -1366,7 +1363,7 @@ off_t pos = 0; off_t begin = 0; - cli(); + spin_lock_bh(&rose_list_lock); len += sprintf(buffer, "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n"); @@ -1390,7 +1387,7 @@ len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n", rose2asc(&rose->source_addr), callsign, - devname, + devname, rose->lci & 0x0FFF, (rose->neighbour) ? rose->neighbour->number : 0, rose->state, @@ -1418,48 +1415,44 @@ if (pos > offset + length) break; } - - sti(); + spin_unlock_bh(&rose_list_lock); *start = buffer + (offset - begin); len -= (offset - begin); if (len > length) len = length; - return(len); -} + return len; +} static struct net_proto_family rose_family_ops = { - .family = PF_ROSE, - .create = rose_create, + .family = PF_ROSE, + .create = rose_create, }; -static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = { - .family = PF_ROSE, +static struct proto_ops rose_proto_ops = { + .family = PF_ROSE, - .release = rose_release, - .bind = rose_bind, - .connect = rose_connect, - .socketpair = sock_no_socketpair, - .accept = rose_accept, - .getname = rose_getname, - .poll = datagram_poll, - .ioctl = rose_ioctl, - .listen = rose_listen, - .shutdown = sock_no_shutdown, - .setsockopt = rose_setsockopt, - .getsockopt = rose_getsockopt, - .sendmsg = rose_sendmsg, - .recvmsg = rose_recvmsg, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, + .release = rose_release, + .bind = rose_bind, + .connect = rose_connect, + .socketpair = sock_no_socketpair, + .accept = rose_accept, + .getname = rose_getname, + .poll = datagram_poll, + .ioctl = rose_ioctl, + .listen = rose_listen, + .shutdown = sock_no_shutdown, + .setsockopt = rose_setsockopt, + .getsockopt = rose_getsockopt, + .sendmsg = rose_sendmsg, + .recvmsg = rose_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, }; -#include -SOCKOPS_WRAP(rose_proto, PF_ROSE); - static struct notifier_block rose_dev_notifier = { - .notifier_call =rose_device_event, + .notifier_call = rose_device_event, }; static struct net_device *dev_rose; @@ -1555,5 +1548,5 @@ kfree(dev_rose); } -module_exit(rose_exit); +module_exit(rose_exit); diff -Nru a/net/rose/rose_dev.c b/net/rose/rose_dev.c --- a/net/rose/rose_dev.c Fri Sep 20 08:20:43 2002 +++ b/net/rose/rose_dev.c Fri Sep 20 08:20:43 2002 @@ -1,19 +1,11 @@ /* - * ROSE release 003 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * ROSE 001 Jonathan(G4KLX) Cloned from nr_dev.c. - * Hans(PE1AYX) Fixed interface to IP layer. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #define __NO_VERSION__ #include @@ -29,7 +21,7 @@ #include #include #include -#include /* For the statistics structure. */ +#include #include #include diff -Nru a/net/rose/rose_in.c b/net/rose/rose_in.c --- a/net/rose/rose_in.c Fri Sep 20 08:20:47 2002 +++ b/net/rose/rose_in.c Fri Sep 20 08:20:47 2002 @@ -1,27 +1,16 @@ /* - * ROSE release 003 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; - * - * History - * ROSE 001 Jonathan(G4KLX) Cloned from nr_in.c - * ROSE 002 Jonathan(G4KLX) Return cause and diagnostic codes from Clear Requests. - * ROSE 003 Jonathan(G4KLX) New timer architecture. - * Removed M bit processing. + * Most of this code is based on the SDL diagrams published in the 7th ARRL + * Computer Networking Conference papers. The diagrams have mistakes in them, + * but are mostly correct. Before you modify the code could you read the SDL + * diagrams as the code is not obvious and probably very easy to break. */ - #include #include #include @@ -55,29 +44,28 @@ rose_cb *rose = rose_sk(sk); switch (frametype) { + case ROSE_CALL_ACCEPTED: + rose_stop_timer(sk); + rose_start_idletimer(sk); + rose->condition = 0x00; + rose->vs = 0; + rose->va = 0; + rose->vr = 0; + rose->vl = 0; + rose->state = ROSE_STATE_3; + sk->state = TCP_ESTABLISHED; + if (!sk->dead) + sk->state_change(sk); + break; - case ROSE_CALL_ACCEPTED: - rose_stop_timer(sk); - rose_start_idletimer(sk); - rose->condition = 0x00; - rose->vs = 0; - rose->va = 0; - rose->vr = 0; - rose->vl = 0; - rose->state = ROSE_STATE_3; - sk->state = TCP_ESTABLISHED; - if (!sk->dead) - sk->state_change(sk); - break; - - case ROSE_CLEAR_REQUEST: - rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); - rose->neighbour->use--; - break; + case ROSE_CLEAR_REQUEST: + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); + rose->neighbour->use--; + break; - default: - break; + default: + break; } return 0; @@ -93,20 +81,19 @@ rose_cb *rose = rose_sk(sk); switch (frametype) { + case ROSE_CLEAR_REQUEST: + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); + rose->neighbour->use--; + break; - case ROSE_CLEAR_REQUEST: - rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose->neighbour->use--; - break; + case ROSE_CLEAR_CONFIRMATION: + rose_disconnect(sk, 0, -1, -1); + rose->neighbour->use--; + break; - case ROSE_CLEAR_CONFIRMATION: - rose_disconnect(sk, 0, -1, -1); - rose->neighbour->use--; - break; - - default: - break; + default: + break; } return 0; @@ -123,50 +110,68 @@ int queued = 0; switch (frametype) { + case ROSE_RESET_REQUEST: + rose_stop_timer(sk); + rose_start_idletimer(sk); + rose_write_internal(sk, ROSE_RESET_CONFIRMATION); + rose->condition = 0x00; + rose->vs = 0; + rose->vr = 0; + rose->va = 0; + rose->vl = 0; + rose_requeue_frames(sk); + break; - case ROSE_RESET_REQUEST: - rose_stop_timer(sk); - rose_start_idletimer(sk); - rose_write_internal(sk, ROSE_RESET_CONFIRMATION); + case ROSE_CLEAR_REQUEST: + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); + rose->neighbour->use--; + break; + + case ROSE_RR: + case ROSE_RNR: + if (!rose_validate_nr(sk, nr)) { + rose_write_internal(sk, ROSE_RESET_REQUEST); rose->condition = 0x00; rose->vs = 0; rose->vr = 0; rose->va = 0; rose->vl = 0; - rose_requeue_frames(sk); - break; - - case ROSE_CLEAR_REQUEST: - rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose->neighbour->use--; - break; - - case ROSE_RR: - case ROSE_RNR: - if (!rose_validate_nr(sk, nr)) { - rose_write_internal(sk, ROSE_RESET_REQUEST); - rose->condition = 0x00; - rose->vs = 0; - rose->vr = 0; - rose->va = 0; - rose->vl = 0; - rose->state = ROSE_STATE_4; - rose_start_t2timer(sk); - rose_stop_idletimer(sk); + rose->state = ROSE_STATE_4; + rose_start_t2timer(sk); + rose_stop_idletimer(sk); + } else { + rose_frames_acked(sk, nr); + if (frametype == ROSE_RNR) { + rose->condition |= ROSE_COND_PEER_RX_BUSY; } else { - rose_frames_acked(sk, nr); - if (frametype == ROSE_RNR) { - rose->condition |= ROSE_COND_PEER_RX_BUSY; - } else { - rose->condition &= ~ROSE_COND_PEER_RX_BUSY; - } + rose->condition &= ~ROSE_COND_PEER_RX_BUSY; } - break; + } + break; - case ROSE_DATA: /* XXX */ - rose->condition &= ~ROSE_COND_PEER_RX_BUSY; - if (!rose_validate_nr(sk, nr)) { + case ROSE_DATA: /* XXX */ + rose->condition &= ~ROSE_COND_PEER_RX_BUSY; + if (!rose_validate_nr(sk, nr)) { + rose_write_internal(sk, ROSE_RESET_REQUEST); + rose->condition = 0x00; + rose->vs = 0; + rose->vr = 0; + rose->va = 0; + rose->vl = 0; + rose->state = ROSE_STATE_4; + rose_start_t2timer(sk); + rose_stop_idletimer(sk); + break; + } + rose_frames_acked(sk, nr); + if (ns == rose->vr) { + rose_start_idletimer(sk); + if (sock_queue_rcv_skb(sk, skb) == 0) { + rose->vr = (rose->vr + 1) % ROSE_MODULUS; + queued = 1; + } else { + /* Should never happen ! */ rose_write_internal(sk, ROSE_RESET_REQUEST); rose->condition = 0x00; rose->vs = 0; @@ -178,45 +183,26 @@ rose_stop_idletimer(sk); break; } - rose_frames_acked(sk, nr); - if (ns == rose->vr) { - rose_start_idletimer(sk); - if (sock_queue_rcv_skb(sk, skb) == 0) { - rose->vr = (rose->vr + 1) % ROSE_MODULUS; - queued = 1; - } else { - /* Should never happen ! */ - rose_write_internal(sk, ROSE_RESET_REQUEST); - rose->condition = 0x00; - rose->vs = 0; - rose->vr = 0; - rose->va = 0; - rose->vl = 0; - rose->state = ROSE_STATE_4; - rose_start_t2timer(sk); - rose_stop_idletimer(sk); - break; - } - if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2)) - rose->condition |= ROSE_COND_OWN_RX_BUSY; - } - /* - * If the window is full, ack the frame, else start the - * acknowledge hold back timer. - */ - if (((rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == rose->vr) { - rose->condition &= ~ROSE_COND_ACK_PENDING; - rose_stop_timer(sk); - rose_enquiry_response(sk); - } else { - rose->condition |= ROSE_COND_ACK_PENDING; - rose_start_hbtimer(sk); - } - break; - - default: - printk(KERN_WARNING "ROSE: unknown %02X in state 3\n", frametype); - break; + if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2)) + rose->condition |= ROSE_COND_OWN_RX_BUSY; + } + /* + * If the window is full, ack the frame, else start the + * acknowledge hold back timer. + */ + if (((rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == rose->vr) { + rose->condition &= ~ROSE_COND_ACK_PENDING; + rose_stop_timer(sk); + rose_enquiry_response(sk); + } else { + rose->condition |= ROSE_COND_ACK_PENDING; + rose_start_hbtimer(sk); + } + break; + + default: + printk(KERN_WARNING "ROSE: unknown %02X in state 3\n", frametype); + break; } return queued; @@ -232,29 +218,28 @@ rose_cb *rose = rose_sk(sk); switch (frametype) { + case ROSE_RESET_REQUEST: + rose_write_internal(sk, ROSE_RESET_CONFIRMATION); + case ROSE_RESET_CONFIRMATION: + rose_stop_timer(sk); + rose_start_idletimer(sk); + rose->condition = 0x00; + rose->va = 0; + rose->vr = 0; + rose->vs = 0; + rose->vl = 0; + rose->state = ROSE_STATE_3; + rose_requeue_frames(sk); + break; - case ROSE_RESET_REQUEST: - rose_write_internal(sk, ROSE_RESET_CONFIRMATION); - case ROSE_RESET_CONFIRMATION: - rose_stop_timer(sk); - rose_start_idletimer(sk); - rose->condition = 0x00; - rose->va = 0; - rose->vr = 0; - rose->vs = 0; - rose->vl = 0; - rose->state = ROSE_STATE_3; - rose_requeue_frames(sk); - break; - - case ROSE_CLEAR_REQUEST: - rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose->neighbour->use--; - break; + case ROSE_CLEAR_REQUEST: + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); + rose->neighbour->use--; + break; - default: - break; + default: + break; } return 0; @@ -288,21 +273,21 @@ frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); switch (rose->state) { - case ROSE_STATE_1: - queued = rose_state1_machine(sk, skb, frametype); - break; - case ROSE_STATE_2: - queued = rose_state2_machine(sk, skb, frametype); - break; - case ROSE_STATE_3: - queued = rose_state3_machine(sk, skb, frametype, ns, nr, q, d, m); - break; - case ROSE_STATE_4: - queued = rose_state4_machine(sk, skb, frametype); - break; - case ROSE_STATE_5: - queued = rose_state5_machine(sk, skb, frametype); - break; + case ROSE_STATE_1: + queued = rose_state1_machine(sk, skb, frametype); + break; + case ROSE_STATE_2: + queued = rose_state2_machine(sk, skb, frametype); + break; + case ROSE_STATE_3: + queued = rose_state3_machine(sk, skb, frametype, ns, nr, q, d, m); + break; + case ROSE_STATE_4: + queued = rose_state4_machine(sk, skb, frametype); + break; + case ROSE_STATE_5: + queued = rose_state5_machine(sk, skb, frametype); + break; } rose_kick(sk); diff -Nru a/net/rose/rose_link.c b/net/rose/rose_link.c --- a/net/rose/rose_link.c Fri Sep 20 08:20:47 2002 +++ b/net/rose/rose_link.c Fri Sep 20 08:20:47 2002 @@ -1,19 +1,11 @@ /* - * ROSE release 003 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * ROSE 001 Jonathan(G4KLX) Cloned from rose_timer.c - * ROSE 003 Jonathan(G4KLX) New timer architecture. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include @@ -142,25 +134,25 @@ struct sk_buff *skbn; switch (frametype) { - case ROSE_RESTART_REQUEST: - rose_stop_t0timer(neigh); - neigh->restarted = 1; - neigh->dce_mode = (skb->data[3] == ROSE_DTE_ORIGINATED); - rose_transmit_restart_confirmation(neigh); - break; - - case ROSE_RESTART_CONFIRMATION: - rose_stop_t0timer(neigh); - neigh->restarted = 1; - break; - - case ROSE_DIAGNOSTIC: - printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]); - break; - - default: - printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype); - break; + case ROSE_RESTART_REQUEST: + rose_stop_t0timer(neigh); + neigh->restarted = 1; + neigh->dce_mode = (skb->data[3] == ROSE_DTE_ORIGINATED); + rose_transmit_restart_confirmation(neigh); + break; + + case ROSE_RESTART_CONFIRMATION: + rose_stop_t0timer(neigh); + neigh->restarted = 1; + break; + + case ROSE_DIAGNOSTIC: + printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]); + break; + + default: + printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype); + break; } if (neigh->restarted) { diff -Nru a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c --- a/net/rose/rose_loopback.c Fri Sep 20 08:20:43 2002 +++ b/net/rose/rose_loopback.c Fri Sep 20 08:20:43 2002 @@ -1,19 +1,11 @@ /* - * ROSE release 003 - * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * ROSE 003 Jonathan(G4KLX) Created this file from nr_loopback.c. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include diff -Nru a/net/rose/rose_out.c b/net/rose/rose_out.c --- a/net/rose/rose_out.c Fri Sep 20 08:20:46 2002 +++ b/net/rose/rose_out.c Fri Sep 20 08:20:46 2002 @@ -1,20 +1,11 @@ /* - * ROSE release 003 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * ROSE 001 Jonathan(G4KLX) Cloned from nr_out.c - * ROSE 003 Jonathan(G4KLX) New timer architecture. - * Removed M bit processing. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include @@ -36,7 +27,7 @@ #include #include -/* +/* * This procedure is passed a buffer descriptor for an iframe. It builds * the rest of the control part of the frame and then writes it out. */ @@ -52,7 +43,7 @@ rose_start_idletimer(sk); - rose_transmit_link(skb, rose->neighbour); + rose_transmit_link(skb, rose->neighbour); } void rose_kick(struct sock *sk) diff -Nru a/net/rose/rose_route.c b/net/rose/rose_route.c --- a/net/rose/rose_route.c Fri Sep 20 08:20:45 2002 +++ b/net/rose/rose_route.c Fri Sep 20 08:20:45 2002 @@ -1,24 +1,12 @@ /* - * ROSE release 003 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * ROSE 001 Jonathan(G4KLX) Cloned from nr_route.c. - * Terry(VK2KTJ) Added support for variable length - * address masks. - * ROSE 002 Jonathan(G4KLX) Uprated through routing of packets. - * Routing loop detection. - * ROSE 003 Jonathan(G4KLX) New timer architecture. - * Added use count to neighbours. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) Terry Dawson VK2KTJ (terry@animats.net) */ - #include #include #include @@ -51,8 +39,11 @@ static unsigned int rose_neigh_no = 1; static struct rose_node *rose_node_list; +static spinlock_t rose_node_list_lock = SPIN_LOCK_UNLOCKED; static struct rose_neigh *rose_neigh_list; +static spinlock_t rose_neigh_list_lock = SPIN_LOCK_UNLOCKED; static struct rose_route *rose_route_list; +static spinlock_t rose_route_list_lock = SPIN_LOCK_UNLOCKED; struct rose_neigh *rose_loopback_neigh; @@ -62,27 +53,44 @@ * Add a new route to a node, and in the process add the node and the * neighbour if it is new. */ -static int rose_add_node(struct rose_route_struct *rose_route, struct net_device *dev) +static int rose_add_node(struct rose_route_struct *rose_route, + struct net_device *dev) { struct rose_node *rose_node, *rose_tmpn, *rose_tmpp; struct rose_neigh *rose_neigh; - unsigned long flags; - int i; + int i, res = 0; + + spin_lock_bh(&rose_node_list_lock); + spin_lock_bh(&rose_neigh_list_lock); - for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) - if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0)) + rose_node = rose_node_list; + while (rose_node != NULL) { + if ((rose_node->mask == rose_route->mask) && + (rosecmpm(&rose_route->address, &rose_node->address, + rose_route->mask) == 0)) break; + rose_node = rose_node->next; + } - if (rose_node != NULL && rose_node->loopback) - return -EINVAL; + if (rose_node != NULL && rose_node->loopback) { + res = -EINVAL; + goto out; + } - for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) - if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev) + rose_neigh = rose_neigh_list; + while (rose_neigh != NULL) { + if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 + && rose_neigh->dev == dev) break; + rose_neigh = rose_neigh->next; + } if (rose_neigh == NULL) { - if ((rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL) - return -ENOMEM; + rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC); + if (rose_neigh == NULL) { + res = -ENOMEM; + goto out; + } rose_neigh->callsign = rose_route->neighbour; rose_neigh->digipeat = NULL; @@ -103,22 +111,22 @@ if (rose_route->ndigis != 0) { if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) { kfree(rose_neigh); - return -ENOMEM; + res = -ENOMEM; + goto out; } rose_neigh->digipeat->ndigi = rose_route->ndigis; rose_neigh->digipeat->lastrepeat = -1; for (i = 0; i < rose_route->ndigis; i++) { - rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i]; + rose_neigh->digipeat->calls[i] = + rose_route->digipeaters[i]; rose_neigh->digipeat->repeated[i] = 0; } } - save_flags(flags); cli(); rose_neigh->next = rose_neigh_list; rose_neigh_list = rose_neigh; - restore_flags(flags); } /* @@ -142,8 +150,11 @@ } /* create new node */ - if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL) - return -ENOMEM; + rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC); + if (rose_node == NULL) { + res = -ENOMEM; + goto out; + } rose_node->address = rose_route->address; rose_node->mask = rose_route->mask; @@ -151,8 +162,6 @@ rose_node->loopback = 0; rose_node->neighbour[0] = rose_neigh; - save_flags(flags); cli(); - if (rose_tmpn == NULL) { if (rose_tmpp == NULL) { /* Empty list */ rose_node_list = rose_node; @@ -170,12 +179,9 @@ rose_node->next = rose_tmpn; } } - - restore_flags(flags); - rose_neigh->count++; - return 0; + goto out; } /* We have space, slot it in */ @@ -185,20 +191,23 @@ rose_neigh->count++; } - return 0; +out: + spin_unlock_bh(&rose_neigh_list_lock); + spin_unlock_bh(&rose_node_list_lock); + + return res; } +/* + * Caller is holding rose_node_list_lock. + */ static void rose_remove_node(struct rose_node *rose_node) { struct rose_node *s; - unsigned long flags; - - save_flags(flags); - cli(); + spin_lock_bh(&rose_node_list_lock); if ((s = rose_node_list) == rose_node) { rose_node_list = rose_node->next; - restore_flags(flags); kfree(rose_node); return; } @@ -206,32 +215,31 @@ while (s != NULL && s->next != NULL) { if (s->next == rose_node) { s->next = rose_node->next; - restore_flags(flags); kfree(rose_node); return; } s = s->next; } - - restore_flags(flags); } +/* + * Caller is holding rose_neigh_list_lock. + */ static void rose_remove_neigh(struct rose_neigh *rose_neigh) { struct rose_neigh *s; - unsigned long flags; rose_stop_ftimer(rose_neigh); rose_stop_t0timer(rose_neigh); skb_queue_purge(&rose_neigh->queue); - save_flags(flags); cli(); + spin_lock_bh(&rose_neigh_list_lock); if ((s = rose_neigh_list) == rose_neigh) { rose_neigh_list = rose_neigh->next; - restore_flags(flags); + spin_unlock_bh(&rose_neigh_list_lock); if (rose_neigh->digipeat != NULL) kfree(rose_neigh->digipeat); kfree(rose_neigh); @@ -241,7 +249,7 @@ while (s != NULL && s->next != NULL) { if (s->next == rose_neigh) { s->next = rose_neigh->next; - restore_flags(flags); + spin_unlock_bh(&rose_neigh_list_lock); if (rose_neigh->digipeat != NULL) kfree(rose_neigh->digipeat); kfree(rose_neigh); @@ -250,14 +258,15 @@ s = s->next; } - - restore_flags(flags); + spin_unlock_bh(&rose_neigh_list_lock); } +/* + * Caller is holding rose_route_list_lock. + */ static void rose_remove_route(struct rose_route *rose_route) { struct rose_route *s; - unsigned long flags; if (rose_route->neigh1 != NULL) rose_route->neigh1->use--; @@ -265,11 +274,8 @@ if (rose_route->neigh2 != NULL) rose_route->neigh2->use--; - save_flags(flags); cli(); - if ((s = rose_route_list) == rose_route) { rose_route_list = rose_route->next; - restore_flags(flags); kfree(rose_route); return; } @@ -277,40 +283,54 @@ while (s != NULL && s->next != NULL) { if (s->next == rose_route) { s->next = rose_route->next; - restore_flags(flags); kfree(rose_route); return; } s = s->next; } - - restore_flags(flags); } /* * "Delete" a node. Strictly speaking remove a route to a node. The node * is only deleted if no routes are left to it. */ -static int rose_del_node(struct rose_route_struct *rose_route, struct net_device *dev) +static int rose_del_node(struct rose_route_struct *rose_route, + struct net_device *dev) { struct rose_node *rose_node; struct rose_neigh *rose_neigh; - int i; + int i, err = 0; - for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) - if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0)) - break; + spin_lock_bh(&rose_node_list_lock); + spin_lock_bh(&rose_neigh_list_lock); - if (rose_node == NULL) return -EINVAL; + rose_node = rose_node_list; + while (rose_node != NULL) { + if ((rose_node->mask == rose_route->mask) && + (rosecmpm(&rose_route->address, &rose_node->address, + rose_route->mask) == 0)) + break; + rose_node = rose_node->next; + } - if (rose_node->loopback) return -EINVAL; + if (rose_node == NULL || rose_node->loopback) { + err = -EINVAL; + goto out; + } - for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) - if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev) + rose_neigh = rose_neigh_list; + while (rose_neigh != NULL) { + if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 + && rose_neigh->dev == dev) break; + rose_neigh = rose_neigh->next; + } - if (rose_neigh == NULL) return -EINVAL; + if (rose_neigh == NULL) { + err = -EINVAL; + goto out; + } for (i = 0; i < rose_node->count; i++) { if (rose_node->neighbour[i] == rose_neigh) { @@ -325,20 +345,26 @@ rose_remove_node(rose_node); } else { switch (i) { - case 0: - rose_node->neighbour[0] = rose_node->neighbour[1]; - case 1: - rose_node->neighbour[1] = rose_node->neighbour[2]; - case 2: - break; + case 0: + rose_node->neighbour[0] = + rose_node->neighbour[1]; + case 1: + rose_node->neighbour[1] = + rose_node->neighbour[2]; + case 2: + break; } } - - return 0; + goto out; } } + err = -EINVAL; + +out: + spin_unlock_bh(&rose_neigh_list_lock); + spin_unlock_bh(&rose_node_list_lock); - return -EINVAL; + return err; } /* @@ -346,8 +372,6 @@ */ int rose_add_loopback_neigh(void) { - unsigned long flags; - if ((rose_loopback_neigh = kmalloc(sizeof(struct rose_neigh), GFP_ATOMIC)) == NULL) return -ENOMEM; @@ -367,10 +391,10 @@ init_timer(&rose_loopback_neigh->ftimer); init_timer(&rose_loopback_neigh->t0timer); - save_flags(flags); cli(); + spin_lock_bh(&rose_neigh_list_lock); rose_loopback_neigh->next = rose_neigh_list; rose_neigh_list = rose_loopback_neigh; - restore_flags(flags); + spin_unlock_bh(&rose_neigh_list_lock); return 0; } @@ -381,16 +405,26 @@ int rose_add_loopback_node(rose_address *address) { struct rose_node *rose_node; - unsigned long flags; + unsigned int err = 0; + + spin_lock_bh(&rose_node_list_lock); - for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) - if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback) + rose_node = rose_node_list; + while (rose_node != NULL) { + if ((rose_node->mask == 10) && + (rosecmpm(address, &rose_node->address, 10) == 0) && + rose_node->loopback) break; + rose_node = rose_node->next; + } - if (rose_node != NULL) return 0; - - if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL) - return -ENOMEM; + if (rose_node != NULL) + goto out; + + if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL) { + err = -ENOMEM; + goto out; + } rose_node->address = *address; rose_node->mask = 10; @@ -399,13 +433,14 @@ rose_node->neighbour[0] = rose_loopback_neigh; /* Insert at the head of list. Address is always mask=10 */ - save_flags(flags); cli(); rose_node->next = rose_node_list; rose_node_list = rose_node; - restore_flags(flags); rose_loopback_neigh->count++; +out: + spin_unlock_bh(&rose_node_list_lock); + return 0; } @@ -416,15 +451,26 @@ { struct rose_node *rose_node; - for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) - if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback) + spin_lock_bh(&rose_node_list_lock); + + rose_node = rose_node_list; + while (rose_node != NULL) { + if ((rose_node->mask == 10) && + (rosecmpm(address, &rose_node->address, 10) == 0) && + rose_node->loopback) break; + rose_node = rose_node->next; + } - if (rose_node == NULL) return; + if (rose_node == NULL) + goto out; rose_remove_node(rose_node); rose_loopback_neigh->count--; + +out: + spin_unlock_bh(&rose_node_list_lock); } /* @@ -432,52 +478,62 @@ */ void rose_rt_device_down(struct net_device *dev) { - struct rose_neigh *s, *rose_neigh = rose_neigh_list; + struct rose_neigh *s, *rose_neigh; struct rose_node *t, *rose_node; int i; + spin_lock_bh(&rose_node_list_lock); + spin_lock_bh(&rose_neigh_list_lock); + rose_neigh = rose_neigh_list; while (rose_neigh != NULL) { s = rose_neigh; rose_neigh = rose_neigh->next; - if (s->dev == dev) { - rose_node = rose_node_list; + if (s->dev != dev) + continue; - while (rose_node != NULL) { - t = rose_node; - rose_node = rose_node->next; - - for (i = 0; i < t->count; i++) { - if (t->neighbour[i] == s) { - t->count--; - - switch (i) { - case 0: - t->neighbour[0] = t->neighbour[1]; - case 1: - t->neighbour[1] = t->neighbour[2]; - case 2: - break; - } - } - } + rose_node = rose_node_list; + + while (rose_node != NULL) { + t = rose_node; + rose_node = rose_node->next; + + for (i = 0; i < t->count; i++) { + if (t->neighbour[i] != s) + continue; + + t->count--; - if (t->count <= 0) - rose_remove_node(t); + switch (i) { + case 0: + t->neighbour[0] = t->neighbour[1]; + case 1: + t->neighbour[1] = t->neighbour[2]; + case 2: + break; + } } - rose_remove_neigh(s); + if (t->count <= 0) + rose_remove_node(t); } + + rose_remove_neigh(s); } + spin_unlock_bh(&rose_neigh_list_lock); + spin_unlock_bh(&rose_node_list_lock); } +#if 0 /* Currently unused */ /* * A device has been removed. Remove its links. */ void rose_route_device_down(struct net_device *dev) { - struct rose_route *s, *rose_route = rose_route_list; + struct rose_route *s, *rose_route; + spin_lock_bh(&rose_route_list_lock); + rose_route = rose_route_list; while (rose_route != NULL) { s = rose_route; rose_route = rose_route->next; @@ -485,7 +541,9 @@ if (s->neigh1->dev == dev || s->neigh2->dev == dev) rose_remove_route(s); } + spin_unlock_bh(&rose_route_list_lock); } +#endif /* * Clear all nodes and neighbours out, except for neighbours with @@ -494,8 +552,14 @@ */ static int rose_clear_routes(void) { - struct rose_neigh *s, *rose_neigh = rose_neigh_list; - struct rose_node *t, *rose_node = rose_node_list; + struct rose_neigh *s, *rose_neigh; + struct rose_node *t, *rose_node; + + spin_lock_bh(&rose_node_list_lock); + spin_lock_bh(&rose_neigh_list_lock); + + rose_neigh = rose_neigh_list; + rose_node = rose_node_list; while (rose_node != NULL) { t = rose_node; @@ -514,6 +578,9 @@ } } + spin_unlock_bh(&rose_neigh_list_lock); + spin_unlock_bh(&rose_node_list_lock); + return 0; } @@ -603,18 +670,22 @@ /* * Find a neighbour given a ROSE address. */ -struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsigned char *diagnostic) +struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, + unsigned char *diagnostic) { + struct rose_neigh *res = NULL; struct rose_node *node; int failed = 0; int i; + spin_lock_bh(&rose_node_list_lock); for (node = rose_node_list; node != NULL; node = node->next) { if (rosecmpm(addr, &node->address, node->mask) == 0) { for (i = 0; i < node->count; i++) { if (!rose_ftimer_running(node->neighbour[i])) { - return node->neighbour[i]; } - else + res = node->neighbour[i]; + goto out; + } else failed = 1; } break; @@ -629,7 +700,10 @@ *diagnostic = 0; } - return NULL; +out: + spin_unlock_bh(&rose_node_list_lock); + + return res; } /* @@ -642,38 +716,36 @@ int err; switch (cmd) { - - case SIOCADDRT: - if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) - return -EFAULT; - if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) - return -EINVAL; - if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */ - dev_put(dev); - return -EINVAL; - } - if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ - return -EINVAL; - - err = rose_add_node(&rose_route, dev); + case SIOCADDRT: + if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) + return -EFAULT; + if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) + return -EINVAL; + if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */ dev_put(dev); - return err; + return -EINVAL; + } + if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ + return -EINVAL; - case SIOCDELRT: - if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) - return -EFAULT; - if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) - return -EINVAL; - err = rose_del_node(&rose_route, dev); - dev_put(dev); - return err; - + err = rose_add_node(&rose_route, dev); + dev_put(dev); + return err; + + case SIOCDELRT: + if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) + return -EFAULT; + if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) + return -EINVAL; + err = rose_del_node(&rose_route, dev); + dev_put(dev); + return err; - case SIOCRSCLRRT: - return rose_clear_routes(); + case SIOCRSCLRRT: + return rose_clear_routes(); - default: - return -EINVAL; + default: + return -EINVAL; } return 0; @@ -690,6 +762,8 @@ skb_queue_purge(&rose_neigh->queue); + spin_lock_bh(&rose_route_list_lock); + rose_route = rose_route_list; while (rose_route != NULL) { @@ -716,6 +790,7 @@ rose_route = rose_route->next; } + spin_unlock_bh(&rose_route_list_lock); } /* @@ -727,16 +802,21 @@ { struct rose_neigh *rose_neigh; - for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) + spin_lock_bh(&rose_neigh_list_lock); + rose_neigh = rose_neigh_list; + while (rose_neigh != NULL) { if (rose_neigh->ax25 == ax25) break; + rose_neigh = rose_neigh->next; + } - if (rose_neigh == NULL) return; - - rose_neigh->ax25 = NULL; + if (rose_neigh != NULL) { + rose_neigh->ax25 = NULL; - rose_del_route_by_neigh(rose_neigh); - rose_kill_by_neigh(rose_neigh); + rose_del_route_by_neigh(rose_neigh); + rose_kill_by_neigh(rose_neigh); + } + spin_unlock_bh(&rose_neigh_list_lock); } /* @@ -769,12 +849,11 @@ unsigned int lci, new_lci; unsigned char cause, diagnostic; struct net_device *dev; - unsigned long flags; - int len; + int len, res = 0; #if 0 if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) - return 0; + return res; #endif frametype = skb->data[2]; @@ -782,13 +861,22 @@ src_addr = (rose_address *)(skb->data + 9); dest_addr = (rose_address *)(skb->data + 4); - for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) - if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->ax25_dev->dev == rose_neigh->dev) + spin_lock_bh(&rose_node_list_lock); + spin_lock_bh(&rose_neigh_list_lock); + spin_lock_bh(&rose_route_list_lock); + + rose_neigh = rose_neigh_list; + while (rose_neigh != NULL) { + if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && + ax25->ax25_dev->dev == rose_neigh->dev) break; + rose_neigh = rose_neigh->next; + } if (rose_neigh == NULL) { - printk("rose_route : unknown neighbour or device %s\n", ax2asc(&ax25->dest_addr)); - return 0; + printk("rose_route : unknown neighbour or device %s\n", + ax2asc(&ax25->dest_addr)); + goto out; } /* @@ -802,7 +890,7 @@ */ if (lci == 0) { rose_link_rx_restart(skb, rose_neigh, frametype); - return 0; + goto out; } /* @@ -828,7 +916,8 @@ } else { skb->h.raw = skb->data; - return rose_process_rx_frame(sk, skb); + res = rose_process_rx_frame(sk, skb); + goto out; } } @@ -837,21 +926,23 @@ */ if (frametype == ROSE_CALL_REQUEST) if ((dev = rose_dev_get(dest_addr)) != NULL) { - int err = rose_rx_call_request(skb, dev, rose_neigh, lci); + res = rose_rx_call_request(skb, dev, rose_neigh, lci); dev_put(dev); - return err; + goto out; } if (!sysctl_rose_routing_control) { rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0); - return 0; + goto out; } /* * Route it to the next in line if we have an entry for it. */ - for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) { - if (rose_route->lci1 == lci && rose_route->neigh1 == rose_neigh) { + rose_route = rose_route_list; + while (rose_route != NULL) { + if (rose_route->lci1 == lci && + rose_route->neigh1 == rose_neigh) { if (frametype == ROSE_CALL_REQUEST) { /* F6FBB - Remove an existing unused route */ rose_remove_route(rose_route); @@ -863,14 +954,16 @@ rose_transmit_link(skb, rose_route->neigh2); if (frametype == ROSE_CLEAR_CONFIRMATION) rose_remove_route(rose_route); - return 1; + res = 1; + goto out; } else { if (frametype == ROSE_CLEAR_CONFIRMATION) rose_remove_route(rose_route); - return 0; + goto out; } } - if (rose_route->lci2 == lci && rose_route->neigh2 == rose_neigh) { + if (rose_route->lci2 == lci && + rose_route->neigh2 == rose_neigh) { if (frametype == ROSE_CALL_REQUEST) { /* F6FBB - Remove an existing unused route */ rose_remove_route(rose_route); @@ -882,13 +975,15 @@ rose_transmit_link(skb, rose_route->neigh1); if (frametype == ROSE_CLEAR_CONFIRMATION) rose_remove_route(rose_route); - return 1; + res = 1; + goto out; } else { if (frametype == ROSE_CLEAR_CONFIRMATION) rose_remove_route(rose_route); - return 0; + goto out; } } + rose_route = rose_route->next; } /* @@ -903,38 +998,40 @@ len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2; memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); - + if (!rose_parse_facilities(skb->data + len + 4, &facilities)) { rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76); - return 0; + goto out; } /* * Check for routing loops. */ - for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) { + rose_route = rose_route_list; + while (rose_route != NULL) { if (rose_route->rand == facilities.rand && rosecmp(src_addr, &rose_route->src_addr) == 0 && ax25cmp(&facilities.dest_call, &rose_route->src_call) == 0 && ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) { rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120); - return 0; + goto out; } + rose_route = rose_route->next; } if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) { rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic); - return 0; + goto out; } if ((new_lci = rose_new_lci(new_neigh)) == 0) { rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71); - return 0; + goto out; } if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) { rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120); - return 0; + goto out; } rose_route->lci1 = lci; @@ -950,18 +1047,22 @@ rose_route->neigh1->use++; rose_route->neigh2->use++; - save_flags(flags); cli(); rose_route->next = rose_route_list; rose_route_list = rose_route; - restore_flags(flags); skb->data[0] &= 0xF0; skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F; skb->data[1] = (rose_route->lci2 >> 0) & 0xFF; rose_transmit_link(skb, rose_route->neigh2); + res = 1; + +out: + spin_unlock_bh(&rose_route_list_lock); + spin_unlock_bh(&rose_neigh_list_lock); + spin_unlock_bh(&rose_node_list_lock); - return 1; + return res; } int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length) @@ -972,7 +1073,7 @@ off_t begin = 0; int i; - cli(); + spin_lock_bh(&rose_neigh_list_lock); len += sprintf(buffer, "address mask n neigh neigh neigh\n"); @@ -1004,16 +1105,16 @@ if (pos > offset + length) break; } - - sti(); + spin_unlock_bh(&rose_neigh_list_lock); *start = buffer + (offset - begin); len -= (offset - begin); - if (len > length) len = length; + if (len > length) + len = length; return len; -} +} int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length) { @@ -1023,7 +1124,7 @@ off_t begin = 0; int i; - cli(); + spin_lock_bh(&rose_neigh_list_lock); len += sprintf(buffer, "addr callsign dev count use mode restart t0 tf digipeaters\n"); @@ -1059,15 +1160,16 @@ /* } */ } - sti(); + spin_unlock_bh(&rose_neigh_list_lock); *start = buffer + (offset - begin); len -= (offset - begin); - if (len > length) len = length; + if (len > length) + len = length; return len; -} +} int rose_routes_get_info(char *buffer, char **start, off_t offset, int length) { @@ -1076,7 +1178,7 @@ off_t pos = 0; off_t begin = 0; - cli(); + spin_lock_bh(&rose_route_list_lock); len += sprintf(buffer, "lci address callsign neigh <-> lci address callsign neigh\n"); @@ -1112,15 +1214,16 @@ break; } - sti(); + spin_unlock_bh(&rose_route_list_lock); *start = buffer + (offset - begin); len -= (offset - begin); - if (len > length) len = length; + if (len > length) + len = length; return len; -} +} /* * Release all memory associated with ROSE routing structures. diff -Nru a/net/rose/rose_subr.c b/net/rose/rose_subr.c --- a/net/rose/rose_subr.c Fri Sep 20 08:20:46 2002 +++ b/net/rose/rose_subr.c Fri Sep 20 08:20:46 2002 @@ -1,20 +1,11 @@ /* - * ROSE release 003 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * ROSE 001 Jonathan(G4KLX) Cloned from nr_subr.c - * ROSE 002 Jonathan(G4KLX) Centralised disconnect processing. - * ROSE 003 Jonathan(G4KLX) Added use count to neighbours. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ - #include #include #include @@ -103,7 +94,7 @@ return nr == rose->vs; } -/* +/* * This routine is called when the packet layer internally generates a * control frame. */ @@ -119,16 +110,16 @@ len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1; switch (frametype) { - case ROSE_CALL_REQUEST: - len += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN; - faclen = rose_create_facilities(buffer, rose); - len += faclen; - break; - case ROSE_CALL_ACCEPTED: - case ROSE_CLEAR_REQUEST: - case ROSE_RESET_REQUEST: - len += 2; - break; + case ROSE_CALL_REQUEST: + len += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN; + faclen = rose_create_facilities(buffer, rose); + len += faclen; + break; + case ROSE_CALL_ACCEPTED: + case ROSE_CLEAR_REQUEST: + case ROSE_RESET_REQUEST: + len += 2; + break; } if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) @@ -138,70 +129,69 @@ * Space for AX.25 header and PID. */ skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1); - + dptr = skb_put(skb, skb_tailroom(skb)); lci1 = (rose->lci >> 8) & 0x0F; lci2 = (rose->lci >> 0) & 0xFF; switch (frametype) { - - case ROSE_CALL_REQUEST: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr++ = frametype; - *dptr++ = 0xAA; - memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN); - dptr += ROSE_ADDR_LEN; - memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); - dptr += ROSE_ADDR_LEN; - memcpy(dptr, buffer, faclen); - dptr += faclen; - break; - - case ROSE_CALL_ACCEPTED: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr++ = frametype; - *dptr++ = 0x00; /* Address length */ - *dptr++ = 0; /* Facilities length */ - break; - - case ROSE_CLEAR_REQUEST: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr++ = frametype; - *dptr++ = rose->cause; - *dptr++ = rose->diagnostic; - break; - - case ROSE_RESET_REQUEST: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr++ = frametype; - *dptr++ = ROSE_DTE_ORIGINATED; - *dptr++ = 0; - break; - - case ROSE_RR: - case ROSE_RNR: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr = frametype; - *dptr++ |= (rose->vr << 5) & 0xE0; - break; - - case ROSE_CLEAR_CONFIRMATION: - case ROSE_RESET_CONFIRMATION: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr++ = frametype; - break; - - default: - printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype); - kfree_skb(skb); - return; + case ROSE_CALL_REQUEST: + *dptr++ = ROSE_GFI | lci1; + *dptr++ = lci2; + *dptr++ = frametype; + *dptr++ = 0xAA; + memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN); + dptr += ROSE_ADDR_LEN; + memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); + dptr += ROSE_ADDR_LEN; + memcpy(dptr, buffer, faclen); + dptr += faclen; + break; + + case ROSE_CALL_ACCEPTED: + *dptr++ = ROSE_GFI | lci1; + *dptr++ = lci2; + *dptr++ = frametype; + *dptr++ = 0x00; /* Address length */ + *dptr++ = 0; /* Facilities length */ + break; + + case ROSE_CLEAR_REQUEST: + *dptr++ = ROSE_GFI | lci1; + *dptr++ = lci2; + *dptr++ = frametype; + *dptr++ = rose->cause; + *dptr++ = rose->diagnostic; + break; + + case ROSE_RESET_REQUEST: + *dptr++ = ROSE_GFI | lci1; + *dptr++ = lci2; + *dptr++ = frametype; + *dptr++ = ROSE_DTE_ORIGINATED; + *dptr++ = 0; + break; + + case ROSE_RR: + case ROSE_RNR: + *dptr++ = ROSE_GFI | lci1; + *dptr++ = lci2; + *dptr = frametype; + *dptr++ |= (rose->vr << 5) & 0xE0; + break; + + case ROSE_CLEAR_CONFIRMATION: + case ROSE_RESET_CONFIRMATION: + *dptr++ = ROSE_GFI | lci1; + *dptr++ = lci2; + *dptr++ = frametype; + break; + + default: + printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype); + kfree_skb(skb); + return; } rose_transmit_link(skb, rose->neighbour); @@ -216,15 +206,15 @@ *ns = *nr = *q = *d = *m = 0; switch (frame[2]) { - case ROSE_CALL_REQUEST: - case ROSE_CALL_ACCEPTED: - case ROSE_CLEAR_REQUEST: - case ROSE_CLEAR_CONFIRMATION: - case ROSE_RESET_REQUEST: - case ROSE_RESET_CONFIRMATION: - return frame[2]; - default: - break; + case ROSE_CALL_REQUEST: + case ROSE_CALL_ACCEPTED: + case ROSE_CLEAR_REQUEST: + case ROSE_CLEAR_CONFIRMATION: + case ROSE_RESET_REQUEST: + case ROSE_RESET_CONFIRMATION: + return frame[2]; + default: + break; } if ((frame[2] & 0x1F) == ROSE_RR || @@ -253,61 +243,61 @@ do { switch (*p & 0xC0) { - case 0x00: - p += 2; - n += 2; - len -= 2; - break; + case 0x00: + p += 2; + n += 2; + len -= 2; + break; - case 0x40: - if (*p == FAC_NATIONAL_RAND) - facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); - p += 3; - n += 3; - len -= 3; - break; + case 0x40: + if (*p == FAC_NATIONAL_RAND) + facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); + p += 3; + n += 3; + len -= 3; + break; - case 0x80: - p += 4; - n += 4; - len -= 4; - break; + case 0x80: + p += 4; + n += 4; + len -= 4; + break; - case 0xC0: - l = p[1]; - if (*p == FAC_NATIONAL_DEST_DIGI) { - if (!fac_national_digis_received) { - memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN); - facilities->source_ndigis = 1; - } - } - else if (*p == FAC_NATIONAL_SRC_DIGI) { - if (!fac_national_digis_received) { - memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN); - facilities->dest_ndigis = 1; - } + case 0xC0: + l = p[1]; + if (*p == FAC_NATIONAL_DEST_DIGI) { + if (!fac_national_digis_received) { + memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN); + facilities->source_ndigis = 1; } - else if (*p == FAC_NATIONAL_FAIL_CALL) { - memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN); - } - else if (*p == FAC_NATIONAL_FAIL_ADD) { - memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN); + } + else if (*p == FAC_NATIONAL_SRC_DIGI) { + if (!fac_national_digis_received) { + memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN); + facilities->dest_ndigis = 1; } - else if (*p == FAC_NATIONAL_DIGIS) { - fac_national_digis_received = 1; - facilities->source_ndigis = 0; - facilities->dest_ndigis = 0; - for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { - if (pt[6] & AX25_HBIT) - memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); - else - memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); - } + } + else if (*p == FAC_NATIONAL_FAIL_CALL) { + memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN); + } + else if (*p == FAC_NATIONAL_FAIL_ADD) { + memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN); + } + else if (*p == FAC_NATIONAL_DIGIS) { + fac_national_digis_received = 1; + facilities->source_ndigis = 0; + facilities->dest_ndigis = 0; + for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { + if (pt[6] & AX25_HBIT) + memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); + else + memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); } - p += l + 2; - n += l + 2; - len -= l + 2; - break; + } + p += l + 2; + n += l + 2; + len -= l + 2; + break; } } while (*p != 0x00 && len > 0); @@ -321,49 +311,50 @@ do { switch (*p & 0xC0) { - case 0x00: - p += 2; - n += 2; - len -= 2; - break; + case 0x00: + p += 2; + n += 2; + len -= 2; + break; - case 0x40: - p += 3; - n += 3; - len -= 3; - break; + case 0x40: + p += 3; + n += 3; + len -= 3; + break; - case 0x80: - p += 4; - n += 4; - len -= 4; - break; + case 0x80: + p += 4; + n += 4; + len -= 4; + break; - case 0xC0: - l = p[1]; - if (*p == FAC_CCITT_DEST_NSAP) { - memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); - memcpy(callsign, p + 12, l - 10); - callsign[l - 10] = '\0'; - facilities->source_call = *asc2ax(callsign); - } - if (*p == FAC_CCITT_SRC_NSAP) { - memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN); - memcpy(callsign, p + 12, l - 10); - callsign[l - 10] = '\0'; - facilities->dest_call = *asc2ax(callsign); - } - p += l + 2; - n += l + 2; - len -= l + 2; - break; + case 0xC0: + l = p[1]; + if (*p == FAC_CCITT_DEST_NSAP) { + memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); + memcpy(callsign, p + 12, l - 10); + callsign[l - 10] = '\0'; + facilities->source_call = *asc2ax(callsign); + } + if (*p == FAC_CCITT_SRC_NSAP) { + memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN); + memcpy(callsign, p + 12, l - 10); + callsign[l - 10] = '\0'; + facilities->dest_call = *asc2ax(callsign); + } + p += l + 2; + n += l + 2; + len -= l + 2; + break; } } while (*p != 0x00 && len > 0); return n; } -int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facilities) +int rose_parse_facilities(unsigned char *p, + struct rose_facilities_struct *facilities) { int facilities_len, len; @@ -378,26 +369,26 @@ p++; switch (*p) { - case FAC_NATIONAL: /* National */ - len = rose_parse_national(p + 1, facilities, facilities_len - 1); - facilities_len -= len + 1; - p += len + 1; - break; - - case FAC_CCITT: /* CCITT */ - len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); - facilities_len -= len + 1; - p += len + 1; - break; - - default: - printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); - facilities_len--; - p++; - break; + case FAC_NATIONAL: /* National */ + len = rose_parse_national(p + 1, facilities, facilities_len - 1); + facilities_len -= len + 1; + p += len + 1; + break; + + case FAC_CCITT: /* CCITT */ + len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); + facilities_len -= len + 1; + p += len + 1; + break; + + default: + printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); + facilities_len--; + p++; + break; } - } - else break; /* Error in facilities format */ + } else + break; /* Error in facilities format */ } return 1; diff -Nru a/net/rose/rose_timer.c b/net/rose/rose_timer.c --- a/net/rose/rose_timer.c Fri Sep 20 08:20:47 2002 +++ b/net/rose/rose_timer.c Fri Sep 20 08:20:47 2002 @@ -1,20 +1,12 @@ /* - * ROSE release 003 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This code REQUIRES 2.1.15 or higher/ NET3.038 - * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * History - * ROSE 001 Jonathan(G4KLX) Cloned from nr_timer.c - * ROSE 003 Jonathan(G4KLX) New timer architecture. - * Implemented idle timer. + * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) + * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org) */ - #include #include #include @@ -139,34 +131,35 @@ struct sock *sk = (struct sock *)param; rose_cb *rose = rose_sk(sk); + bh_lock_sock(sk); switch (rose->state) { - - case ROSE_STATE_0: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) { - rose_destroy_socket(sk); - return; - } - break; - - case ROSE_STATE_3: - /* - * Check for the state of the receive buffer. - */ - if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && - (rose->condition & ROSE_COND_OWN_RX_BUSY)) { - rose->condition &= ~ROSE_COND_OWN_RX_BUSY; - rose->condition &= ~ROSE_COND_ACK_PENDING; - rose->vl = rose->vr; - rose_write_internal(sk, ROSE_RR); - rose_stop_timer(sk); /* HB */ - break; - } + case ROSE_STATE_0: + /* Magic here: If we listen() and a new link dies before it + is accepted() it isn't 'dead' so doesn't get removed. */ + if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) { + rose_destroy_socket(sk); + return; + } + break; + + case ROSE_STATE_3: + /* + * Check for the state of the receive buffer. + */ + if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && + (rose->condition & ROSE_COND_OWN_RX_BUSY)) { + rose->condition &= ~ROSE_COND_OWN_RX_BUSY; + rose->condition &= ~ROSE_COND_ACK_PENDING; + rose->vl = rose->vr; + rose_write_internal(sk, ROSE_RR); + rose_stop_timer(sk); /* HB */ break; + } + break; } rose_start_heartbeat(sk); + bh_unlock_sock(sk); } static void rose_timer_expiry(unsigned long param) @@ -174,33 +167,35 @@ struct sock *sk = (struct sock *)param; rose_cb *rose = rose_sk(sk); + bh_lock_sock(sk); switch (rose->state) { - - case ROSE_STATE_1: /* T1 */ - case ROSE_STATE_4: /* T2 */ - rose_write_internal(sk, ROSE_CLEAR_REQUEST); - rose->state = ROSE_STATE_2; - rose_start_t3timer(sk); - break; - - case ROSE_STATE_2: /* T3 */ - rose->neighbour->use--; - rose_disconnect(sk, ETIMEDOUT, -1, -1); - break; - - case ROSE_STATE_3: /* HB */ - if (rose->condition & ROSE_COND_ACK_PENDING) { - rose->condition &= ~ROSE_COND_ACK_PENDING; - rose_enquiry_response(sk); - } - break; + case ROSE_STATE_1: /* T1 */ + case ROSE_STATE_4: /* T2 */ + rose_write_internal(sk, ROSE_CLEAR_REQUEST); + rose->state = ROSE_STATE_2; + rose_start_t3timer(sk); + break; + + case ROSE_STATE_2: /* T3 */ + rose->neighbour->use--; + rose_disconnect(sk, ETIMEDOUT, -1, -1); + break; + + case ROSE_STATE_3: /* HB */ + if (rose->condition & ROSE_COND_ACK_PENDING) { + rose->condition &= ~ROSE_COND_ACK_PENDING; + rose_enquiry_response(sk); + } + break; } + bh_unlock_sock(sk); } static void rose_idletimer_expiry(unsigned long param) { struct sock *sk = (struct sock *)param; + bh_lock_sock(sk); rose_clear_queues(sk); rose_write_internal(sk, ROSE_CLEAR_REQUEST); @@ -210,10 +205,11 @@ sk->state = TCP_CLOSE; sk->err = 0; - sk->shutdown |= SEND_SHUTDOWN; + sk->shutdown |= SEND_SHUTDOWN; if (!sk->dead) sk->state_change(sk); sk->dead = 1; + bh_unlock_sock(sk); } diff -Nru a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c --- a/net/rose/sysctl_net_rose.c Fri Sep 20 08:20:41 2002 +++ b/net/rose/sysctl_net_rose.c Fri Sep 20 08:20:41 2002 @@ -1,10 +1,11 @@ -/* -*- linux-c -*- - * sysctl_net_rose.c: sysctl interface to net ROSE subsystem. +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * Begun April 1, 1996, Mike Shaver. - * Added /proc/sys/net/rose directory entry (empty =) ). [MS] + * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com) */ - #include #include #include diff -Nru a/net/sunrpc/auth.c b/net/sunrpc/auth.c --- a/net/sunrpc/auth.c Fri Sep 20 08:20:41 2002 +++ b/net/sunrpc/auth.c Fri Sep 20 08:20:41 2002 @@ -1,7 +1,7 @@ /* - * linux/fs/nfs/rpcauth.c + * linux/net/sunrpc/auth.c * - * Generic RPC authentication API. + * Generic RPC client authentication API. * * Copyright (C) 1996, Olaf Kirch */ @@ -18,9 +18,7 @@ # define RPCDBG_FACILITY RPCDBG_AUTH #endif -#define RPC_MAXFLAVOR 8 - -static struct rpc_authops * auth_flavors[RPC_MAXFLAVOR] = { +static struct rpc_authops * auth_flavors[RPC_AUTH_MAXFLAVOR] = { &authnull_ops, /* AUTH_NULL */ &authunix_ops, /* AUTH_UNIX */ NULL, /* others can be loadable modules */ @@ -29,9 +27,9 @@ int rpcauth_register(struct rpc_authops *ops) { - unsigned int flavor; + rpc_authflavor_t flavor; - if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR) + if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) return -EINVAL; if (auth_flavors[flavor] != NULL) return -EPERM; /* what else? */ @@ -42,9 +40,9 @@ int rpcauth_unregister(struct rpc_authops *ops) { - unsigned int flavor; + rpc_authflavor_t flavor; - if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR) + if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) return -EINVAL; if (auth_flavors[flavor] != ops) return -EPERM; /* what else? */ @@ -53,11 +51,11 @@ } struct rpc_auth * -rpcauth_create(unsigned int flavor, struct rpc_clnt *clnt) +rpcauth_create(rpc_authflavor_t flavor, struct rpc_clnt *clnt) { struct rpc_authops *ops; - if (flavor >= RPC_MAXFLAVOR || !(ops = auth_flavors[flavor])) + if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor])) return NULL; clnt->cl_auth = ops->create(clnt); return clnt->cl_auth; diff -Nru a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c --- a/net/sunrpc/auth_null.c Fri Sep 20 08:20:49 2002 +++ b/net/sunrpc/auth_null.c Fri Sep 20 08:20:49 2002 @@ -1,5 +1,5 @@ /* - * linux/net/sunrpc/rpcauth_null.c + * linux/net/sunrpc/auth_null.c * * AUTH_NULL authentication. Really :-) * @@ -106,14 +106,18 @@ static u32 * nul_validate(struct rpc_task *task, u32 *p) { - u32 n = ntohl(*p++); + rpc_authflavor_t flavor; + u32 size; - if (n != RPC_AUTH_NULL) { - printk("RPC: bad verf flavor: %ld\n", (unsigned long) n); + flavor = ntohl(*p++); + if (flavor != RPC_AUTH_NULL) { + printk("RPC: bad verf flavor: %u\n", flavor); return NULL; } - if ((n = ntohl(*p++)) != 0) { - printk("RPC: bad verf size: %ld\n", (unsigned long) n); + + size = ntohl(*p++); + if (size != 0) { + printk("RPC: bad verf size: %u\n", size); return NULL; } diff -Nru a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c --- a/net/sunrpc/auth_unix.c Fri Sep 20 08:20:41 2002 +++ b/net/sunrpc/auth_unix.c Fri Sep 20 08:20:41 2002 @@ -1,5 +1,5 @@ /* - * linux/net/sunrpc/rpcauth_unix.c + * linux/net/sunrpc/auth_unix.c * * UNIX-style authentication; no AUTH_SHORT support * @@ -216,18 +216,24 @@ static u32 * unx_validate(struct rpc_task *task, u32 *p) { - u32 n = ntohl(*p++); + rpc_authflavor_t flavor; + u32 size; - if (n != RPC_AUTH_NULL && n != RPC_AUTH_UNIX && n != RPC_AUTH_SHORT) { - printk("RPC: bad verf flavor: %ld\n", (unsigned long) n); + flavor = ntohl(*p++); + if (flavor != RPC_AUTH_NULL && + flavor != RPC_AUTH_UNIX && + flavor != RPC_AUTH_SHORT) { + printk("RPC: bad verf flavor: %u\n", flavor); return NULL; } - if ((n = ntohl(*p++)) > 400) { - printk("RPC: giant verf size: %ld\n", (unsigned long) n); + + size = ntohl(*p++); + if (size > 400) { + printk("RPC: giant verf size: %u\n", size); return NULL; } - task->tk_auth->au_rslack = (n >> 2) + 2; - p += (n >> 2); + task->tk_auth->au_rslack = (size >> 2) + 2; + p += (size >> 2); return p; } diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c --- a/net/sunrpc/clnt.c Fri Sep 20 08:20:44 2002 +++ b/net/sunrpc/clnt.c Fri Sep 20 08:20:44 2002 @@ -7,7 +7,7 @@ * * - RPC header generation and argument serialization. * - Credential refresh. - * - TCP reconnect handling (when finished). + * - TCP connect handling. * - Retry of operation when it is suspected the operation failed because * of uid squashing on the server, or when the credentials were stale * and need to be refreshed, or when a packet was damaged in transit. @@ -55,9 +55,9 @@ static void call_refresh(struct rpc_task *task); static void call_refreshresult(struct rpc_task *task); static void call_timeout(struct rpc_task *task); -static void call_reconnect(struct rpc_task *task); -static void child_reconnect(struct rpc_task *); -static void child_reconnect_status(struct rpc_task *); +static void call_connect(struct rpc_task *task); +static void child_connect(struct rpc_task *task); +static void child_connect_status(struct rpc_task *task); static u32 * call_header(struct rpc_task *task); static u32 * call_verify(struct rpc_task *task); @@ -71,7 +71,8 @@ */ struct rpc_clnt * rpc_create_client(struct rpc_xprt *xprt, char *servname, - struct rpc_program *program, u32 vers, int flavor) + struct rpc_program *program, u32 vers, + rpc_authflavor_t flavor) { struct rpc_version *version; struct rpc_clnt *clnt = NULL; @@ -122,7 +123,7 @@ printk(KERN_INFO "RPC: out of memory in rpc_create_client\n"); goto out; out_no_auth: - printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %d)\n", + printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n", flavor); rpc_free(clnt); clnt = NULL; @@ -561,51 +562,54 @@ dprintk("RPC: %4d call_bind xprt %p %s connected\n", task->tk_pid, xprt, (xprt_connected(xprt) ? "is" : "is not")); - task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_reconnect; + task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_connect; if (!clnt->cl_port) { - task->tk_action = call_reconnect; - task->tk_timeout = clnt->cl_timeout.to_maxval; + task->tk_action = call_connect; + task->tk_timeout = RPC_CONNECT_TIMEOUT; rpc_getport(task, clnt); } } /* - * 4a. Reconnect to the RPC server (TCP case) + * 4a. Connect to the RPC server (TCP case) */ static void -call_reconnect(struct rpc_task *task) +call_connect(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; struct rpc_task *child; - dprintk("RPC: %4d call_reconnect status %d\n", + dprintk("RPC: %4d call_connect status %d\n", task->tk_pid, task->tk_status); task->tk_action = call_transmit; if (task->tk_status < 0 || !clnt->cl_xprt->stream) return; - /* Run as a child to ensure it runs as an rpciod task */ + /* Run as a child to ensure it runs as an rpciod task. Rpciod + * guarantees we have the correct capabilities for socket bind + * to succeed. */ child = rpc_new_child(clnt, task); if (child) { - child->tk_action = child_reconnect; + child->tk_action = child_connect; rpc_run_child(task, child, NULL); } } -static void child_reconnect(struct rpc_task *task) +static void +child_connect(struct rpc_task *task) { - task->tk_client->cl_stats->netreconn++; task->tk_status = 0; - task->tk_action = child_reconnect_status; - xprt_reconnect(task); + task->tk_action = child_connect_status; + xprt_connect(task); } -static void child_reconnect_status(struct rpc_task *task) +static void +child_connect_status(struct rpc_task *task) { if (task->tk_status == -EAGAIN) - task->tk_action = child_reconnect; + task->tk_action = child_connect; else task->tk_action = NULL; } @@ -638,7 +642,6 @@ call_status(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - struct rpc_xprt *xprt = clnt->cl_xprt; struct rpc_rqst *req = task->tk_rqstp; int status; @@ -661,30 +664,23 @@ break; case -ECONNREFUSED: case -ENOTCONN: - req->rq_bytes_sent = 0; - if (clnt->cl_autobind || !clnt->cl_port) { + if (clnt->cl_autobind) clnt->cl_port = 0; - task->tk_action = call_bind; - break; - } - if (xprt->stream) { - task->tk_action = call_reconnect; - break; - } - /* - * Sleep and dream of an open connection - */ - task->tk_timeout = 5 * HZ; - rpc_sleep_on(&xprt->sending, task, NULL, NULL); - case -ENOMEM: + task->tk_action = call_bind; + break; case -EAGAIN: task->tk_action = call_transmit; break; + case -EIO: + /* shutdown or soft timeout */ + rpc_exit(task, status); + break; default: if (clnt->cl_chatty) printk("%s: RPC call returned error %d\n", clnt->cl_protname, -status); rpc_exit(task, status); + break; } } diff -Nru a/net/sunrpc/svc.c b/net/sunrpc/svc.c --- a/net/sunrpc/svc.c Fri Sep 20 08:20:47 2002 +++ b/net/sunrpc/svc.c Fri Sep 20 08:20:47 2002 @@ -247,8 +247,8 @@ vers = ntohl(*bufp++); /* First words of reply: */ - svc_putlong(resp, xdr_one); /* REPLY */ - svc_putlong(resp, xdr_zero); /* ACCEPT */ + svc_putu32(resp, xdr_one); /* REPLY */ + svc_putu32(resp, xdr_zero); /* ACCEPT */ if (dir != 0) /* direction != CALL */ goto err_bad_dir; @@ -300,7 +300,7 @@ /* Build the reply header. */ statp = resp->buf; - svc_putlong(resp, rpc_success); /* RPC_SUCCESS */ + svc_putu32(resp, rpc_success); /* RPC_SUCCESS */ /* Bump per-procedure stats counter */ procp->pc_count++; @@ -371,17 +371,17 @@ err_bad_rpc: serv->sv_stats->rpcbadfmt++; resp->buf[-1] = xdr_one; /* REJECT */ - svc_putlong(resp, xdr_zero); /* RPC_MISMATCH */ - svc_putlong(resp, xdr_two); /* Only RPCv2 supported */ - svc_putlong(resp, xdr_two); + svc_putu32(resp, xdr_zero); /* RPC_MISMATCH */ + svc_putu32(resp, xdr_two); /* Only RPCv2 supported */ + svc_putu32(resp, xdr_two); goto sendit; err_bad_auth: dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); serv->sv_stats->rpcbadauth++; resp->buf[-1] = xdr_one; /* REJECT */ - svc_putlong(resp, xdr_one); /* AUTH_ERROR */ - svc_putlong(resp, auth_stat); /* status */ + svc_putu32(resp, xdr_one); /* AUTH_ERROR */ + svc_putu32(resp, auth_stat); /* status */ goto sendit; err_bad_prog: @@ -391,7 +391,7 @@ /* else it is just a Solaris client seeing if ACLs are supported */ #endif serv->sv_stats->rpcbadfmt++; - svc_putlong(resp, rpc_prog_unavail); + svc_putu32(resp, rpc_prog_unavail); goto sendit; err_bad_vers: @@ -399,9 +399,9 @@ printk("svc: unknown version (%d)\n", vers); #endif serv->sv_stats->rpcbadfmt++; - svc_putlong(resp, rpc_prog_mismatch); - svc_putlong(resp, htonl(progp->pg_lovers)); - svc_putlong(resp, htonl(progp->pg_hivers)); + svc_putu32(resp, rpc_prog_mismatch); + svc_putu32(resp, htonl(progp->pg_lovers)); + svc_putu32(resp, htonl(progp->pg_hivers)); goto sendit; err_bad_proc: @@ -409,7 +409,7 @@ printk("svc: unknown procedure (%d)\n", proc); #endif serv->sv_stats->rpcbadfmt++; - svc_putlong(resp, rpc_proc_unavail); + svc_putu32(resp, rpc_proc_unavail); goto sendit; err_garbage: @@ -417,6 +417,6 @@ printk("svc: failed to decode args\n"); #endif serv->sv_stats->rpcbadfmt++; - svc_putlong(resp, rpc_garbage_args); + svc_putu32(resp, rpc_garbage_args); goto sendit; } diff -Nru a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c --- a/net/sunrpc/svcauth.c Fri Sep 20 08:20:43 2002 +++ b/net/sunrpc/svcauth.c Fri Sep 20 08:20:43 2002 @@ -31,14 +31,9 @@ static void svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp); /* - * Max number of authentication flavors we support - */ -#define RPC_SVCAUTH_MAX 8 - -/* * Table of authenticators */ -static auth_fn_t authtab[RPC_SVCAUTH_MAX] = { +static auth_fn_t authtab[RPC_AUTH_MAXFLAVOR] = { svcauth_null, svcauth_unix, NULL, @@ -47,17 +42,17 @@ void svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp) { - u32 flavor; - auth_fn_t func; + rpc_authflavor_t flavor; + auth_fn_t func; *statp = rpc_success; *authp = rpc_auth_ok; - svc_getlong(&rqstp->rq_argbuf, flavor); + svc_getu32(&rqstp->rq_argbuf, flavor); flavor = ntohl(flavor); dprintk("svc: svc_authenticate (%d)\n", flavor); - if (flavor >= RPC_SVCAUTH_MAX || !(func = authtab[flavor])) { + if (flavor >= RPC_AUTH_MAXFLAVOR || !(func = authtab[flavor])) { *authp = rpc_autherr_badcred; return; } @@ -67,18 +62,18 @@ } int -svc_auth_register(u32 flavor, auth_fn_t func) +svc_auth_register(rpc_authflavor_t flavor, auth_fn_t func) { - if (flavor >= RPC_SVCAUTH_MAX || authtab[flavor]) + if (flavor >= RPC_AUTH_MAXFLAVOR || authtab[flavor]) return -EINVAL; authtab[flavor] = func; return 0; } void -svc_auth_unregister(u32 flavor) +svc_auth_unregister(rpc_authflavor_t flavor) { - if (flavor < RPC_SVCAUTH_MAX) + if (flavor < RPC_AUTH_MAXFLAVOR) authtab[flavor] = NULL; } @@ -110,8 +105,8 @@ /* Put NULL verifier */ rqstp->rq_verfed = 1; - svc_putlong(resp, RPC_AUTH_NULL); - svc_putlong(resp, 0); + svc_putu32(resp, RPC_AUTH_NULL); + svc_putu32(resp, 0); } static void @@ -157,8 +152,8 @@ /* Put NULL verifier */ rqstp->rq_verfed = 1; - svc_putlong(resp, RPC_AUTH_NULL); - svc_putlong(resp, 0); + svc_putu32(resp, RPC_AUTH_NULL); + svc_putu32(resp, 0); return; diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c --- a/net/sunrpc/svcsock.c Fri Sep 20 08:20:41 2002 +++ b/net/sunrpc/svcsock.c Fri Sep 20 08:20:41 2002 @@ -1091,8 +1091,8 @@ rqstp->rq_userset = 0; rqstp->rq_verfed = 0; - svc_getlong(&rqstp->rq_argbuf, rqstp->rq_xid); - svc_putlong(&rqstp->rq_resbuf, rqstp->rq_xid); + svc_getu32(&rqstp->rq_argbuf, rqstp->rq_xid); + svc_putu32(&rqstp->rq_resbuf, rqstp->rq_xid); /* Assume that the reply consists of a single buffer. */ rqstp->rq_resbuf.nriov = 1; diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c --- a/net/sunrpc/xprt.c Fri Sep 20 08:20:47 2002 +++ b/net/sunrpc/xprt.c Fri Sep 20 08:20:47 2002 @@ -86,9 +86,11 @@ static void do_xprt_transmit(struct rpc_task *); static inline void do_xprt_reserve(struct rpc_task *); static void xprt_disconnect(struct rpc_xprt *); -static void xprt_reconn_status(struct rpc_task *task); +static void xprt_conn_status(struct rpc_task *task); +static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap, + struct rpc_timeout *to); static struct socket *xprt_create_socket(int, struct rpc_timeout *); -static int xprt_bind_socket(struct rpc_xprt *, struct socket *); +static void xprt_bind_socket(struct rpc_xprt *, struct socket *); static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); #ifdef RPC_DEBUG_DATA @@ -134,7 +136,7 @@ /* * Serialize write access to sockets, in order to prevent different * requests from interfering with each other. - * Also prevents TCP socket reconnections from colliding with writes. + * Also prevents TCP socket connects from colliding with writes. */ static int __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) @@ -407,106 +409,150 @@ } /* - * Reconnect a broken TCP connection. + * Attempt to connect a TCP socket. * - * Note: This cannot collide with the TCP reads, as both run from rpciod + * NB: This never collides with TCP reads, as both run from rpciod */ void -xprt_reconnect(struct rpc_task *task) +xprt_connect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; struct socket *sock = xprt->sock; struct sock *inet; int status; - dprintk("RPC: %4d xprt_reconnect %p connected %d\n", - task->tk_pid, xprt, xprt_connected(xprt)); - if (xprt->shutdown) - return; + dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid, + xprt, (xprt_connected(xprt) ? "is" : "is not")); - if (!xprt->stream) + if (xprt->shutdown) { + task->tk_status = -EIO; return; - + } if (!xprt->addr.sin_port) { task->tk_status = -EIO; return; } - if (!xprt_lock_write(xprt, task)) return; if (xprt_connected(xprt)) goto out_write; - if (sock && sock->state != SS_UNCONNECTED) - xprt_close(xprt); - status = -ENOTCONN; - if (!(inet = xprt->inet)) { - /* Create an unconnected socket */ - if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout))) - goto defer; - xprt_bind_socket(xprt, sock); - inet = sock->sk; + /* + * We're here because the xprt was marked disconnected. + * Start by resetting any existing state. + */ + xprt_close(xprt); + if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout))) { + /* couldn't create socket or bind to reserved port; + * this is likely a permanent error, so cause an abort */ + task->tk_status = -EIO; + goto out_write; } + xprt_bind_socket(xprt, sock); + inet = sock->sk; - /* Now connect it asynchronously. */ - dprintk("RPC: %4d connecting new socket\n", task->tk_pid); + /* + * Tell the socket layer to start connecting... + */ status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, sizeof(xprt->addr), O_NONBLOCK); + dprintk("RPC: %4d connect status %d connected %d sock state %d\n", + task->tk_pid, -status, xprt_connected(xprt), inet->state); - if (status < 0) { - switch (status) { - case -EALREADY: - case -EINPROGRESS: - status = 0; - break; - case -EISCONN: - case -EPIPE: - status = 0; - xprt_close(xprt); - goto defer; - default: - printk("RPC: TCP connect error %d!\n", -status); - xprt_close(xprt); - goto defer; - } - + switch (status) { + case -EINPROGRESS: + case -EALREADY: /* Protect against TCP socket state changes */ lock_sock(inet); - dprintk("RPC: %4d connect status %d connected %d\n", - task->tk_pid, status, xprt_connected(xprt)); - if (inet->state != TCP_ESTABLISHED) { - task->tk_timeout = xprt->timeout.to_maxval; - /* if the socket is already closing, delay 5 secs */ - if ((1<state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV)) - task->tk_timeout = 5*HZ; - rpc_sleep_on(&xprt->pending, task, xprt_reconn_status, NULL); + dprintk("RPC: %4d waiting for connection\n", + task->tk_pid); + task->tk_timeout = RPC_CONNECT_TIMEOUT; + /* if the socket is already closing, delay briefly */ + if ((1 << inet->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV)) + task->tk_timeout = RPC_REESTABLISH_TIMEOUT; + rpc_sleep_on(&xprt->pending, task, xprt_conn_status, + NULL); release_sock(inet); + /* task status set when task wakes up again */ return; } release_sock(inet); - } -defer: - if (status < 0) { - rpc_delay(task, 5*HZ); + task->tk_status = 0; + break; + + case 0: + case -EISCONN: /* not likely, but just in case */ + /* Half closed state. No race -- this socket is dead. */ + if (inet->state != TCP_ESTABLISHED) { + xprt_close(xprt); + task->tk_status = -EAGAIN; + goto out_write; + } + + /* Otherwise, the connection is already established. */ + task->tk_status = 0; + break; + + case -EPIPE: + xprt_close(xprt); task->tk_status = -ENOTCONN; + goto out_write; + + default: + /* Report myriad other possible returns. If this file + * system is soft mounted, just error out, like Solaris. */ + xprt_close(xprt); + if (task->tk_client->cl_softrtry) { + printk(KERN_WARNING + "RPC: error %d connecting to server %s, exiting\n", + -status, task->tk_client->cl_server); + task->tk_status = -EIO; + } else { + printk(KERN_WARNING + "RPC: error %d connecting to server %s\n", + -status, task->tk_client->cl_server); + rpc_delay(task, RPC_REESTABLISH_TIMEOUT); + task->tk_status = status; + } + break; } + out_write: xprt_release_write(xprt, task); } /* - * Reconnect timeout. We just mark the transport as not being in the - * process of reconnecting, and leave the rest to the upper layers. + * We arrive here when awoken from waiting on connection establishment. */ static void -xprt_reconn_status(struct rpc_task *task) +xprt_conn_status(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - dprintk("RPC: %4d xprt_reconn_timeout %d\n", - task->tk_pid, task->tk_status); + switch (task->tk_status) { + case 0: + dprintk("RPC: %4d xprt_conn_status: connection established\n", + task->tk_pid); + goto out; + case -ETIMEDOUT: + dprintk("RPC: %4d xprt_conn_status: timed out\n", + task->tk_pid); + /* prevent TCP from continuing to retry SYNs */ + xprt_close(xprt); + break; + default: + printk(KERN_ERR "RPC: error %d connecting to server %s\n", + -task->tk_status, task->tk_client->cl_server); + xprt_close(xprt); + rpc_delay(task, RPC_REESTABLISH_TIMEOUT); + break; + } + /* if soft mounted, cause this RPC to fail */ + if (task->tk_client->cl_softrtry) + task->tk_status = -EIO; + out: xprt_release_write(xprt, task); } @@ -1154,8 +1200,12 @@ return; case -ECONNREFUSED: case -ENOTCONN: - if (!xprt->stream) + if (!xprt->stream) { + task->tk_timeout = RPC_REESTABLISH_TIMEOUT; + rpc_sleep_on(&xprt->sending, task, NULL, NULL); return; + } + /* fall through */ default: if (xprt->stream) xprt_disconnect(xprt); @@ -1305,8 +1355,7 @@ * Initialize an RPC client */ static struct rpc_xprt * -xprt_setup(struct socket *sock, int proto, - struct sockaddr_in *ap, struct rpc_timeout *to) +xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) { struct rpc_xprt *xprt; struct rpc_rqst *req; @@ -1353,7 +1402,6 @@ dprintk("RPC: created transport %p\n", xprt); - xprt_bind_socket(xprt, sock); return xprt; } @@ -1381,13 +1429,13 @@ return err; } -static int +static void xprt_bind_socket(struct rpc_xprt *xprt, struct socket *sock) { struct sock *sk = sock->sk; if (xprt->inet) - return -EBUSY; + return; sk->user_data = xprt; xprt->old_data_ready = sk->data_ready; @@ -1413,7 +1461,7 @@ if(xprt->stream) rpciod_up(); - return 0; + return; } /* @@ -1438,7 +1486,8 @@ } /* - * Create a client socket given the protocol and peer address. + * Datastream sockets are created here, but xprt_connect will create + * and connect stream sockets. */ static struct socket * xprt_create_socket(int proto, struct rpc_timeout *to) @@ -1457,8 +1506,10 @@ } /* If the caller has the capability, bind to a reserved port */ - if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0) + if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0) { + printk("RPC: can't bind to reserved port.\n"); goto failed; + } return sock; @@ -1473,17 +1524,32 @@ struct rpc_xprt * xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) { - struct socket *sock; struct rpc_xprt *xprt; - dprintk("RPC: xprt_create_proto called\n"); - - if (!(sock = xprt_create_socket(proto, to))) - return NULL; + xprt = xprt_setup(proto, sap, to); + if (!xprt) + goto out; - if (!(xprt = xprt_setup(sock, proto, sap, to))) - sock_release(sock); + if (!xprt->stream) { + struct socket *sock = xprt_create_socket(proto, to); + if (sock) + xprt_bind_socket(xprt, sock); + else { + rpc_free(xprt); + xprt = NULL; + } + } else + /* + * Don't allow a TCP service user unless they have + * enough capability to bind a reserved port. + */ + if (!capable(CAP_NET_BIND_SERVICE)) { + rpc_free(xprt); + xprt = NULL; + } + out: + dprintk("RPC: xprt_create_proto created xprt %p\n", xprt); return xprt; } @@ -1522,7 +1588,7 @@ dprintk("RPC: destroying transport %p\n", xprt); xprt_shutdown(xprt); xprt_close(xprt); - kfree(xprt); + rpc_free(xprt); return 0; } diff -Nru a/scripts/mkcompile_h b/scripts/mkcompile_h --- a/scripts/mkcompile_h Fri Sep 20 08:20:48 2002 +++ b/scripts/mkcompile_h Fri Sep 20 08:20:49 2002 @@ -67,8 +67,8 @@ # first line. if [ -r $TARGET ] && \ - grep -v 'auto generated\|UTS_VERSION\|LINUX_COMPILE_TIME' $TARGET > .tmpver.1 && \ - grep -v 'auto generated\|UTS_VERSION\|LINUX_COMPILE_TIME' .tmpcompile > .tmpver.2 && \ + grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' $TARGET > .tmpver.1 && \ + grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' .tmpcompile > .tmpver.2 && \ cmp -s .tmpver.1 .tmpver.2; then echo ' (unchanged)' rm -f .tmpcompile diff -Nru a/sound/Makefile b/sound/Makefile --- a/sound/Makefile Fri Sep 20 08:20:44 2002 +++ b/sound/Makefile Fri Sep 20 08:20:44 2002 @@ -1,8 +1,6 @@ # Makefile for the Linux sound card driver # -O_TARGET := sound.o - export-objs := sound_core.o obj-$(CONFIG_SOUND) += soundcore.o diff -Nru a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c --- a/sound/oss/cs4281/cs4281m.c Fri Sep 20 08:20:48 2002 +++ b/sound/oss/cs4281/cs4281m.c Fri Sep 20 08:20:48 2002 @@ -3205,7 +3205,7 @@ "cs4281: cs4281_ioctl(): DSP_RESET\n")); if (file->f_mode & FMODE_WRITE) { stop_dac(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = s->dma_dac.blocks = s->dma_dac.wakeup = 0; @@ -3213,7 +3213,7 @@ } if (file->f_mode & FMODE_READ) { stop_adc(s); - synchronize_irq(); + synchronize_irq(s->irq); s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = s->dma_adc.blocks = s->dma_dac.wakeup = 0; @@ -4452,7 +4452,7 @@ { struct cs4281_state *s = pci_get_drvdata(pci_dev); // stop DMA controller - synchronize_irq(); + synchronize_irq(s->irq); free_irq(s->irq, s); unregister_sound_dsp(s->dev_audio); unregister_sound_mixer(s->dev_mixer);