--- /dev/null
+What: /sys/bus/rbd/
+Date: November 2010
+Contact: Yehuda Sadeh <yehuda@hq.newdream.net>,
+ Sage Weil <sage@newdream.net>
+Description:
+
+Being used for adding and removing rbd block devices.
+
+Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name]
+
+ $ echo "192.168.0.1 name=admin rbd foo" > /sys/bus/rbd/add
+
+The snapshot name can be "-" or omitted to map the image read/write. A <dev-id>
+will be assigned for any registered block device. If snapshot is used, it will
+be mapped read-only.
+
+Removal of a device:
+
+ $ echo <dev-id> > /sys/bus/rbd/remove
+
+Entries under /sys/bus/rbd/devices/<dev-id>/
+--------------------------------------------
+
+client_id
+
+ The ceph unique client id that was assigned for this specific session.
+
+major
+
+ The block device major number.
+
+name
+
+ The name of the rbd image.
+
+pool
+
+ The pool where this rbd image resides. The pool-name pair is unique
+ per rados system.
+
+size
+
+ The size (in bytes) of the mapped block device.
+
+refresh
+
+ Writing to this file will reread the image header data and set
+ all relevant datastructures accordingly.
+
+current_snap
+
+ The current snapshot for which the device is mapped.
+
+create_snap
+
+ Create a snapshot:
+
+ $ echo <snap-name> > /sys/bus/rbd/devices/<dev-id>/snap_create
+
+rollback_snap
+
+ Rolls back data to the specified snapshot. This goes over the entire
+ list of rados blocks and sends a rollback command to each.
+
+ $ echo <snap-name> > /sys/bus/rbd/devices/<dev-id>/snap_rollback
+
+snap_*
+
+ A directory per each snapshot
+
+
+Entries under /sys/bus/rbd/devices/<dev-id>/snap_<snap-name>
+-------------------------------------------------------------
+
+id
+
+ The rados internal snapshot id assigned for this snapshot
+
+size
+
+ The size of the image when this snapshot was taken.
+
+
KernelVersion: 2.6.20
Contact: "Corentin Chary" <corentincj@iksaif.net>
Description:
- Control the bluetooth device. 1 means on, 0 means off.
+ Control the wlan device. 1 means on, 0 means off.
This may control the led, the device or both.
Users: Lapsus
+
+What: /sys/devices/platform/asus_laptop/wimax
+Date: October 2010
+KernelVersion: 2.6.37
+Contact: "Corentin Chary" <corentincj@iksaif.net>
+Description:
+ Control the wimax device. 1 means on, 0 means off.
+
+What: /sys/devices/platform/asus_laptop/wwan
+Date: October 2010
+KernelVersion: 2.6.37
+Contact: "Corentin Chary" <corentincj@iksaif.net>
+Description:
+ Control the wwan (3G) device. 1 means on, 0 means off.
--- /dev/null
+What: /sys/devices/platform/eeepc-wmi/cpufv
+Date: Oct 2010
+KernelVersion: 2.6.37
+Contact: "Corentin Chary" <corentincj@iksaif.net>
+Description:
+ Change CPU clock configuration (write-only).
+ There are three available clock configuration:
+ * 0 -> Super Performance Mode
+ * 1 -> High Performance Mode
+ * 2 -> Power Saving Mode
</sect2>
</sect1>
</chapter>
- <chapter id="clk">
- <title>Clock Framework Extensions</title>
-!Iinclude/linux/sh_clk.h
- </chapter>
<chapter id="mach">
<title>Machine Specific Interfaces</title>
<sect1 id="dreamcast">
</orgname>
<address>
- <email>hjk@linutronix.de</email>
+ <email>hjk@hansjkoch.de</email>
</address>
</affiliation>
</author>
<para>If you know of any translations for this document, or you are
interested in translating it, please email me
-<email>hjk@linutronix.de</email>.
+<email>hjk@hansjkoch.de</email>.
</para>
</sect1>
<title>Feedback</title>
<para>Find something wrong with this document? (Or perhaps something
right?) I would love to hear from you. Please email me at
- <email>hjk@linutronix.de</email>.</para>
+ <email>hjk@hansjkoch.de</email>.</para>
</sect1>
</chapter>
inclusion, it should be accepted by a relevant subsystem maintainer -
though this acceptance is not a guarantee that the patch will make it
all the way to the mainline. The patch will show up in the maintainer's
- subsystem tree and into the staging trees (described below). When the
+ subsystem tree and into the -next trees (described below). When the
process works, this step leads to more extensive review of the patch and
the discovery of any problems resulting from the integration of this
patch with work being done by others.
normally the right way to go.
-2.4: STAGING TREES
+2.4: NEXT TREES
The chain of subsystem trees guides the flow of patches into the kernel,
but it also raises an interesting question: what if somebody wants to look
the interesting subsystem trees, but that would be a big and error-prone
job.
-The answer comes in the form of staging trees, where subsystem trees are
+The answer comes in the form of -next trees, where subsystem trees are
collected for testing and review. The older of these trees, maintained by
Andrew Morton, is called "-mm" (for memory management, which is how it got
started). The -mm tree integrates patches from a long list of subsystem
Use of the MMOTM tree is likely to be a frustrating experience, though;
there is a definite chance that it will not even compile.
-The other staging tree, started more recently, is linux-next, maintained by
+The other -next tree, started more recently, is linux-next, maintained by
Stephen Rothwell. The linux-next tree is, by design, a snapshot of what
the mainline is expected to look like after the next merge window closes.
Linux-next trees are announced on the linux-kernel and linux-next mailing
See http://lwn.net/Articles/289013/ for more information on this topic, and
stay tuned; much is still in flux where linux-next is involved.
-Besides the mmotm and linux-next trees, the kernel source tree now contains
-the drivers/staging/ directory and many sub-directories for drivers or
-filesystems that are on their way to being added to the kernel tree
-proper, but they remain in drivers/staging/ while they still need more
-work.
-
+2.4.1: STAGING TREES
+
+The kernel source tree now contains the drivers/staging/ directory, where
+many sub-directories for drivers or filesystems that are on their way to
+being added to the kernel tree live. They remain in drivers/staging while
+they still need more work; once complete, they can be moved into the
+kernel proper. This is a way to keep track of drivers that aren't
+up to Linux kernel coding or quality standards, but people may want to use
+them and track development.
+
+Greg Kroah-Hartman currently (as of 2.6.36) maintains the staging tree.
+Drivers that still need work are sent to him, with each driver having
+its own subdirectory in drivers/staging/. Along with the driver source
+files, a TODO file should be present in the directory as well. The TODO
+file lists the pending work that the driver needs for acceptance into
+the kernel proper, as well as a list of people that should be Cc'd for any
+patches to the driver. Staging drivers that don't currently build should
+have their config entries depend upon CONFIG_BROKEN. Once they can
+be successfully built without outside patches, CONFIG_BROKEN can be removed.
2.5: TOOLS
+++ /dev/null
-
-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.
-
-sysfs
-~~~~~
-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 will 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 allocations could happen when the interface
-is registered with the class, or via a helper function.
-
The representation of the above is reflected in the directory tree
in EDAC's sysfs interface. Starting in directory
/sys/devices/system/edac/mc each memory controller will be represented
-by its own 'mcX' directory, where 'X" is the index of the MC.
+by its own 'mcX' directory, where 'X' is the index of the MC.
..../edac/mc/
....
Under each 'mcX' directory each 'csrowX' is again represented by a
-'csrowX', where 'X" is the csrow index:
+'csrowX', where 'X' is the csrow index:
.../mc/mc0/
In 'mcX' directories are EDAC control and attribute files for
-this 'X" instance of the memory controllers:
+this 'X' instance of the memory controllers:
Counter reset control file:
'csrowX' DIRECTORIES
In the 'csrowX' directories are EDAC control and attribute files for
-this 'X" instance of csrow:
+this 'X' instance of csrow:
Total Uncorrectable Errors count attribute file:
Geert Uytterhoeven <geert@linux-m68k.org>
00-INDEX
- - this file
+ - this file.
arkfb.txt
- info on the fbdev driver for ARK Logic chips.
aty128fb.txt
- info on the ATI Rage128 frame buffer driver.
cirrusfb.txt
- info on the driver for Cirrus Logic chipsets.
+cmap_xfbdev.txt
+ - an introduction to fbdev's cmap structures.
deferred_io.txt
- an introduction to deferred IO.
+efifb.txt
+ - info on the EFI platform driver for Intel based Apple computers.
+ep93xx-fb.txt
+ - info on the driver for EP93xx LCD controller.
fbcon.txt
- intro to and usage guide for the framebuffer console (fbcon).
framebuffer.txt
- introduction to frame buffer devices.
-imacfb.txt
- - info on the generic EFI platform driver for Intel based Macs.
+gxfb.txt
+ - info on the framebuffer driver for AMD Geode GX2 based processors.
intel810.txt
- documentation for the Intel 810/815 framebuffer driver.
intelfb.txt
- docs for Intel 830M/845G/852GM/855GM/865G/915G/945G fb driver.
internals.txt
- quick overview of frame buffer device internals.
+lxfb.txt
+ - info on the framebuffer driver for AMD Geode LX based processors.
matroxfb.txt
- info on the Matrox framebuffer driver for Alpha, Intel and PPC.
+metronomefb.txt
+ - info on the driver for the Metronome display controller.
modedb.txt
- info on the video mode database.
-matroxfb.txt
- - info on the Matrox frame buffer driver.
pvr2fb.txt
- info on the PowerVR 2 frame buffer driver.
pxafb.txt
- info on the fbdev driver for S3 Trio/Virge chips.
sa1100fb.txt
- information about the driver for the SA-1100 LCD controller.
+sh7760fb.txt
+ - info on the SH7760/SH7763 integrated LCDC Framebuffer driver.
sisfb.txt
- info on the framebuffer device driver for various SiS chips.
sstfb.txt
- info on the frame buffer driver for 3dfx' Voodoo Graphics boards.
tgafb.txt
- - info on the TGA (DECChip 21030) frame buffer driver
+ - info on the TGA (DECChip 21030) frame buffer driver.
+tridentfb.txt
+ info on the framebuffer driver for some Trident chip based cards.
+uvesafb.txt
+ - info on the userspace VESA (VBE2+ compliant) frame buffer device.
vesafb.txt
- - info on the VESA frame buffer device
+ - info on the VESA frame buffer device.
+viafb.modes
+ - list of modes for VIA Integration Graphic Chip.
+viafb.txt
+ - info on the VIA Integration Graphic Chip console framebuffer driver.
vt8623fb.txt
- info on the fb driver for the graphics core in VIA VT8623 chipsets.
sector_t (*bmap)(struct address_space *, sector_t);
int (*invalidatepage) (struct page *, unsigned long);
int (*releasepage) (struct page *, int);
+ void (*freepage)(struct page *);
int (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
loff_t offset, unsigned long nr_segs);
int (*launder_page) (struct page *);
locking rules:
- All except set_page_dirty may block
+ All except set_page_dirty and freepage may block
BKL PageLocked(page) i_mutex
writepage: no yes, unlocks (see below)
bmap: no
invalidatepage: no yes
releasepage: no yes
+freepage: no yes
direct_IO: no
launder_page: no yes
indicate that the buffers are (or may be) freeable. If ->releasepage is zero,
the kernel assumes that the fs has no private interest in the buffers.
+ ->freepage() is called when the kernel is done dropping the page
+from the page cache.
+
->launder_page() may be called prior to releasing a page if
it is still found to be dirty. It returns zero if the page was successfully
cleaned, or an error value if not. Note that in order to prevent the page
char *p = (char *) page;
tmp = simple_strtoul(p, &p, 10);
- if (!p || (*p && (*p != '\n')))
+ if ((*p != '\0') && (*p != '\n'))
return -EINVAL;
if (tmp > INT_MAX)
sector_t (*bmap)(struct address_space *, sector_t);
int (*invalidatepage) (struct page *, unsigned long);
int (*releasepage) (struct page *, int);
+ void (*freepage)(struct page *);
ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
loff_t offset, unsigned long nr_segs);
struct page* (*get_xip_page)(struct address_space *, sector_t,
releasepage: releasepage is called on PagePrivate pages to indicate
that the page should be freed if possible. ->releasepage
should remove any private data from the page and clear the
- PagePrivate flag. It may also remove the page from the
- address_space. If this fails for some reason, it may indicate
- failure with a 0 return value.
- This is used in two distinct though related cases. The first
- is when the VM finds a clean page with no active users and
+ PagePrivate flag. If releasepage() fails for some reason, it must
+ indicate failure with a 0 return value.
+ releasepage() is used in two distinct though related cases. The
+ first is when the VM finds a clean page with no active users and
wants to make it a free page. If ->releasepage succeeds, the
page will be removed from the address_space and become free.
need to ensure this. Possibly it can clear the PageUptodate
bit if it cannot free private data yet.
+ freepage: freepage is called once the page is no longer visible in
+ the page cache in order to allow the cleanup of any private
+ data. Since it may be called by the memory reclaimer, it
+ should not assume that the original address_space mapping still
+ exists, and it should not block.
+
direct_IO: called by the generic read/write routines to perform
direct_IO - that is IO requests which bypass the page cache
and transfer data directly between the storage and the
is configured as an output, this value may be written;
any nonzero value is treated as high.
+ If the pin can be configured as interrupt-generating interrupt
+ and if it has been configured to generate interrupts (see the
+ description of "edge"), you can poll(2) on that file and
+ poll(2) will return whenever the interrupt was triggered. If
+ you use poll(2), set the events POLLPRI and POLLERR. If you
+ use select(2), set the file descriptor in exceptfds. After
+ poll(2) returns, either lseek(2) to the beginning of the sysfs
+ file and read the new value or close the file and re-open it
+ to read the value.
+
"edge" ... reads as either "none", "rising", "falling", or
"both". Write these strings to select the signal edge(s)
that will make poll(2) on the "value" file return.
Mark M. Hoffman <mhoffman@lightlink.com>
Ported to 2.6 by Eric J. Bowersox <ericb@aspsys.com>
Adapted to 2.6.20 by Carsten Emde <ce@osadl.org>
- Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+ Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de>
Module Parameters
-----------------
Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
Authors:
- Hans J. Koch <hjk@linutronix.de>
+ Hans J. Koch <hjk@hansjkoch.de>
John Morris <john.morris@spirentcom.com>
Claus Gindhart <claus.gindhart@kontron.com>
improve throughput, but will also increase the
amount of memory reserved for use by the client.
+ swapaccount[=0|1]
+ [KNL] Enable accounting of swap in memory resource
+ controller if no parameter or 1 is given or disable
+ it if 0 is given (See Documentation/cgroups/memory.txt)
+
swiotlb= [IA-64] Number of I/O TLB slabs
switches= [HW,M68k]
Count buffering overhead as bytes/2^tcp_adv_win_scale
(if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale),
if it is <= 0.
+ Possible values are [-31, 31], inclusive.
Default: 2
tcp_allowed_congestion_control - STRING
SoC framework -> modifies on required cases certain OPPs -> OPP layer
-> queries to search/retrieve information ->
+Architectures that provide a SoC framework for OPP should select ARCH_HAS_OPP
+to make the OPP layer available.
+
OPP layer expects each domain to be represented by a unique device pointer. SoC
framework registers a set of initial OPPs per device with the OPP layer. This
list is expected to be an optimally small number typically around 5 per device.
+Release Date : Tues. Dec 14, 2010 17:00:00 PST 2010 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Adam Radford
+Current Version : 00.00.05.29-rc1
+Old Version : 00.00.04.31-rc1
+ 1. Rename megaraid_sas.c to megaraid_sas_base.c.
+ 2. Update GPL headers.
+ 3. Add MSI-X support and 'msix_disable' module parameter.
+ 4. Use lowest memory bar (for SR-IOV VF support).
+ 5. Add struct megasas_instance_temlate changes, and change all code to use
+ new instance entries:
+
+ irqreturn_t (*service_isr )(int irq, void *devp);
+ void (*tasklet)(unsigned long);
+ u32 (*init_adapter)(struct megasas_instance *);
+ u32 (*build_and_issue_cmd) (struct megasas_instance *,
+ struct scsi_cmnd *);
+ void (*issue_dcmd) (struct megasas_instance *instance,
+ struct megasas_cmd *cmd);
+
+ 6. Add code to support MegaRAID 9265/9285 controllers device id (0x5b).
+-------------------------------------------------------------------------------
1 Release Date : Thur. May 03, 2010 09:12:45 PST 2009 -
(emaild-id:megaraidlinux@lsi.com)
Bo Yang
/**
- * queuecommand - queue scsi command, invoke 'done' on completion
+ * queuecommand - queue scsi command, invoke scp->scsi_done on completion
+ * @shost: pointer to the scsi host object
* @scp: pointer to scsi command object
- * @done: function pointer to be invoked on completion
*
* Returns 0 on success.
*
*
* Other types of errors that are detected immediately may be
* flagged by setting scp->result to an appropriate value,
- * invoking the 'done' callback, and then returning 0 from this
- * function. If the command is not performed immediately (and the
- * LLD is starting (or will start) the given command) then this
- * function should place 0 in scp->result and return 0.
+ * invoking the scp->scsi_done callback, and then returning 0
+ * from this function. If the command is not performed
+ * immediately (and the LLD is starting (or will start) the given
+ * command) then this function should place 0 in scp->result and
+ * return 0.
*
* Command ownership. If the driver returns zero, it owns the
- * command and must take responsibility for ensuring the 'done'
- * callback is executed. Note: the driver may call done before
- * returning zero, but after it has called done, it may not
- * return any value other than zero. If the driver makes a
- * non-zero return, it must not execute the command's done
- * callback at any time.
- *
- * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave")
- * and is expected to be held on return.
+ * command and must take responsibility for ensuring the
+ * scp->scsi_done callback is executed. Note: the driver may
+ * call scp->scsi_done before returning zero, but after it has
+ * called scp->scsi_done, it may not return any value other than
+ * zero. If the driver makes a non-zero return, it must not
+ * execute the command's scsi_done callback at any time.
+ *
+ * Locks: up to and including 2.6.36, struct Scsi_Host::host_lock
+ * held on entry (with "irqsave") and is expected to be
+ * held on return. From 2.6.37 onwards, queuecommand is
+ * called without any locks held.
*
* Calling context: in interrupt (soft irq) or process context
*
- * Notes: This function should be relatively fast. Normally it will
- * not wait for IO to complete. Hence the 'done' callback is invoked
- * (often directly from an interrupt service routine) some time after
- * this function has returned. In some cases (e.g. pseudo adapter
- * drivers that manufacture the response to a SCSI INQUIRY)
- * the 'done' callback may be invoked before this function returns.
- * If the 'done' callback is not invoked within a certain period
- * the SCSI mid level will commence error processing.
- * If a status of CHECK CONDITION is placed in "result" when the
- * 'done' callback is invoked, then the LLD driver should
- * perform autosense and fill in the struct scsi_cmnd::sense_buffer
+ * Notes: This function should be relatively fast. Normally it
+ * will not wait for IO to complete. Hence the scp->scsi_done
+ * callback is invoked (often directly from an interrupt service
+ * routine) some time after this function has returned. In some
+ * cases (e.g. pseudo adapter drivers that manufacture the
+ * response to a SCSI INQUIRY) the scp->scsi_done callback may be
+ * invoked before this function returns. If the scp->scsi_done
+ * callback is not invoked within a certain period the SCSI mid
+ * level will commence error processing. If a status of CHECK
+ * CONDITION is placed in "result" when the scp->scsi_done
+ * callback is invoked, then the LLD driver should perform
+ * autosense and fill in the struct scsi_cmnd::sense_buffer
* array. The scsi_cmnd::sense_buffer array is zeroed prior to
* the mid level queuing a command to an LLD.
*
* Defined in: LLD
**/
- int queuecommand(struct scsi_cmnd * scp,
- void (*done)(struct scsi_cmnd *))
+ int queuecommand(struct Scsi_Host *shost, struct scsi_cmnd * scp)
/**
+++ /dev/null
-Clock framework on SuperH architecture
-
-The framework on SH extends existing API by the function clk_set_rate_ex,
-which prototype is as follows:
-
- clk_set_rate_ex (struct clk *clk, unsigned long rate, int algo_id)
-
-The algo_id parameter is used to specify algorithm used to recalculate clocks,
-adjanced to clock, specified as first argument. It is assumed that algo_id==0
-means no changes to adjanced clock
-
-Internally, the clk_set_rate_ex forwards request to clk->ops->set_rate method,
-if it is present in ops structure. The method should set the clock rate and adjust
-all needed clocks according to the passed algo_id.
-Exact values for algo_id are machine-dependent. For the sh7722, the following
-values are defined:
-
- NO_CHANGE = 0,
- IUS_N1_N1, /* I:U = N:1, U:Sh = N:1 */
- IUS_322, /* I:U:Sh = 3:2:2 */
- IUS_522, /* I:U:Sh = 5:2:2 */
- IUS_N11, /* I:U:Sh = N:1:1 */
- SB_N1, /* Sh:B = N:1 */
- SB3_N1, /* Sh:B3 = N:1 */
- SB3_32, /* Sh:B3 = 3:2 */
- SB3_43, /* Sh:B3 = 4:3 */
- SB3_54, /* Sh:B3 = 5:4 */
- BP_N1, /* B:P = N:1 */
- IP_N1 /* I:P = N:1 */
-
-Each of these constants means relation between clocks that can be set via the FRQCR
-register
S: Maintained
ARM/BCMRING ARM ARCHITECTURE
-M: Leo Chen <leochen@broadcom.com>
+M: Jiandong Zheng <jdzheng@broadcom.com>
M: Scott Branden <sbranden@broadcom.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-bcmring
ARM/BCMRING MTD NAND DRIVER
-M: Leo Chen <leochen@broadcom.com>
+M: Jiandong Zheng <jdzheng@broadcom.com>
M: Scott Branden <sbranden@broadcom.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mmc/host/msm_sdcc.h
F: drivers/serial/msm_serial.h
F: drivers/serial/msm_serial.c
-T: git git://codeaurora.org/quic/kernel/dwalker/linux-msm.git
+T: git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
S: Maintained
ARM/TOSA MACHINE SUPPORT
BONDING DRIVER
M: Jay Vosburgh <fubar@us.ibm.com>
-L: bonding-devel@lists.sourceforge.net
+L: netdev@vger.kernel.org
W: http://sourceforge.net/projects/bonding/
S: Supported
F: drivers/net/bonding/
S: Supported
F: drivers/net/cxgb4vf/
+STMMAC ETHERNET DRIVER
+M: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+L: netdev@vger.kernel.org
+W: http://www.stlinux.com
+S: Supported
+F: drivers/net/stmmac/
+
CYBERPRO FB DRIVER
M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
DOCBOOK FOR DOCUMENTATION
M: Randy Dunlap <rdunlap@xenotime.net>
S: Maintained
+F: scripts/kernel-doc
DOCKING STATION DRIVER
M: Shaohua Li <shaohua.li@intel.com>
DOCUMENTATION
M: Randy Dunlap <rdunlap@xenotime.net>
L: linux-doc@vger.kernel.org
+T: quilt oss.oracle.com/~rdunlap/kernel-doc-patches/current/
S: Maintained
F: Documentation/
DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
M: Greg Kroah-Hartman <gregkh@suse.de>
-T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6.git
S: Supported
F: Documentation/kobject.txt
F: drivers/base/
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
M: Chris Wilson <chris@chris-wilson.co.uk>
-L: intel-gfx@lists.freedesktop.org
+L: intel-gfx@lists.freedesktop.org (subscribers-only)
L: dri-devel@lists.freedesktop.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git
S: Supported
FRAMEBUFFER LAYER
L: linux-fbdev@vger.kernel.org
W: http://linux-fbdev.sourceforge.net/
+Q: http://patchwork.kernel.org/project/linux-fbdev/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6.git
S: Orphan
F: Documentation/fb/
-F: drivers/video/fb*
+F: drivers/video/
+F: include/video/
F: include/linux/fb.h
FREESCALE DMA DRIVER
NETEFFECT IWARP RNIC DRIVER (IW_NES)
M: Faisal Latif <faisal.latif@intel.com>
-M: Chien Tung <chien.tin.tung@intel.com>
L: linux-rdma@vger.kernel.org
-W: http://www.neteffect.com
+W: http://www.intel.com/Products/Server/Adapters/Server-Cluster/Server-Cluster-overview.htm
S: Supported
F: drivers/infiniband/hw/nes/
W: http://www.tilera.com/scm/
S: Supported
F: arch/tile/
+F: drivers/char/hvc_tile.c
+F: drivers/net/tile/
TLAN NETWORK DRIVER
M: Samuel Chessman <chessman@tux.org>
TULIP NETWORK DRIVERS
M: Grant Grundler <grundler@parisc-linux.org>
-M: Kyle McMartin <kyle@mcmartin.ca>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/tulip/
F: include/sound/wm????.h
F: sound/soc/codecs/wm*
+WORKQUEUE
+M: Tejun Heo <tj@kernel.org>
+L: linux-kernel@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git
+S: Maintained
+F: include/linux/workqueue.h
+F: kernel/workqueue.c
+F: Documentation/workqueue.txt
+
X.25 NETWORK LAYER
M: Andrew Hendry <andrew.hendry@gmail.com>
L: linux-x25@vger.kernel.org
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 37
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc6
NAME = Flesh-Eating Bats with Fangs
# *DOCUMENTATION*
select GENERIC_ATOMIC64 if (!CPU_32v6K || !AEABI)
select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
select HAVE_ARCH_KGDB
- select HAVE_KPROBES if (!XIP_KERNEL)
+ select HAVE_KPROBES if (!XIP_KERNEL && !THUMB2_KERNEL)
select HAVE_KRETPROBES if (HAVE_KPROBES)
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
config THUMB2_KERNEL
bool "Compile the kernel in Thumb-2 mode"
- depends on CPU_V7 && EXPERIMENTAL
+ depends on CPU_V7 && !CPU_V6 && EXPERIMENTAL
select AEABI
select ARM_ASM_UNIFIED
help
config FPE_NWFPE
bool "NWFPE math emulation"
- depends on !AEABI || OABI_COMPAT
+ depends on (!AEABI || OABI_COMPAT) && !THUMB2_KERNEL
---help---
Say Y to include the NWFPE floating point emulator in the kernel.
This is necessary to run most binaries. Linux does not currently
$(obj)/uImage: LOADADDR=$(ZRELADDR)
endif
-ifeq ($(CONFIG_THUMB2_KERNEL),y)
-# Set bit 0 to 1 so that "mov pc, rx" switches to Thumb-2 mode
-$(obj)/uImage: STARTADDR=$(shell echo $(LOADADDR) | sed -e "s/.$$/1/")
-else
$(obj)/uImage: STARTADDR=$(LOADADDR)
-endif
$(obj)/uImage: $(obj)/zImage FORCE
$(call if_changed,uimage)
.size _start, . - _start
+ .align
+
.type data,#object
data: .word initrd_start @ source initrd address
.word initrd_phys @ destination initrd address
* sort out different calling conventions
*/
.align
+ .arm @ Always enter in ARM state
start:
.type start,#function
- .rept 8
+ THUMB( adr r12, BSYM(1f) )
+ THUMB( bx r12 )
+ THUMB( .rept 6 )
+ ARM( .rept 8 )
mov r0, r0
.endr
.word 0x016f2818 @ Magic numbers to help the loader
.word start @ absolute load/run zImage address
.word _edata @ zImage end address
+ THUMB( .thumb )
1: mov r7, r1 @ save architecture ID
mov r8, r2 @ save atags pointer
ldr sp, [r0, #28]
#ifdef CONFIG_AUTO_ZRELADDR
@ determine final kernel image address
- and r4, pc, #0xf8000000
+ mov r4, pc
+ and r4, r4, #0xf8000000
add r4, r4, #TEXT_OFFSET
#else
ldr r4, =zreladdr
*/
mov r1, #0x1e
orr r1, r1, #3 << 10
- mov r2, pc, lsr #20
+ mov r2, pc
+ mov r2, r2, lsr #20
orr r1, r1, r2, lsl #20
add r0, r3, r2, lsl #2
str r1, [r0], #4
reloc_end:
.align
- .section ".stack", "w"
+ .section ".stack", "aw", %nobits
user_stack: .space 4096
user_stack_end:
.bss : { *(.bss) }
_end = .;
- .stack (NOLOAD) : { *(.stack) }
+ .stack : { *(.stack) }
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
unsigned int shift = (irq % 4) * 8;
unsigned int cpu = cpumask_first(mask_val);
u32 val;
+ struct irq_desc *desc;
spin_lock(&irq_controller_lock);
- irq_desc[irq].node = cpu;
+ desc = irq_to_desc(irq);
+ if (desc == NULL) {
+ spin_unlock(&irq_controller_lock);
+ return -EINVAL;
+ }
+ desc->node = cpu;
val = readl(reg) & ~(0xff << shift);
val |= 1 << (cpu + shift);
writel(val, reg);
void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
unsigned int irq_start)
{
- unsigned int max_irq, i;
+ unsigned int gic_irqs, irq_limit, i;
u32 cpumask = 1 << smp_processor_id();
if (gic_nr >= MAX_GIC_NR)
/*
* Find out how many interrupts are supported.
- */
- max_irq = readl(base + GIC_DIST_CTR) & 0x1f;
- max_irq = (max_irq + 1) * 32;
-
- /*
* The GIC only supports up to 1020 interrupt sources.
- * Limit this to either the architected maximum, or the
- * platform maximum.
*/
- if (max_irq > max(1020, NR_IRQS))
- max_irq = max(1020, NR_IRQS);
+ gic_irqs = readl(base + GIC_DIST_CTR) & 0x1f;
+ gic_irqs = (gic_irqs + 1) * 32;
+ if (gic_irqs > 1020)
+ gic_irqs = 1020;
/*
* Set all global interrupts to be level triggered, active low.
*/
- for (i = 32; i < max_irq; i += 16)
+ for (i = 32; i < gic_irqs; i += 16)
writel(0, base + GIC_DIST_CONFIG + i * 4 / 16);
/*
* Set all global interrupts to this CPU only.
*/
- for (i = 32; i < max_irq; i += 4)
+ for (i = 32; i < gic_irqs; i += 4)
writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
/*
* Set priority on all global interrupts.
*/
- for (i = 32; i < max_irq; i += 4)
+ for (i = 32; i < gic_irqs; i += 4)
writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
/*
* Disable all interrupts. Leave the PPI and SGIs alone
* as these enables are banked registers.
*/
- for (i = 32; i < max_irq; i += 32)
+ for (i = 32; i < gic_irqs; i += 32)
writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
+ /*
+ * Limit number of interrupts registered to the platform maximum
+ */
+ irq_limit = gic_data[gic_nr].irq_offset + gic_irqs;
+ if (WARN_ON(irq_limit > NR_IRQS))
+ irq_limit = NR_IRQS;
+
/*
* Setup the Linux IRQ subsystem.
*/
- for (i = irq_start; i < gic_data[gic_nr].irq_offset + max_irq; i++) {
+ for (i = irq_start; i < irq_limit; i++) {
set_irq_chip(i, &gic_chip);
set_irq_chip_data(i, &gic_data[gic_nr]);
set_irq_handler(i, handle_level_irq);
--- /dev/null
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_AT91=y
+CONFIG_MACH_ONEARM=y
+CONFIG_ARCH_AT91RM9200DK=y
+CONFIG_MACH_AT91RM9200EK=y
+CONFIG_MACH_CSB337=y
+CONFIG_MACH_CSB637=y
+CONFIG_MACH_CARMEVA=y
+CONFIG_MACH_ATEB9200=y
+CONFIG_MACH_KB9200=y
+CONFIG_MACH_PICOTUX2XX=y
+CONFIG_MACH_KAFA=y
+CONFIG_MACH_ECBAT91=y
+CONFIG_MACH_YL9200=y
+CONFIG_MACH_CPUAT91=y
+CONFIG_MACH_ECO920=y
+CONFIG_MTD_AT91_DATAFLASH_CARD=y
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_AT91_TIMER_HZ=100
+# CONFIG_ARM_THUMB is not set
+CONFIG_PCCARD=y
+CONFIG_AT91_CF=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_LEDS=y
+CONFIG_LEDS_CPU=y
+CONFIG_ZBOOT_ROM_TEXT=0x10000000
+CONFIG_ZBOOT_ROM_BSS=0x20040000
+CONFIG_KEXEC=y
+CONFIG_FPE_NWFPE=y
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_AFS_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PLATRAM=y
+CONFIG_MTD_DATAFLASH=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_NAND_PLATFORM=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_GLUEBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_ATMEL_TCLIB=y
+CONFIG_EEPROM_LEGACY=m
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_TUN=m
+CONFIG_PHYLIB=y
+CONFIG_DAVICOM_PHY=y
+CONFIG_SMSC_PHY=y
+CONFIG_MICREL_PHY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_ARM_AT91_ETHER=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=32
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_GPIO=y
+CONFIG_SPI=y
+CONFIG_SPI_ATMEL=y
+CONFIG_SPI_BITBANG=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HWMON=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1029=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM73=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83791D=m
+CONFIG_SENSORS_W83792D=m
+CONFIG_SENSORS_W83793=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_AT91RM9200_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_S1D13XXX=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_DISPLAY_SUPPORT=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_MINI_4x6=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_USB=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_MON=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_FTDI_SIO=y
+CONFIG_USB_SERIAL_KEYSPAN=y
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_MCT_U232=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_ETH=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_MMC=y
+CONFIG_MMC_AT91=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_PCF8563=y
+CONFIG_RTC_DRV_AT91RM9200=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_REISERFS_FS=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=m
+CONFIG_TMPFS=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_CRAMFS=y
+CONFIG_MINIX_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_SMB_FS=m
+CONFIG_CIFS=m
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_FTRACE is not set
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_SHA1=y
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91RM9200DK=y
-CONFIG_MACH_ECO920=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_GADGET=y
-CONFIG_MMC=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_AT91RM9200EK=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-CONFIG_FB=y
-CONFIG_FB_S1D13XXX=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_GADGET=y
-CONFIG_MMC=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_ATEB9200=y
-CONFIG_PCCARD=m
-CONFIG_AT91_CF=m
-CONFIG_PREEMPT=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_FPE_NWFPE=y
-CONFIG_PM=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-# CONFIG_IPV6 is not set
-CONFIG_BRIDGE=m
-CONFIG_VLAN_8021Q=m
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK_RO=y
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_BLK_DEV_NBD=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
-CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=m
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-CONFIG_TUN=m
-CONFIG_PHYLIB=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-CONFIG_USB_USBNET=y
-CONFIG_USB_NET_GL620A=y
-CONFIG_USB_NET_PLUSB=y
-CONFIG_USB_NET_RNDIS_HOST=y
-CONFIG_USB_ALI_M5632=y
-CONFIG_USB_AN2720=y
-CONFIG_USB_EPSON2888=y
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPPOE=m
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_I2C=m
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_GPIO=m
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_SOUND=y
-CONFIG_USB_HID=m
-CONFIG_HID_PID=y
-CONFIG_USB_HIDDEV=y
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-CONFIG_USB_STORAGE=m
-CONFIG_USB_STORAGE_DATAFAB=m
-CONFIG_USB_STORAGE_FREECOM=m
-CONFIG_USB_STORAGE_USBAT=m
-CONFIG_USB_STORAGE_SDDR09=m
-CONFIG_USB_STORAGE_SDDR55=m
-CONFIG_USB_STORAGE_JUMPSHOT=m
-CONFIG_USB_SERIAL=m
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_FTDI_SIO=m
-CONFIG_USB_SERIAL_PL2303=m
-CONFIG_USB_GADGET=m
-CONFIG_USB_ETH=m
-CONFIG_USB_GADGETFS=m
-CONFIG_USB_FILE_STORAGE=m
-CONFIG_USB_G_SERIAL=m
-CONFIG_MMC=m
-CONFIG_MMC_DEBUG=y
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_HCTOSYS is not set
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=m
-CONFIG_EXT3_FS=m
-CONFIG_REISERFS_FS=m
-CONFIG_INOTIFY=y
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_NTFS_FS=m
-CONFIG_NTFS_RW=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V4=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAC_PARTITION=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_MINIX_SUBPARTITION=y
-CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_UNIXWARE_DISKLABEL=y
-CONFIG_NLS_CODEPAGE_932=m
-CONFIG_NLS_ASCII=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_UTF8=m
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRC16=m
-CONFIG_LIBCRC32C=m
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-# CONFIG_HOTPLUG is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_CARMEVA=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIO=m
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_MMC=m
-CONFIG_MMC_DEBUG=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-# CONFIG_DNOTIFY is not set
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_NFSD=y
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_CPUAT91=y
-CONFIG_AT91_TIMER_HZ=100
-# CONFIG_ARM_THUMB is not set
-CONFIG_PREEMPT=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PLATRAM=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_MULTI_LUN=y
-# CONFIG_SCSI_LOWLEVEL is not set
-CONFIG_NETDEVICES=y
-CONFIG_PHYLIB=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_PPP=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=32
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_GPIO_SYSFS=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_ETH=m
-CONFIG_MMC=y
-CONFIG_MMC_AT91=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_GPIO=y
-CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_HCTOSYS is not set
-CONFIG_RTC_DRV_DS1307=y
-CONFIG_RTC_DRV_PCF8563=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
-CONFIG_AUTOFS4_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_CRAMFS=y
-CONFIG_MINIX_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_UTF8=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_CSB337=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,38400 initrd=0x20410000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_ATMEL_SSC=y
-CONFIG_SCSI=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_SERIAL=y
-CONFIG_USB_SERIAL_CONSOLE=y
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_FTDI_SIO=y
-CONFIG_USB_SERIAL_KEYSPAN=y
-CONFIG_USB_SERIAL_KEYSPAN_MPR=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19=y
-CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
-CONFIG_USB_SERIAL_MCT_U232=y
-CONFIG_USB_GADGET=y
-CONFIG_MMC=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc1"
-# CONFIG_RTC_INTF_SYSFS is not set
-CONFIG_RTC_DRV_DS1307=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_CSB637=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,38400 initrd=0x20410000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_SCSI=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_SERIAL=y
-CONFIG_USB_SERIAL_CONSOLE=y
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_FTDI_SIO=y
-CONFIG_USB_SERIAL_KEYSPAN=y
-CONFIG_USB_SERIAL_KEYSPAN_MPR=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19=y
-CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
-CONFIG_USB_SERIAL_MCT_U232=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_ECBAT91=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_PREEMPT=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="rootfstype=reiserfs root=/dev/mmcblk0p1 console=ttyS0,115200n8 rootdelay=1"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IPV6 is not set
-CONFIG_CFG80211=y
-CONFIG_MAC80211=y
-# CONFIG_STANDALONE is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_AFS_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_PPP=y
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_SPI=y
-CONFIG_SPI_BITBANG=y
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_PRINTER=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
-CONFIG_MMC_AT91=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_HCTOSYS is not set
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-CONFIG_REISERFS_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CONFIGFS_FS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_PCBC=y
-CONFIG_CRYPTO_SHA1=y
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_KAFA=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PREEMPT=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20800000,10M root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_BINFMT_MISC=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK_RO=y
-CONFIG_NETDEVICES=y
-CONFIG_PHYLIB=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=32
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_HCTOSYS is not set
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_DES=y
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_AUDIT=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_KB9200=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x10000000
-CONFIG_ZBOOT_ROM_BSS=0x20040000
-CONFIG_CMDLINE="noinitrd root=/dev/mtdblock0 rootfstype=jffs2 mem=64M"
-CONFIG_KEXEC=y
-CONFIG_FPE_NWFPE=y
-CONFIG_BINFMT_MISC=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_FIRMWARE_IN_KERNEL is not set
-CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_GLUEBI=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_ATMEL_TCLIB=y
-CONFIG_ATMEL_SSC=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SPI_ATTRS=m
-# CONFIG_SCSI_LOWLEVEL is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_AT91RM9200_WATCHDOG=y
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-# CONFIG_LCD_CLASS_DEVICE is not set
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_BACKLIGHT_GENERIC is not set
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_MINI_4x6=y
-# CONFIG_HID_SUPPORT is not set
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_LIBUSUAL=y
-CONFIG_MMC=y
-CONFIG_MMC_AT91=m
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_INOTIFY=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_CONFIGFS_FS=y
-CONFIG_JFFS2_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_UTF8=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_ONEARM=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp mem=64M"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IPV6=y
-# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET6_XFRM_MODE_BEET is not set
-# CONFIG_IPV6_SIT is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_GADGET=y
-CONFIG_MMC=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_ROOT_NFS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
+++ /dev/null
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=m
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-# CONFIG_KALLSYMS is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_PICOTUX2XX=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_KEXEC=y
-CONFIG_FPE_NWFPE=y
-CONFIG_BINFMT_MISC=m
-CONFIG_NET=y
-CONFIG_PACKET=m
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=m
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
-CONFIG_INET_AH=m
-CONFIG_INET_ESP=m
-CONFIG_INET_IPCOMP=m
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
-CONFIG_INET_XFRM_MODE_BEET=m
-CONFIG_INET_DIAG=m
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_INET6_AH=m
-CONFIG_INET6_ESP=m
-CONFIG_INET6_IPCOMP=m
-CONFIG_IPV6_MIP6=m
-CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
-CONFIG_IPV6_TUNNEL=m
-CONFIG_BRIDGE=m
-CONFIG_VLAN_8021Q=m
-CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
-CONFIG_BT_RFCOMM=m
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=m
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=m
-CONFIG_FW_LOADER=m
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_EEPROM_LEGACY=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
-CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=m
-CONFIG_NETDEVICES=y
-CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-CONFIG_USB_CATC=m
-CONFIG_USB_KAWETH=m
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_RTL8150=m
-CONFIG_USB_USBNET=m
-CONFIG_USB_NET_DM9601=m
-CONFIG_USB_NET_GL620A=m
-CONFIG_USB_NET_PLUSB=m
-CONFIG_USB_NET_MCS7830=m
-CONFIG_USB_NET_RNDIS_HOST=m
-CONFIG_USB_ALI_M5632=y
-CONFIG_USB_AN2720=y
-CONFIG_USB_EPSON2888=y
-CONFIG_USB_KC2190=y
-CONFIG_PPP=m
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPP_MPPE=m
-CONFIG_PPPOE=m
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-CONFIG_SLIP_MODE_SLIP6=y
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_I2C=m
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_GPIO=m
-CONFIG_HWMON=m
-CONFIG_SENSORS_ADM1021=m
-CONFIG_SENSORS_ADM1025=m
-CONFIG_SENSORS_ADM1026=m
-CONFIG_SENSORS_ADM1029=m
-CONFIG_SENSORS_ADM1031=m
-CONFIG_SENSORS_ADM9240=m
-CONFIG_SENSORS_DS1621=m
-CONFIG_SENSORS_GL518SM=m
-CONFIG_SENSORS_GL520SM=m
-CONFIG_SENSORS_IT87=m
-CONFIG_SENSORS_LM63=m
-CONFIG_SENSORS_LM75=m
-CONFIG_SENSORS_LM77=m
-CONFIG_SENSORS_LM78=m
-CONFIG_SENSORS_LM80=m
-CONFIG_SENSORS_LM83=m
-CONFIG_SENSORS_LM85=m
-CONFIG_SENSORS_LM87=m
-CONFIG_SENSORS_LM90=m
-CONFIG_SENSORS_LM92=m
-CONFIG_SENSORS_MAX1619=m
-CONFIG_SENSORS_PCF8591=m
-CONFIG_SENSORS_SMSC47B397=m
-CONFIG_SENSORS_W83781D=m
-CONFIG_SENSORS_W83791D=m
-CONFIG_SENSORS_W83792D=m
-CONFIG_SENSORS_W83793=m
-CONFIG_SENSORS_W83L785TS=m
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=m
-CONFIG_HID=m
-CONFIG_USB=m
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_OHCI_HCD=m
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-CONFIG_USB_STORAGE=m
-CONFIG_USB_SERIAL=m
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_PL2303=m
-CONFIG_MMC=m
-CONFIG_MMC_AT91=m
-CONFIG_RTC_CLASS=m
-CONFIG_RTC_DRV_AT91RM9200=m
-CONFIG_EXT2_FS=m
-CONFIG_EXT3_FS=m
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-CONFIG_UDF_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_NTFS_FS=m
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_NFS_FS=m
-CONFIG_SMB_FS=m
-CONFIG_CIFS=m
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_AMIGA_PARTITION=y
-CONFIG_NLS_DEFAULT="utf-8"
-CONFIG_NLS_CODEPAGE_437=m
-CONFIG_NLS_CODEPAGE_737=m
-CONFIG_NLS_CODEPAGE_775=m
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-CONFIG_NLS_CODEPAGE_855=m
-CONFIG_NLS_CODEPAGE_857=m
-CONFIG_NLS_CODEPAGE_860=m
-CONFIG_NLS_CODEPAGE_861=m
-CONFIG_NLS_CODEPAGE_862=m
-CONFIG_NLS_CODEPAGE_863=m
-CONFIG_NLS_CODEPAGE_864=m
-CONFIG_NLS_CODEPAGE_865=m
-CONFIG_NLS_CODEPAGE_866=m
-CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
-CONFIG_NLS_CODEPAGE_932=m
-CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-CONFIG_NLS_ASCII=m
-CONFIG_NLS_ISO8859_1=m
-CONFIG_NLS_ISO8859_2=m
-CONFIG_NLS_ISO8859_3=m
-CONFIG_NLS_ISO8859_4=m
-CONFIG_NLS_ISO8859_5=m
-CONFIG_NLS_ISO8859_6=m
-CONFIG_NLS_ISO8859_7=m
-CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_KOI8_R=m
-CONFIG_NLS_KOI8_U=m
-CONFIG_NLS_UTF8=m
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_LL=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAMELLIA=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_FCRYPT=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_LIBCRC32C=m
+++ /dev/null
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91RM9200DK=y
-CONFIG_MACH_YL9200=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PLATRAM=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_PLATFORM=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=3
-CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_MISC_DEVICES is not set
-CONFIG_BLK_DEV_SD=y
-CONFIG_ATA=y
-CONFIG_NETDEVICES=y
-CONFIG_PHYLIB=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
-CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_GPIO=y
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ADS7846=y
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_SPI=y
-CONFIG_SPI_DEBUG=y
-CONFIG_SPI_ATMEL=y
-CONFIG_FB=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_DISPLAY_SUPPORT=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_LOGO=y
-# CONFIG_LOGO_LINUX_MONO is not set
-# CONFIG_LOGO_LINUX_VGA16 is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_M66592=y
-CONFIG_USB_FILE_STORAGE=m
-CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_AT91=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-CONFIG_REISERFS_FS=y
-CONFIG_INOTIFY=y
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=1
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_RUBIN=y
-CONFIG_CRAMFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAC_PARTITION=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_SLUB_DEBUG_ON=y
-CONFIG_DEBUG_KOBJECT=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_LIST=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
@ Slightly optimised to avoid incrementing the pointer twice
usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort
.if \rept == 2
- usraccoff \instr, \reg, \ptr, \inc, 4, \cond, \abort
+ usraccoff \instr, \reg, \ptr, \inc, \inc, \cond, \abort
.endif
add\cond \ptr, #\rept * \inc
#ifdef CONFIG_CPU_HAS_ASID
#define ASID(mm) ((mm)->context.id & 255)
+
+/* init_mm.context.id_lock should be initialized. */
+#define INIT_MM_CONTEXT(name) \
+ .context.id_lock = __SPIN_LOCK_UNLOCKED(name.context.id_lock),
#else
#define ASID(mm) (0)
#endif
#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd)))
+/* we don't need complex calculations here as the pmd is folded into the pgd */
+#define pmd_addr_end(addr,end) (end)
+
/*
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
* A special ghost syscall is used for that (see traps.c).
*/
stmfd sp!, {r7, lr}
- ldr r7, =1f @ it's 20 bits
+ ldr r7, 1f @ it's 20 bits
swi __ARM_NR_cmpxchg
ldmfd sp!, {r7, pc}
1: .word __ARM_NR_cmpxchg
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
+ THUMB( it eq ) @ force fixup-able long branch encoding
beq __error_p @ yes, error 'p'
bl __lookup_machine_type @ r5=machinfo
movs r8, r5 @ invalid machine (r5=0)?
+ THUMB( it eq ) @ force fixup-able long branch encoding
beq __error_a @ yes, error 'a'
bl __vet_atags
#ifdef CONFIG_SMP_ON_UP
mov pc, lr
ENDPROC(__create_page_tables)
.ltorg
+ .align
__enable_mmu_loc:
.long .
.long __enable_mmu
bl __lookup_processor_type
movs r10, r5 @ invalid processor?
moveq r0, #'p' @ yes, error 'p'
+ THUMB( it eq ) @ force fixup-able long branch encoding
beq __error_p
/*
b secondary_start_kernel
ENDPROC(__secondary_switched)
+ .align
+
.type __secondary_data, %object
__secondary_data:
.long .
mov pc, lr
ENDPROC(__fixup_smp)
+ .align
1: .word .
.word __smpalt_begin
.word __smpalt_end
ldr r2,kexec_boot_atags
mov pc,lr
+ .align
+
.globl kexec_start_address
kexec_start_address:
.long 0x0
*/
.L_found:
#if __LINUX_ARM_ARCH__ >= 5
- rsb r1, r3, #0
- and r3, r3, r1
+ rsb r0, r3, #0
+ and r3, r3, r0
clz r3, r3
rsb r3, r3, #31
add r0, r2, r3
addeq r2, r2, #1
mov r0, r2
#endif
+ cmp r1, r0 @ Clamp to maxbit
+ movlo r0, r1
mov pc, lr
#ifndef __ASM_ARCH_VMALLOC_H
#define __ASM_ARCH_VMALLOC_H
-#define VMALLOC_END 0xd0000000
+#define VMALLOC_END 0xd0000000UL
#endif /* __ASM_ARCH_VMALLOC_H */
# AT91RM9200 board-specific support
obj-$(CONFIG_MACH_ONEARM) += board-1arm.o
-obj-$(CONFIG_ARCH_AT91RM9200DK) += board-dk.o
-obj-$(CONFIG_MACH_AT91RM9200EK) += board-ek.o
+obj-$(CONFIG_ARCH_AT91RM9200DK) += board-rm9200dk.o
+obj-$(CONFIG_MACH_AT91RM9200EK) += board-rm9200ek.o
obj-$(CONFIG_MACH_CSB337) += board-csb337.o
obj-$(CONFIG_MACH_CSB637) += board-csb637.o
obj-$(CONFIG_MACH_CARMEVA) += board-carmeva.o
static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
struct platform_device *atmel_default_console_device; /* the serial console device */
-void __init __deprecated at91_init_serial(struct at91_uart_config *config)
-{
- int i;
-
- /* Fill in list of supported UARTs */
- for (i = 0; i < config->nr_tty; i++) {
- switch (config->tty_map[i]) {
- case 0:
- configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_uarts[i] = &at91rm9200_uart0_device;
- at91_clock_associate("usart0_clk", &at91rm9200_uart0_device.dev, "usart");
- break;
- case 1:
- configure_usart1_pins(ATMEL_UART_CTS | ATMEL_UART_RTS | ATMEL_UART_DSR | ATMEL_UART_DTR | ATMEL_UART_DCD | ATMEL_UART_RI);
- at91_uarts[i] = &at91rm9200_uart1_device;
- at91_clock_associate("usart1_clk", &at91rm9200_uart1_device.dev, "usart");
- break;
- case 2:
- configure_usart2_pins(0);
- at91_uarts[i] = &at91rm9200_uart2_device;
- at91_clock_associate("usart2_clk", &at91rm9200_uart2_device.dev, "usart");
- break;
- case 3:
- configure_usart3_pins(0);
- at91_uarts[i] = &at91rm9200_uart3_device;
- at91_clock_associate("usart3_clk", &at91rm9200_uart3_device.dev, "usart");
- break;
- case 4:
- configure_dbgu_pins();
- at91_uarts[i] = &at91rm9200_dbgu_device;
- at91_clock_associate("mck", &at91rm9200_dbgu_device.dev, "usart");
- break;
- default:
- continue;
- }
- at91_uarts[i]->id = i; /* update ID number to mapped ID */
- }
-
- /* Set serial console device */
- if (config->console_tty < ATMEL_MAX_UART)
- atmel_default_console_device = at91_uarts[config->console_tty];
- if (!atmel_default_console_device)
- printk(KERN_INFO "AT91: No default serial console defined.\n");
-}
-
void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
{
struct platform_device *pdev;
#include "generic.h"
-/*
- * Serial port configuration.
- * 0 .. 3 = USART0 .. USART3
- * 4 = DBGU
- */
-static struct at91_uart_config __initdata onearm_uart_config = {
- .console_tty = 0, /* ttyS0 */
- .nr_tty = 3,
- .tty_map = { 4, 0, 1, -1, -1 }, /* ttyS0, ..., ttyS4 */
-};
-
static void __init onearm_map_io(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91rm9200_initialize(18432000, AT91RM9200_PQFP);
- /* Setup the serial ports and console */
- at91_init_serial(&onearm_uart_config);
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+ /* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
}
static void __init onearm_init_irq(void)
#include "generic.h"
-/*
- * Serial port configuration.
- * 0 .. 3 = USART0 .. USART3
- * 4 = DBGU
- */
-static struct at91_uart_config __initdata kafa_uart_config = {
- .console_tty = 0, /* ttyS0 */
- .nr_tty = 2,
- .tty_map = { 4, 0, -1, -1, -1 } /* ttyS0, ..., ttyS4 */
-};
-
static void __init kafa_map_io(void)
{
/* Initialize processor: 18.432 MHz crystal */
/* Set up the LEDs */
at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
- /* Setup the serial ports and console */
- at91_init_serial(&kafa_uart_config);
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
}
static void __init kafa_init_irq(void)
#include "generic.h"
-/*
- * Serial port configuration.
- * 0 .. 3 = USART0 .. USART3
- * 4 = DBGU
- */
-static struct at91_uart_config __initdata picotux200_uart_config = {
- .console_tty = 0, /* ttyS0 */
- .nr_tty = 2,
- .tty_map = { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */
-};
-
static void __init picotux200_map_io(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91rm9200_initialize(18432000, AT91RM9200_BGA);
- /* Setup the serial ports and console */
- at91_init_serial(&picotux200_uart_config);
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
}
static void __init picotux200_init_irq(void)
.ports = 1,
};
-// static struct at91_udc_data __initdata picotux200_udc_data = {
-// .vbus_pin = AT91_PIN_PD4,
-// .pullup_pin = AT91_PIN_PD5,
-// };
-
static struct at91_mmc_data __initdata picotux200_mmc_data = {
.det_pin = AT91_PIN_PB27,
.slot_b = 0,
.wp_pin = AT91_PIN_PA17,
};
-// static struct spi_board_info picotux200_spi_devices[] = {
-// { /* DataFlash chip */
-// .modalias = "mtd_dataflash",
-// .chip_select = 0,
-// .max_speed_hz = 15 * 1000 * 1000,
-// },
-// #ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
-// { /* DataFlash card */
-// .modalias = "mtd_dataflash",
-// .chip_select = 3,
-// .max_speed_hz = 15 * 1000 * 1000,
-// },
-// #endif
-// };
-
#define PICOTUX200_FLASH_BASE AT91_CHIPSELECT_0
#define PICOTUX200_FLASH_SIZE SZ_4M
at91_add_device_eth(&picotux200_eth_data);
/* USB Host */
at91_add_device_usbh(&picotux200_usbh_data);
- /* USB Device */
- // at91_add_device_udc(&picotux200_udc_data);
- // at91_set_multi_drive(picotux200_udc_data.pullup_pin, 1); /* pullup_pin is connected to reset */
/* I2C */
at91_add_device_i2c(NULL, 0);
- /* SPI */
- // at91_add_device_spi(picotux200_spi_devices, ARRAY_SIZE(picotux200_spi_devices));
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
- /* DataFlash card */
- at91_set_gpio_output(AT91_PIN_PB22, 0);
-#else
/* MMC */
at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
at91_add_device_mmc(0, &picotux200_mmc_data);
-#endif
/* NOR Flash */
platform_device_register(&picotux200_flash);
}
/*
- * linux/arch/arm/mach-at91/board-dk.c
+ * linux/arch/arm/mach-at91/board-rm9200dk.c
*
* Copyright (C) 2005 SAN People
*
// .vcc_pin = ... always powered
};
+#ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
static struct at91_mmc_data __initdata dk_mmc_data = {
.slot_b = 0,
.wire4 = 1,
};
+#endif
static struct spi_board_info dk_spi_devices[] = {
{ /* DataFlash chip */
/*
- * linux/arch/arm/mach-at91/board-ek.c
+ * linux/arch/arm/mach-at91/board-rm9200ek.c
*
* Copyright (C) 2005 SAN People
*
.pullup_pin = AT91_PIN_PD5,
};
+#ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
static struct at91_mmc_data __initdata ek_mmc_data = {
.det_pin = AT91_PIN_PB27,
.slot_b = 0,
.wire4 = 1,
.wp_pin = AT91_PIN_PA17,
};
+#endif
static struct spi_board_info ek_spi_devices[] = {
{ /* DataFlash chip */
* EPSON S1D13806 FB (discontinued chip)
* EPSON S1D13506 FB
*/
-#if defined(CONFIG_FB_S1D135XX) || defined(CONFIG_FB_S1D13XXX_MODULE)
+#if defined(CONFIG_FB_S1D13XXX) || defined(CONFIG_FB_S1D13XXX_MODULE)
#include <video/s1d13xxxfb.h>
extern void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins);
extern void __init at91_set_serial_console(unsigned portnr);
-struct at91_uart_config {
- unsigned short console_tty; /* tty number of serial console */
- unsigned short nr_tty; /* number of serial tty's */
- short tty_map[]; /* map UART to tty number */
-};
extern struct platform_device *atmel_default_console_device;
-extern void __init __deprecated at91_init_serial(struct at91_uart_config *config);
struct atmel_uart_data {
short use_dma_tx; /* use transmit DMA? */
* 0xe0000000 to 0xefffffff. This gives us 256 MB of vm space and handles
* larger physical memory designs better.
*/
-#define VMALLOC_END 0xf0000000
+#define VMALLOC_END 0xf0000000UL
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define VMALLOC_END 0xd0000000
+#define VMALLOC_END 0xd0000000UL
{
int i;
- hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS,
+ hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0,
"imprecise external abort");
for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
CLK(NULL, "uart1", &uart1_clk),
CLK(NULL, "uart2", &uart2_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
- CLK("davinci-asp.0", NULL, &asp0_clk),
- CLK("davinci-asp.1", NULL, &asp1_clk),
+ CLK("davinci-mcbsp.0", NULL, &asp0_clk),
+ CLK("davinci-mcbsp.1", NULL, &asp1_clk),
CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
CLK("spi_davinci.0", NULL, &spi0_clk),
};
static struct platform_device dm355_asp1_device = {
- .name = "davinci-asp",
+ .name = "davinci-mcbsp",
.id = 1,
.num_resources = ARRAY_SIZE(dm355_asp1_resources),
.resource = dm355_asp1_resources,
CLK(NULL, "usb", &usb_clk),
CLK("davinci_emac.1", NULL, &emac_clk),
CLK("davinci_voicecodec", NULL, &voicecodec_clk),
- CLK("davinci-asp.0", NULL, &asp0_clk),
+ CLK("davinci-mcbsp", NULL, &asp0_clk),
CLK(NULL, "rto", &rto_clk),
CLK(NULL, "mjcp", &mjcp_clk),
CLK(NULL, NULL, NULL),
};
static struct platform_device dm365_asp_device = {
- .name = "davinci-asp",
- .id = 0,
+ .name = "davinci-mcbsp",
+ .id = -1,
.num_resources = ARRAY_SIZE(dm365_asp_resources),
.resource = dm365_asp_resources,
};
CLK("davinci_emac.1", NULL, &emac_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
CLK("palm_bk3710", NULL, &ide_clk),
- CLK("davinci-asp", NULL, &asp_clk),
+ CLK("davinci-mcbsp", NULL, &asp_clk),
CLK("davinci_mmc.0", NULL, &mmcsd_clk),
CLK(NULL, "spi", &spi_clk),
CLK(NULL, "gpio", &gpio_clk),
};
static struct platform_device dm644x_asp_device = {
- .name = "davinci-asp",
+ .name = "davinci-mcbsp",
.id = -1,
.num_resources = ARRAY_SIZE(dm644x_asp_resources),
.resource = dm644x_asp_resources,
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#define VMALLOC_END 0xdf000000
+#define VMALLOC_END 0xdf000000UL
*/
-#define VMALLOC_END 0xf0000000
+#define VMALLOC_END 0xf0000000UL
#ifndef __ARCH_ARM_VMALLOC_H
#define __ARCH_ARM_VMALLOC_H
-#define VMALLOC_END 0xd0000000
+#define VMALLOC_END 0xd0000000UL
#endif
.flags = IMXUART_HAVE_RTSCTS,
};
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) \
- || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-
#define ADS7846_PENDOWN (GPIO_PORTD | 25)
static void ads7846_dev_init(void)
.get_pendown_state = ads7846_get_pendown_state,
.keep_vref_on = 1,
};
-#endif
-#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
static struct spi_board_info eukrea_mbimx27_spi_board_info[] __initdata = {
[0] = {
.modalias = "ads7846",
.chipselect = eukrea_mbimx27_spi_cs,
.num_chipselect = ARRAY_SIZE(eukrea_mbimx27_spi_cs),
};
-#endif
static struct i2c_board_info eukrea_mbimx27_i2c_devices[] = {
{
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define VMALLOC_END 0xd0000000
+#define VMALLOC_END 0xd0000000UL
static APBC_CLK(twsi4, MMP2_TWSI4, 0, 26000000);
static APBC_CLK(twsi5, MMP2_TWSI5, 0, 26000000);
static APBC_CLK(twsi6, MMP2_TWSI6, 0, 26000000);
-static APBC_CLK(rtc, MMP2_RTC, 0, 32768);
static APMU_CLK(nand, NAND, 0xbf, 100000000);
#ifndef __ASM_ARCH_MSM_VMALLOC_H
#define __ASM_ARCH_MSM_VMALLOC_H
-#define VMALLOC_END 0xd0000000
+#define VMALLOC_END 0xd0000000UL
#endif
#define imx25_add_mxc_nand(pdata) \
imx_add_mxc_nand(&imx25_mxc_nand_data, pdata)
-extern const struct imx_spi_imx_data imx25_spi_imx_data[] __initconst;
+extern const struct imx_spi_imx_data imx25_cspi_data[] __initconst;
#define imx25_add_spi_imx(id, pdata) \
- imx_add_spi_imx(&imx25_spi_imx_data[id], pdata)
+ imx_add_spi_imx(&imx25_cspi_data[id], pdata)
#define imx25_add_spi_imx0(pdata) imx25_add_spi_imx(0, pdata)
#define imx25_add_spi_imx1(pdata) imx25_add_spi_imx(1, pdata)
#define imx25_add_spi_imx2(pdata) imx25_add_spi_imx(2, pdata)
#include <mach/common.h>
#include <mach/iomux-mx3.h>
+#include <mach/spi.h>
#include <asm/mach-types.h>
};
/* Platform Data for MXC CSPI */
-#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
static int pcm037_spi1_cs[] = {MXC_SPI_CS(1), IOMUX_TO_GPIO(MX31_PIN_KEY_COL7)};
static const struct spi_imx_master pcm037_spi1_pdata __initconst = {
.chipselect = pcm037_spi1_cs,
.num_chipselect = ARRAY_SIZE(pcm037_spi1_cs),
};
-#endif
/* GPIO-keys input device */
static struct gpio_keys_button pcm037_gpio_keys[] = {
},
};
-static int eet_init_devices(void)
+static int __init eet_init_devices(void)
{
if (!machine_is_pcm037() || pcm037_variant() != PCM037_EET)
return 0;
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define VMALLOC_END 0xd0000000
+#define VMALLOC_END 0xd0000000UL
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define VMALLOC_END 0xd8000000
+#define VMALLOC_END 0xd8000000UL
{
.name = "wl1271",
.mmc = 3,
- .caps = MMC_CAP_4_BIT_DATA,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
.gpio_wp = -EINVAL,
.gpio_cd = -EINVAL,
.nonremovable = true,
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define VMALLOC_END 0xf8000000
+#define VMALLOC_END 0xf8000000UL
return 0;
dpll3_m2_ck = clk_get(NULL, "dpll3_m2_ck");
- if (!dpll3_m2_ck)
+ if (IS_ERR(dpll3_m2_ck))
return -EINVAL;
rate = clk_get_rate(dpll3_m2_ck);
printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val);
}
+void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds)
+{
+ u32 tick_rate, cycles;
+
+ if (!seconds && !milliseconds)
+ return;
+
+ tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup));
+ cycles = tick_rate * seconds + tick_rate * milliseconds / 1000;
+ omap_dm_timer_stop(gptimer_wakeup);
+ omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles);
+
+ pr_info("PM: Resume timer in %u.%03u secs"
+ " (%d ticks at %d ticks/sec.)\n",
+ seconds, milliseconds, cycles, tick_rate);
+}
+
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>
pwrdm->timer = t;
}
-void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds)
-{
- u32 tick_rate, cycles;
-
- if (!seconds && !milliseconds)
- return;
-
- tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup));
- cycles = tick_rate * seconds + tick_rate * milliseconds / 1000;
- omap_dm_timer_stop(gptimer_wakeup);
- omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles);
-
- pr_info("PM: Resume timer in %u.%03u secs"
- " (%d ticks at %d ticks/sec.)\n",
- seconds, milliseconds, cycles, tick_rate);
-}
-
static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
{
struct seq_file *s = (struct seq_file *)user;
#include <linux/irq.h>
#include <linux/time.h>
#include <linux/gpio.h>
+#include <linux/console.h>
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
#include <plat/powerdomain.h>
#include <plat/clockdomain.h>
+#ifdef CONFIG_SUSPEND
+static suspend_state_t suspend_state = PM_SUSPEND_ON;
+static inline bool is_suspending(void)
+{
+ return (suspend_state != PM_SUSPEND_ON);
+}
+#else
+static inline bool is_suspending(void)
+{
+ return false;
+}
+#endif
+
static void (*omap2_sram_idle)(void);
static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
void __iomem *sdrc_power);
if (omap_irq_pending())
goto no_sleep;
+ /* Block console output in case it is on one of the OMAP UARTs */
+ if (!is_suspending())
+ if (try_acquire_console_sem())
+ goto no_sleep;
+
omap_uart_prepare_idle(0);
omap_uart_prepare_idle(1);
omap_uart_prepare_idle(2);
omap_uart_resume_idle(1);
omap_uart_resume_idle(0);
+ if (!is_suspending())
+ release_console_sem();
+
no_sleep:
if (omap2_pm_debug) {
unsigned long long tmp;
local_irq_enable();
}
+static int omap2_pm_begin(suspend_state_t state)
+{
+ suspend_state = state;
+ return 0;
+}
+
static int omap2_pm_prepare(void)
{
/* We cannot sleep in idle until we have resumed */
enable_hlt();
}
+static void omap2_pm_end(void)
+{
+ suspend_state = PM_SUSPEND_ON;
+}
+
static struct platform_suspend_ops omap_pm_ops = {
+ .begin = omap2_pm_begin,
.prepare = omap2_pm_prepare,
.enter = omap2_pm_enter,
.finish = omap2_pm_finish,
+ .end = omap2_pm_end,
.valid = suspend_valid_only_mem,
};
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/console.h>
#include <plat/sram.h>
#include <plat/clockdomain.h>
#include "sdrc.h"
#include "control.h"
+#ifdef CONFIG_SUSPEND
+static suspend_state_t suspend_state = PM_SUSPEND_ON;
+static inline bool is_suspending(void)
+{
+ return (suspend_state != PM_SUSPEND_ON);
+}
+#else
+static inline bool is_suspending(void)
+{
+ return false;
+}
+#endif
+
/* Scratchpad offsets */
#define OMAP343X_TABLE_ADDRESS_OFFSET 0xc4
#define OMAP343X_TABLE_VALUE_OFFSET 0xc0
omap3_enable_io_chain();
}
+ /* Block console output in case it is on one of the OMAP UARTs */
+ if (!is_suspending())
+ if (per_next_state < PWRDM_POWER_ON ||
+ core_next_state < PWRDM_POWER_ON)
+ if (try_acquire_console_sem())
+ goto console_still_active;
+
/* PER */
if (per_next_state < PWRDM_POWER_ON) {
omap_uart_prepare_idle(2);
omap_uart_resume_idle(3);
}
+ if (!is_suspending())
+ release_console_sem();
+
+console_still_active:
/* Disable IO-PAD and IO-CHAIN wakeup */
if (omap3_has_io_wakeup() &&
(per_next_state < PWRDM_POWER_ON ||
}
#ifdef CONFIG_SUSPEND
-static suspend_state_t suspend_state;
-
static int omap3_pm_prepare(void)
{
disable_hlt();
#define OMAP24XX_EN_GPT1_MASK (1 << 0)
/* PM_WKST_WKUP, CM_IDLEST_WKUP shared bits */
-#define OMAP24XX_ST_GPIOS_SHIFT (1 << 2)
-#define OMAP24XX_ST_GPIOS_MASK 2
-#define OMAP24XX_ST_GPT1_SHIFT (1 << 0)
-#define OMAP24XX_ST_GPT1_MASK 0
+#define OMAP24XX_ST_GPIOS_SHIFT 2
+#define OMAP24XX_ST_GPIOS_MASK (1 << 2)
+#define OMAP24XX_ST_GPT1_SHIFT 0
+#define OMAP24XX_ST_GPT1_MASK (1 << 0)
/* CM_IDLEST_MDM and PM_WKST_MDM shared bits */
-#define OMAP2430_ST_MDM_SHIFT (1 << 0)
+#define OMAP2430_ST_MDM_SHIFT 0
+#define OMAP2430_ST_MDM_MASK (1 << 0)
/* 3430 register bits shared between CM & PRM registers */
#include <linux/slab.h>
#include <linux/serial_8250.h>
#include <linux/pm_runtime.h>
+#include <linux/console.h>
#ifdef CONFIG_SERIAL_OMAP
#include <plat/omap-serial.h>
struct omap_uart_state *uart;
list_for_each_entry(uart, &uart_list, node) {
- if (num == uart->num) {
+ if (num == uart->num && uart->can_sleep) {
omap_uart_enable_clocks(uart);
/* Check for IO pad wakeup */
oh->dev_attr = uart;
+ acquire_console_sem(); /* in case the earlycon is on the UART */
+
/*
* Because of early UART probing, UART did not get idled
* on init. Now that omap_device is ready, ensure full idle
omap_uart_block_sleep(uart);
uart->timeout = DEFAULT_TIMEOUT;
+ release_console_sem();
+
if ((cpu_is_omap34xx() && uart->padconf) ||
(uart->wk_en && uart->wk_mask)) {
device_init_wakeup(&od->pdev.dev, true);
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
* area for the same reason. ;)
*/
-#define VMALLOC_END 0xd0000000
+#define VMALLOC_END 0xd0000000UL
/******************************************************************************
* NAND Flash
******************************************************************************/
-#if defined(CONFIG_MTD_NAND_GPIO) || defined(CONFIG_MTD_NAND_GPIO_MODULE)
+#if defined(CONFIG_MTD_NAND_PLATFORM) || \
+ defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
static void palmtx_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
*/
b secondary_startup
+ .align
1: .long .
.long pen_release
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#define VMALLOC_END 0xdc000000
+#define VMALLOC_END 0xdc000000UL
/* Configures BT serial port GPIOs */
s3c_gpio_cfgpin(S3C2410_GPH(0), S3C2410_GPH0_nCTS0);
- s3c_gpio_cfgpull(S3C2410_GPH(0), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPH(0), S3C_GPIO_PULL_NONE);
s3c_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT);
- s3c_gpio_cfgpull(S3C2410_GPH(1), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPH(1), S3C_GPIO_PULL_NONE);
s3c_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0);
- s3c_gpio_cfgpull(S3C2410_GPH(2), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPH(2), S3C_GPIO_PULL_NONE);
s3c_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0);
- s3c_gpio_cfgpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE);
rfk = rfkill_alloc(DRV_NAME, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
config CPU_S3C2412_ONLY
bool
depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \
- !CPU_2416 && !CPU_S3C2440 && !CPU_S3C2442 && \
+ !CPU_S3C2416 && !CPU_S3C2440 && !CPU_S3C2442 && \
!CPU_S3C2443 && CPU_S3C2412
default y if CPU_S3C2412
config MACH_SMDK2416
bool "SMDK2416"
select CPU_S3C2416
+ select MACH_SMDK
select S3C_DEV_FB
select S3C_DEV_HSMMC
select S3C_DEV_HSMMC1
+ select S3C_DEV_NAND
+ select S3C_DEV_USB_HOST
select S3C2416_PM if PM
help
Say Y here if you are using an SMDK2416
static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
{
- s3c2416_irq_demux(IRQ_S3C2443_UART3, 3);
+ s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
}
#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
+#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
static void s3c2416_irq_uart3_mask(unsigned int irqno)
{
config CPU_S3C2442
bool
select CPU_ARM920T
+ select S3C_GPIO_PULL_DOWN
select S3C2410_CLOCK
select S3C2410_GPIO
select S3C2410_PM if PM
bool "MINI2440 development board"
select CPU_S3C2440
select EEPROM_AT24
+ select NEW_LEDS
+ select LEDS_CLASS
+ select LEDS_TRIGGER
select LEDS_TRIGGER_BACKLIGHT
select S3C_DEV_NAND
select S3C_DEV_USB_HOST
{
printk("S3C2440: Initialising architecture\n");
- s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1up;
- s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1up;
-
/* change irq for watchdog */
s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
return sysdev_register(&s3c2440_sysdev);
}
+
+void __init s3c2440_map_io(void)
+{
+ s3c244x_map_io();
+
+ s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1up;
+ s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1up;
+}
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/mutex.h>
+#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <plat/clock.h>
#include <plat/cpu.h>
+#include <plat/s3c244x.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
/* S3C2442 extended clock support */
return sysdev_register(&s3c2442_sysdev);
}
+
+void __init s3c2442_map_io(void)
+{
+ s3c244x_map_io();
+
+ s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1down;
+ s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1down;
+}
config CPU_S3C2443
bool
depends on ARCH_S3C2410
+ select CPU_ARM920T
select S3C2443_DMA if S3C2410_DMA
select CPU_LLSERIAL_S3C2440
select SAMSUNG_CLKSRC
static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
{
- s3c2443_irq_demux(IRQ_S3C2443_UART3, 3);
+ s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
}
#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
+#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
static void s3c2443_irq_uart3_mask(unsigned int irqno)
{
#include <video/platform_lcd.h>
-#define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK)
+#define UCON S3C2410_UCON_DEFAULT
#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
#include <video/platform_lcd.h>
-#define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK)
+#define UCON S3C2410_UCON_DEFAULT
#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/i2c.h>
+#include <linux/sysdev.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/serial_core.h>
+#include <linux/sysdev.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
/*
* arch/arm/mach-shark/include/mach/vmalloc.h
*/
-#define VMALLOC_END 0xd0000000
+#define VMALLOC_END 0xd0000000UL
/* FSI */
#define IRQ_FSI evt2irq(0x1840)
+static int __fsi_set_rate(struct clk *clk, long rate, int enable)
+{
+ int ret = 0;
+
+ if (rate <= 0)
+ return ret;
+
+ if (enable) {
+ ret = clk_set_rate(clk, rate);
+ if (0 == ret)
+ ret = clk_enable(clk);
+ } else {
+ clk_disable(clk);
+ }
+
+ return ret;
+}
+
+static int __fsi_set_round_rate(struct clk *clk, long rate, int enable)
+{
+ return __fsi_set_rate(clk, clk_round_rate(clk, rate), enable);
+}
-static int fsi_set_rate(int is_porta, int rate)
+static int fsi_ak4642_set_rate(struct device *dev, int rate, int enable)
+{
+ struct clk *fsia_ick;
+ struct clk *fsiack;
+ int ret = -EIO;
+
+ fsia_ick = clk_get(dev, "icka");
+ if (IS_ERR(fsia_ick))
+ return PTR_ERR(fsia_ick);
+
+ /*
+ * FSIACK is connected to AK4642,
+ * and use external clock pin from it.
+ * it is parent of fsia_ick now.
+ */
+ fsiack = clk_get_parent(fsia_ick);
+ if (!fsiack)
+ goto fsia_ick_out;
+
+ /*
+ * we get 1/1 divided clock by setting same rate to fsiack and fsia_ick
+ *
+ ** FIXME **
+ * Because the freq_table of external clk (fsiack) are all 0,
+ * the return value of clk_round_rate became 0.
+ * So, it use __fsi_set_rate here.
+ */
+ ret = __fsi_set_rate(fsiack, rate, enable);
+ if (ret < 0)
+ goto fsiack_out;
+
+ ret = __fsi_set_round_rate(fsia_ick, rate, enable);
+ if ((ret < 0) && enable)
+ __fsi_set_round_rate(fsiack, rate, 0); /* disable FSI ACK */
+
+fsiack_out:
+ clk_put(fsiack);
+
+fsia_ick_out:
+ clk_put(fsia_ick);
+
+ return 0;
+}
+
+static int fsi_hdmi_set_rate(struct device *dev, int rate, int enable)
{
struct clk *fsib_clk;
struct clk *fdiv_clk = &sh7372_fsidivb_clk;
+ long fsib_rate = 0;
+ long fdiv_rate = 0;
+ int ackmd_bpfmd;
int ret;
- /* set_rate is not needed if port A */
- if (is_porta)
- return 0;
-
- fsib_clk = clk_get(NULL, "fsib_clk");
- if (IS_ERR(fsib_clk))
- return -EINVAL;
-
switch (rate) {
case 44100:
- clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 11283000));
- ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
+ fsib_rate = rate * 256;
+ ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
break;
case 48000:
- clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 85428000));
- clk_set_rate(fdiv_clk, clk_round_rate(fdiv_clk, 12204000));
- ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
+ fsib_rate = 85428000; /* around 48kHz x 256 x 7 */
+ fdiv_rate = rate * 256;
+ ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
break;
default:
pr_err("unsupported rate in FSI2 port B\n");
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
+ /* FSI B setting */
+ fsib_clk = clk_get(dev, "ickb");
+ if (IS_ERR(fsib_clk))
+ return -EIO;
+
+ ret = __fsi_set_round_rate(fsib_clk, fsib_rate, enable);
clk_put(fsib_clk);
+ if (ret < 0)
+ return ret;
+
+ /* FSI DIV setting */
+ ret = __fsi_set_round_rate(fdiv_clk, fdiv_rate, enable);
+ if (ret < 0) {
+ /* disable FSI B */
+ if (enable)
+ __fsi_set_round_rate(fsib_clk, fsib_rate, 0);
+ return ret;
+ }
+
+ return ackmd_bpfmd;
+}
+
+static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable)
+{
+ int ret;
+
+ if (is_porta)
+ ret = fsi_ak4642_set_rate(dev, rate, enable);
+ else
+ ret = fsi_hdmi_set_rate(dev, rate, enable);
return ret;
}
goto out;
}
+ ret = clk_enable(&sh7372_pllc2_clk);
+ if (ret < 0) {
+ pr_err("Cannot enable pllc2 clock\n");
+ goto out;
+ }
pr_debug("PLLC2 set frequency %lu\n", rate);
ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk);
device_initcall(hdmi_init_pm_clock);
-#define FSIACK_DUMMY_RATE 48000
static int __init fsi_init_pm_clock(void)
{
struct clk *fsia_ick;
int ret;
- /*
- * FSIACK is connected to AK4642,
- * and the rate is depend on playing sound rate.
- * So, set dummy rate (= 48k) here
- */
- ret = clk_set_rate(&sh7372_fsiack_clk, FSIACK_DUMMY_RATE);
- if (ret < 0) {
- pr_err("Cannot set FSIACK dummy rate: %d\n", ret);
- return ret;
- }
-
fsia_ick = clk_get(&fsi_device.dev, "icka");
if (IS_ERR(fsia_ick)) {
ret = PTR_ERR(fsia_ick);
}
ret = clk_set_parent(fsia_ick, &sh7372_fsiack_clk);
- if (ret < 0) {
- pr_err("Cannot set FSI-A parent: %d\n", ret);
- goto out;
- }
-
- ret = clk_set_rate(fsia_ick, FSIACK_DUMMY_RATE);
if (ret < 0)
- pr_err("Cannot set FSI-A rate: %d\n", ret);
+ pr_err("Cannot set FSI-A parent: %d\n", ret);
-out:
clk_put(fsia_ick);
return ret;
__raw_writel(__raw_readl(PLLC2CR) & ~0x80000000, PLLC2CR);
}
-static int pllc2_set_rate(struct clk *clk,
- unsigned long rate, int algo_id)
+static int pllc2_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long value;
int idx;
if (idx < 0)
return idx;
- if (rate == clk->parent->rate) {
- pllc2_disable(clk);
- return 0;
- }
+ if (rate == clk->parent->rate)
+ return -EINVAL;
value = __raw_readl(PLLC2CR) & ~(0x3f << 24);
- if (value & 0x80000000)
- pllc2_disable(clk);
-
__raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR);
- if (value & 0x80000000)
- return pllc2_enable(clk);
-
return 0;
}
unsigned long value;
value = __raw_readl(clk->mapping->base) >> 16;
- if (value < 2) {
- fsidiv_disable(clk);
- return -ENOENT;
- }
+ if (value < 2)
+ return -EIO;
__raw_writel((value << 16) | 0x3, clk->mapping->base);
return 0;
}
-static int fsidiv_set_rate(struct clk *clk,
- unsigned long rate, int algo_id)
+static int fsidiv_set_rate(struct clk *clk, unsigned long rate)
{
int idx;
- if (clk->parent->rate == rate) {
- fsidiv_disable(clk);
- return 0;
- }
-
idx = (clk->parent->rate / rate) & 0xffff;
if (idx < 2)
- return -ENOENT;
+ return -EINVAL;
__raw_writel(idx << 16, clk->mapping->base);
- return fsidiv_enable(clk);
+ return 0;
}
static struct clk_ops fsidiv_clk_ops = {
CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]),
CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]),
- CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FSIA]),
- CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FSIB]),
CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
- CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */
- CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP323]), /* USB0 */
+ CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
+ CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
#include <mach/io.h>
.macro addruart, rp, rv
- ldreq \rp, =IO_APB_PHYS @ physical
- ldrne \rv, =IO_APB_VIRT @ virtual
+ ldr \rp, =IO_APB_PHYS @ physical
+ ldr \rv, =IO_APB_VIRT @ virtual
#if defined(CONFIG_TEGRA_DEBUG_UART_NONE)
#error "A debug UART must be selected in the kernel config to use DEBUG_LL"
#elif defined(CONFIG_TEGRA_DEBUG_UARTA)
static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask)
{
/* wait for the operation to complete */
- while (readl(reg) & mask)
+ while (readl_relaxed(reg) & mask)
;
}
static inline void ux500_cache_sync(void)
{
void __iomem *base = __io_address(UX500_L2CC_BASE);
- writel(0, base + L2X0_CACHE_SYNC);
+ writel_relaxed(0, base + L2X0_CACHE_SYNC);
ux500_cache_wait(base + L2X0_CACHE_SYNC, 1);
}
uint32_t l2x0_way_mask = (1<<16) - 1; /* Bitmask of active ways */
/* invalidate all ways */
- writel(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
+ writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
ux500_cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
ux500_cache_sync();
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define VMALLOC_END 0xd8000000
+#define VMALLOC_END 0xd8000000UL
*/
b secondary_startup
+ .align
1: .long .
.long pen_release
* - end - virtual end address of region
*/
v6_dma_inv_range:
+#ifdef CONFIG_DMA_CACHE_RWFO
+ ldrb r2, [r0] @ read for ownership
+ strb r2, [r0] @ write for ownership
+#endif
tst r0, #D_CACHE_LINE_SIZE - 1
bic r0, r0, #D_CACHE_LINE_SIZE - 1
#ifdef HARVARD_CACHE
mcrne p15, 0, r0, c7, c11, 1 @ clean unified line
#endif
tst r1, #D_CACHE_LINE_SIZE - 1
+#ifdef CONFIG_DMA_CACHE_RWFO
+ ldrneb r2, [r1, #-1] @ read for ownership
+ strneb r2, [r1, #-1] @ write for ownership
+#endif
bic r1, r1, #D_CACHE_LINE_SIZE - 1
#ifdef HARVARD_CACHE
mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D line
mcrne p15, 0, r1, c7, c15, 1 @ clean & invalidate unified line
#endif
1:
-#ifdef CONFIG_DMA_CACHE_RWFO
- ldr r2, [r0] @ read for ownership
- str r2, [r0] @ write for ownership
-#endif
#ifdef HARVARD_CACHE
mcr p15, 0, r0, c7, c6, 1 @ invalidate D line
#else
#endif
add r0, r0, #D_CACHE_LINE_SIZE
cmp r0, r1
+#ifdef CONFIG_DMA_CACHE_RWFO
+ ldrlo r2, [r0] @ read for ownership
+ strlo r2, [r0] @ write for ownership
+#endif
blo 1b
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
* - end - virtual end address of region
*/
ENTRY(v6_dma_flush_range)
- bic r0, r0, #D_CACHE_LINE_SIZE - 1
-1:
#ifdef CONFIG_DMA_CACHE_RWFO
- ldr r2, [r0] @ read for ownership
- str r2, [r0] @ write for ownership
+ ldrb r2, [r0] @ read for ownership
+ strb r2, [r0] @ write for ownership
#endif
+ bic r0, r0, #D_CACHE_LINE_SIZE - 1
+1:
#ifdef HARVARD_CACHE
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line
#else
#endif
add r0, r0, #D_CACHE_LINE_SIZE
cmp r0, r1
+#ifdef CONFIG_DMA_CACHE_RWFO
+ ldrlob r2, [r0] @ read for ownership
+ strlob r2, [r0] @ write for ownership
+#endif
blo 1b
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
UNWIND(.fnstart )
dcache_line_size r2, r3
sub r3, r2, #1
- bic r0, r0, r3
+ bic r12, r0, r3
1:
- USER( mcr p15, 0, r0, c7, c11, 1 ) @ clean D line to the point of unification
+ USER( mcr p15, 0, r12, c7, c11, 1 ) @ clean D line to the point of unification
+ add r12, r12, r2
+ cmp r12, r1
+ blo 1b
dsb
- USER( mcr p15, 0, r0, c7, c5, 1 ) @ invalidate I line
- add r0, r0, r2
+ icache_line_size r2, r3
+ sub r3, r2, #1
+ bic r12, r0, r3
2:
- cmp r0, r1
- blo 1b
+ USER( mcr p15, 0, r12, c7, c5, 1 ) @ invalidate I line
+ add r12, r12, r2
+ cmp r12, r1
+ blo 2b
+3:
mov r0, #0
ALT_SMP(mcr p15, 0, r0, c7, c1, 6) @ invalidate BTB Inner Shareable
ALT_UP(mcr p15, 0, r0, c7, c5, 6) @ invalidate BTB
* isn't mapped, just try the next page.
*/
9001:
- mov r0, r0, lsr #12
- mov r0, r0, lsl #12
- add r0, r0, #4096
- b 2b
+ mov r12, r12, lsr #12
+ mov r12, r12, lsl #12
+ add r12, r12, #4096
+ b 3b
UNWIND(.fnend )
ENDPROC(v7_coherent_kern_range)
ENDPROC(v7_coherent_user_range)
*/
if (pfn_valid(pfn)) {
printk(KERN_WARNING "BUG: Your driver calls ioremap() on system memory. This leads\n"
- KERN_WARNING "to architecturally unpredictable behaviour on ARMv6+, and ioremap()\n"
- KERN_WARNING "will fail in the next kernel release. Please fix your driver.\n");
+ "to architecturally unpredictable behaviour on ARMv6+, and ioremap()\n"
+ "will fail in the next kernel release. Please fix your driver.\n");
WARN_ON(1);
}
.endm
/*
- * cache_line_size - get the cache line size from the CSIDR register
- * (available on ARMv7+). It assumes that the CSSR register was configured
- * to access the L1 data cache CSIDR.
+ * dcache_line_size - get the minimum D-cache line size from the CTR register
+ * on ARMv7.
*/
.macro dcache_line_size, reg, tmp
- mrc p15, 1, \tmp, c0, c0, 0 @ read CSIDR
- and \tmp, \tmp, #7 @ cache line size encoding
- mov \reg, #16 @ size offset
+ mrc p15, 0, \tmp, c0, c0, 1 @ read ctr
+ lsr \tmp, \tmp, #16
+ and \tmp, \tmp, #0xf @ cache line size encoding
+ mov \reg, #4 @ bytes per word
mov \reg, \reg, lsl \tmp @ actual cache line size
.endm
+/*
+ * icache_line_size - get the minimum I-cache line size from the CTR register
+ * on ARMv7.
+ */
+ .macro icache_line_size, reg, tmp
+ mrc p15, 0, \tmp, c0, c0, 1 @ read ctr
+ and \tmp, \tmp, #0xf @ cache line size encoding
+ mov \reg, #4 @ bytes per word
+ mov \reg, \reg, lsl \tmp @ actual cache line size
+ .endm
/*
* Sanity check the PTE configuration for the code below - which makes
PMD_SECT_XN | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
- b __v7_ca9mp_setup
+ W(b) __v7_ca9mp_setup
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
PMD_SECT_XN | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
- b __v7_setup
+ W(b) __v7_setup
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
#include <linux/time.h>
#include <linux/init.h>
#include <linux/timex.h>
+#include <linux/sched.h>
#include <linux/io.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
/*
* IOP clocksource (free-running timer 1).
*/
-static cycle_t iop_clocksource_read(struct clocksource *unused)
+static cycle_t notrace iop_clocksource_read(struct clocksource *unused)
{
return 0xffffffffu - read_tcr1();
}
#include <mach/hardware.h>
#include <mach/devices-common.h>
-#ifdef SDMA_IS_MERGED
#include <mach/sdma.h>
-#else
-struct sdma_platform_data {
- int sdma_version;
- char *cpu_name;
- int to_version;
-};
-#endif
struct imx_imx_sdma_data {
resource_size_t iobase;
imx_spi_imx_data_entry(MX21, CSPI, "imx21-cspi", _id, _hwid, SZ_4K)
imx21_cspi_data_entry(0, 1),
imx21_cspi_data_entry(1, 2),
+};
#endif
#ifdef CONFIG_ARCH_MX25
*
* Copyright (C) 2008 STMicroelectronics
* Copyright (C) 2010 Alessandro Rubini
+ * Copyright (C) 2010 Linus Walleij for ST-Ericsson
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
#include <linux/clk.h>
#include <linux/jiffies.h>
#include <linux/err.h>
+#include <linux/cnt32_to_63.h>
+#include <linux/timer.h>
#include <asm/mach/time.h>
#include <plat/mtu.h>
-void __iomem *mtu_base; /* ssigned by machine code */
+void __iomem *mtu_base; /* Assigned by machine code */
/*
* Kernel assumes that sched_clock can be called early
/*
* Override the global weak sched_clock symbol with this
* local implementation which uses the clocksource to get some
- * better resolution when scheduling the kernel. We accept that
- * this wraps around for now, since it is just a relative time
- * stamp. (Inspired by OMAP implementation.)
+ * better resolution when scheduling the kernel.
+ *
+ * Because the hardware timer period may be quite short
+ * (32.3 secs on the 133 MHz MTU timer selection on ux500)
+ * and because cnt32_to_63() needs to be called at least once per
+ * half period to work properly, a kernel keepwarm() timer is set up
+ * to ensure this requirement is always met.
+ *
+ * Also the sched_clock timer will wrap around at some point,
+ * here we set it to run continously for a year.
*/
+#define SCHED_CLOCK_MIN_WRAP 3600*24*365
+static struct timer_list cnt32_to_63_keepwarm_timer;
+static u32 sched_mult;
+static u32 sched_shift;
+
unsigned long long notrace sched_clock(void)
{
- return clocksource_cyc2ns(nmdk_clksrc.read(
- &nmdk_clksrc),
- nmdk_clksrc.mult,
- nmdk_clksrc.shift);
+ u64 cycles;
+
+ if (unlikely(!mtu_base))
+ return 0;
+
+ cycles = cnt32_to_63(-readl(mtu_base + MTU_VAL(0)));
+ /*
+ * sched_mult is guaranteed to be even so will
+ * shift out bit 63
+ */
+ return (cycles * sched_mult) >> sched_shift;
+}
+
+/* Just kick sched_clock every so often */
+static void cnt32_to_63_keepwarm(unsigned long data)
+{
+ mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data));
+ (void) sched_clock();
+}
+
+/*
+ * Set up a timer to keep sched_clock():s 32_to_63 algorithm warm
+ * once in half a 32bit timer wrap interval.
+ */
+static void __init nmdk_sched_clock_init(unsigned long rate)
+{
+ u32 v;
+ unsigned long delta;
+ u64 days;
+
+ /* Find the apropriate mult and shift factors */
+ clocks_calc_mult_shift(&sched_mult, &sched_shift,
+ rate, NSEC_PER_SEC, SCHED_CLOCK_MIN_WRAP);
+ /* We need to multiply by an even number to get rid of bit 63 */
+ if (sched_mult & 1)
+ sched_mult++;
+
+ /* Let's see what we get, take max counter and scale it */
+ days = (0xFFFFFFFFFFFFFFFFLLU * sched_mult) >> sched_shift;
+ do_div(days, NSEC_PER_SEC);
+ do_div(days, (3600*24));
+
+ pr_info("sched_clock: using %d bits @ %lu Hz wrap in %lu days\n",
+ (64 - sched_shift), rate, (unsigned long) days);
+
+ /*
+ * Program a timer to kick us at half 32bit wraparound
+ * Formula: seconds per wrap = (2^32) / f
+ */
+ v = 0xFFFFFFFFUL / rate;
+ /* We want half of the wrap time to keep cnt32_to_63 warm */
+ v /= 2;
+ pr_debug("sched_clock: prescaled timer rate: %lu Hz, "
+ "initialize keepwarm timer every %d seconds\n", rate, v);
+ /* Convert seconds to jiffies */
+ delta = msecs_to_jiffies(v*1000);
+ setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, delta);
+ mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + delta));
}
/* Clockevent device: use one-shot mode */
writel(0, mtu_base + MTU_BGLR(0));
writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
- /* Now the scheduling clock is ready */
+ /* Now the clock source is ready */
nmdk_clksrc.read = nmdk_read_timer;
if (clocksource_register(&nmdk_clksrc))
pr_err("timer: failed to initialize clock source %s\n",
nmdk_clksrc.name);
+ nmdk_sched_clock_init(rate);
+
/* Timer 1 is used for events */
clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE);
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/err.h>
#include <plat/common.h>
#include <plat/board.h>
return -ENODEV;
sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
- if (sync_32k_ick)
+ if (!IS_ERR(sync_32k_ick))
clk_enable(sync_32k_ick);
clocksource_32k.mult = clocksource_hz2mult(32768,
cpu_is_omap1710())
omap_sram_size = 0x4000; /* 16K */
else if (cpu_is_omap1611())
- omap_sram_size = 0x3e800; /* 250K */
+ omap_sram_size = SZ_256K;
else {
printk(KERN_ERR "Could not detect SRAM size\n");
omap_sram_size = 0x4000;
/* Require clock free running */
#define PXA_FLAG_DISABLE_CLOCK_GATING (1<<0)
+/* Board design supports 8-bit data on SD/SDIO BUS */
+#define PXA_FLAG_SD_8_BIT_CAPABLE_SLOT (1<<2)
+
/*
* struct pxa_sdhci_platdata() - Platform device data for PXA SDHCI
* @max_speed: the maximum speed supported
{
.idcode = 0x32440000,
.idmask = 0xffffffff,
- .map_io = s3c244x_map_io,
+ .map_io = s3c2440_map_io,
.init_clocks = s3c244x_init_clocks,
.init_uarts = s3c244x_init_uarts,
.init = s3c2440_init,
{
.idcode = 0x32440001,
.idmask = 0xffffffff,
- .map_io = s3c244x_map_io,
+ .map_io = s3c2440_map_io,
.init_clocks = s3c244x_init_clocks,
.init_uarts = s3c244x_init_uarts,
.init = s3c2440_init,
{
.idcode = 0x32440aaa,
.idmask = 0xffffffff,
- .map_io = s3c244x_map_io,
+ .map_io = s3c2442_map_io,
.init_clocks = s3c244x_init_clocks,
.init_uarts = s3c244x_init_uarts,
.init = s3c2442_init,
{
.idcode = 0x32440aab,
.idmask = 0xffffffff,
- .map_io = s3c244x_map_io,
+ .map_io = s3c2442_map_io,
.init_clocks = s3c244x_init_clocks,
.init_uarts = s3c244x_init_uarts,
.init = s3c2442_init,
struct s3c_gpio_cfg s3c24xx_gpiocfg_default = {
.set_config = s3c_gpio_setcfg_s3c24xx,
.get_config = s3c_gpio_getcfg_s3c24xx,
- .set_pull = s3c_gpio_setpull_1up,
- .get_pull = s3c_gpio_getpull_1up,
};
struct s3c_gpio_chip s3c24xx_gpios[] = {
#else
#define s3c244x_init_clocks NULL
#define s3c244x_init_uarts NULL
-#define s3c244x_map_io NULL
#endif
#ifdef CONFIG_CPU_S3C2440
extern int s3c2440_init(void);
+
+extern void s3c2440_map_io(void);
#else
#define s3c2440_init NULL
+#define s3c2440_map_io NULL
#endif
#ifdef CONFIG_CPU_S3C2442
extern int s3c2442_init(void);
+
+extern void s3c2442_map_io(void);
#else
#define s3c2442_init NULL
+#define s3c2442_map_io NULL
#endif
} else {
s3c_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPIO_INPUT);
s3c_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPIO_INPUT);
- s3c_gpio_cfgpull(S3C2410_GPE(11), S3C_GPIO_PULL_NONE);
- s3c_gpio_cfgpull(S3C2410_GPE(12), S3C_GPIO_PULL_NONE);
- s3c_gpio_cfgpull(S3C2410_GPE(13), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPE(11), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPE(12), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPE(13), S3C_GPIO_PULL_NONE);
}
}
} else {
s3c_gpio_cfgpin(S3C2410_GPD(8), S3C2410_GPIO_INPUT);
s3c_gpio_cfgpin(S3C2410_GPD(9), S3C2410_GPIO_INPUT);
- s3c_gpio_cfgpull(S3C2410_GPD(10), S3C_GPIO_PULL_NONE);
- s3c_gpio_cfgpull(S3C2410_GPD(9), S3C_GPIO_PULL_NONE);
- s3c_gpio_cfgpull(S3C2410_GPD(8), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPD(10), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPD(9), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPD(8), S3C_GPIO_PULL_NONE);
}
}
} else {
s3c_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPIO_INPUT);
s3c_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPIO_INPUT);
- s3c_gpio_cfgpull(S3C2410_GPG(5), S3C_GPIO_PULL_NONE);
- s3c_gpio_cfgpull(S3C2410_GPG(6), S3C_GPIO_PULL_NONE);
- s3c_gpio_cfgpull(S3C2410_GPG(7), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPG(5), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPG(6), S3C_GPIO_PULL_NONE);
+ s3c_gpio_setpull(S3C2410_GPG(7), S3C_GPIO_PULL_NONE);
}
}
}
#endif
-#ifdef CONFIG_S3C_GPIO_PULL_UP
-int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip,
- unsigned int off, s3c_gpio_pull_t pull)
+#if defined(CONFIG_S3C_GPIO_PULL_UP) || defined(CONFIG_S3C_GPIO_PULL_DOWN)
+static int s3c_gpio_setpull_1(struct s3c_gpio_chip *chip,
+ unsigned int off, s3c_gpio_pull_t pull,
+ s3c_gpio_pull_t updown)
{
void __iomem *reg = chip->base + 0x08;
u32 pup = __raw_readl(reg);
- pup = __raw_readl(reg);
-
- if (pup == S3C_GPIO_PULL_UP)
+ if (pull == updown)
pup &= ~(1 << off);
- else if (pup == S3C_GPIO_PULL_NONE)
+ else if (pull == S3C_GPIO_PULL_NONE)
pup |= (1 << off);
else
return -EINVAL;
return 0;
}
-s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip,
- unsigned int off)
+static s3c_gpio_pull_t s3c_gpio_getpull_1(struct s3c_gpio_chip *chip,
+ unsigned int off, s3c_gpio_pull_t updown)
{
void __iomem *reg = chip->base + 0x08;
u32 pup = __raw_readl(reg);
pup &= (1 << off);
- return pup ? S3C_GPIO_PULL_NONE : S3C_GPIO_PULL_UP;
+ return pup ? S3C_GPIO_PULL_NONE : updown;
+}
+#endif /* CONFIG_S3C_GPIO_PULL_UP || CONFIG_S3C_GPIO_PULL_DOWN */
+
+#ifdef CONFIG_S3C_GPIO_PULL_UP
+s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip,
+ unsigned int off)
+{
+ return s3c_gpio_getpull_1(chip, off, S3C_GPIO_PULL_UP);
+}
+
+int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip,
+ unsigned int off, s3c_gpio_pull_t pull)
+{
+ return s3c_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_UP);
}
#endif /* CONFIG_S3C_GPIO_PULL_UP */
+#ifdef CONFIG_S3C_GPIO_PULL_DOWN
+s3c_gpio_pull_t s3c_gpio_getpull_1down(struct s3c_gpio_chip *chip,
+ unsigned int off)
+{
+ return s3c_gpio_getpull_1(chip, off, S3C_GPIO_PULL_DOWN);
+}
+
+int s3c_gpio_setpull_1down(struct s3c_gpio_chip *chip,
+ unsigned int off, s3c_gpio_pull_t pull)
+{
+ return s3c_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN);
+}
+#endif /* CONFIG_S3C_GPIO_PULL_DOWN */
+
#ifdef CONFIG_S5P_GPIO_DRVSTR
s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin)
{
extern s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip,
unsigned int off);
+/**
+ * s3c_gpio_getpull_1down() - Get configuration for choice of down or none
+ * @chip: The gpio chip that the GPIO pin belongs to
+ * @off: The offset to the pin to get the configuration of.
+ *
+ * This helper function reads the state of the pull-down resistor for the
+ * given GPIO in the same case as s3c_gpio_setpull_1down.
+*/
+extern s3c_gpio_pull_t s3c_gpio_getpull_1down(struct s3c_gpio_chip *chip,
+ unsigned int off);
+
/**
* s3c_gpio_setpull_s3c2443() - Pull configuration for s3c2443.
* @chip: The gpio chip that is being configured.
#
# http://www.arm.linux.org.uk/developer/machines/?action=new
#
-# Last update: Thu Sep 9 22:43:01 2010
+# Last update: Sun Dec 12 23:24:27 2010
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
u380 MACH_U380 U380 2333
oamp3_hualu MACH_HUALU_BOARD HUALU_BOARD 2334
npcmx50 MACH_NPCMX50 NPCMX50 2335
-mx51_lange51 MACH_MX51_LANGE51 MX51_LANGE51 2336
+mx51_efikamx MACH_MX51_EFIKAMX MX51_EFIKAMX 2336
mx51_lange52 MACH_MX51_LANGE52 MX51_LANGE52 2337
riom MACH_RIOM RIOM 2338
comcas MACH_COMCAS COMCAS 2339
csb732 MACH_CSB732 CSB732 2367
u8500 MACH_U8500 U8500 2368
huqiu MACH_HUQIU HUQIU 2369
-mx51_kunlun MACH_MX51_KUNLUN MX51_KUNLUN 2370
+mx51_efikasb MACH_MX51_EFIKASB MX51_EFIKASB 2370
pmt1g MACH_PMT1G PMT1G 2371
htcelf MACH_HTCELF HTCELF 2372
armadillo420 MACH_ARMADILLO420 ARMADILLO420 2373
wasabi MACH_WASABI WASABI 2986
vivow MACH_VIVOW VIVOW 2987
mx50_rdp MACH_MX50_RDP MX50_RDP 2988
-universal MACH_UNIVERSAL UNIVERSAL 2989
+universal_c210 MACH_UNIVERSAL_C210 UNIVERSAL_C210 2989
real6410 MACH_REAL6410 REAL6410 2990
spx_sakura MACH_SPX_SAKURA SPX_SAKURA 2991
ij3k_2440 MACH_IJ3K_2440 IJ3K_2440 2992
msm8x60_qrdc MACH_MSM8X60_QRDC MSM8X60_QRDC 3060
spear900 MACH_SPEAR900 SPEAR900 3061
pcontrol_g20 MACH_PCONTROL_G20 PCONTROL_G20 3062
+rdstor MACH_RDSTOR RDSTOR 3063
+usdloader MACH_USDLOADER USDLOADER 3064
+tsoploader MACH_TSOPLOADER TSOPLOADER 3065
+kronos MACH_KRONOS KRONOS 3066
+ffcore MACH_FFCORE FFCORE 3067
+mone MACH_MONE MONE 3068
+unit2s MACH_UNIT2S UNIT2S 3069
+acer_a5 MACH_ACER_A5 ACER_A5 3070
+etherpro_isp MACH_ETHERPRO_ISP ETHERPRO_ISP 3071
+stretchs7000 MACH_STRETCHS7000 STRETCHS7000 3072
+p87_smartsim MACH_P87_SMARTSIM P87_SMARTSIM 3073
+tulip MACH_TULIP TULIP 3074
+sunflower MACH_SUNFLOWER SUNFLOWER 3075
+rib MACH_RIB RIB 3076
+clod MACH_CLOD CLOD 3077
+rump MACH_RUMP RUMP 3078
+tenderloin MACH_TENDERLOIN TENDERLOIN 3079
+shortloin MACH_SHORTLOIN SHORTLOIN 3080
+crespo MACH_CRESPO CRESPO 3081
+antares MACH_ANTARES ANTARES 3082
+wb40n MACH_WB40N WB40N 3083
+herring MACH_HERRING HERRING 3084
+naxy400 MACH_NAXY400 NAXY400 3085
+naxy1200 MACH_NAXY1200 NAXY1200 3086
+vpr200 MACH_VPR200 VPR200 3087
+bug20 MACH_BUG20 BUG20 3088
+goflexnet MACH_GOFLEXNET GOFLEXNET 3089
+torbreck MACH_TORBRECK TORBRECK 3090
+saarb_mg1 MACH_SAARB_MG1 SAARB_MG1 3091
+callisto MACH_CALLISTO CALLISTO 3092
+multhsu MACH_MULTHSU MULTHSU 3093
+saluda MACH_SALUDA SALUDA 3094
+pemp_omap3_apollo MACH_PEMP_OMAP3_APOLLO PEMP_OMAP3_APOLLO 3095
+vc0718 MACH_VC0718 VC0718 3096
+mvblx MACH_MVBLX MVBLX 3097
+inhand_apeiron MACH_INHAND_APEIRON INHAND_APEIRON 3098
+inhand_fury MACH_INHAND_FURY INHAND_FURY 3099
+inhand_siren MACH_INHAND_SIREN INHAND_SIREN 3100
+hdnvp MACH_HDNVP HDNVP 3101
+softwinner MACH_SOFTWINNER SOFTWINNER 3102
+prima2_evb MACH_PRIMA2_EVB PRIMA2_EVB 3103
+nas6210 MACH_NAS6210 NAS6210 3104
+unisdev MACH_UNISDEV UNISDEV 3105
+sbca11 MACH_SBCA11 SBCA11 3106
+saga MACH_SAGA SAGA 3107
+ns_k330 MACH_NS_K330 NS_K330 3108
+tanna MACH_TANNA TANNA 3109
+imate8502 MACH_IMATE8502 IMATE8502 3110
+aspen MACH_ASPEN ASPEN 3111
+daintree_cwac MACH_DAINTREE_CWAC DAINTREE_CWAC 3112
+zmx25 MACH_ZMX25 ZMX25 3113
+maple1 MACH_MAPLE1 MAPLE1 3114
+qsd8x72_surf MACH_QSD8X72_SURF QSD8X72_SURF 3115
+qsd8x72_ffa MACH_QSD8X72_FFA QSD8X72_FFA 3116
+abilene MACH_ABILENE ABILENE 3117
+eigen_ttr MACH_EIGEN_TTR EIGEN_TTR 3118
+iomega_ix2_200 MACH_IOMEGA_IX2_200 IOMEGA_IX2_200 3119
+coretec_vcx7400 MACH_CORETEC_VCX7400 CORETEC_VCX7400 3120
+santiago MACH_SANTIAGO SANTIAGO 3121
+mx257sol MACH_MX257SOL MX257SOL 3122
+strasbourg MACH_STRASBOURG STRASBOURG 3123
+msm8x60_fluid MACH_MSM8X60_FLUID MSM8X60_FLUID 3124
+smartqv5 MACH_SMARTQV5 SMARTQV5 3125
+smartqv3 MACH_SMARTQV3 SMARTQV3 3126
+smartqv7 MACH_SMARTQV7 SMARTQV7 3127
+paz00 MACH_PAZ00 PAZ00 3128
+acmenetusfoxg20 MACH_ACMENETUSFOXG20 ACMENETUSFOXG20 3129
+htcwillow MACH_HTCWILLOW HTCWILLOW 3130
+fwbd_0404 MACH_FWBD_0404 FWBD_0404 3131
+hdgu MACH_HDGU HDGU 3132
+pyramid MACH_PYRAMID PYRAMID 3133
+epiphan MACH_EPIPHAN EPIPHAN 3134
+omap_bender MACH_OMAP_BENDER OMAP_BENDER 3135
+gurnard MACH_GURNARD GURNARD 3136
+gtl_it5100 MACH_GTL_IT5100 GTL_IT5100 3137
+bcm2708 MACH_BCM2708 BCM2708 3138
+mx51_ggc MACH_MX51_GGC MX51_GGC 3139
+sharespace MACH_SHARESPACE SHARESPACE 3140
+haba_knx_explorer MACH_HABA_KNX_EXPLORER HABA_KNX_EXPLORER 3141
+simtec_kirkmod MACH_SIMTEC_KIRKMOD SIMTEC_KIRKMOD 3142
+crux MACH_CRUX CRUX 3143
+mx51_bravo MACH_MX51_BRAVO MX51_BRAVO 3144
+charon MACH_CHARON CHARON 3145
+picocom3 MACH_PICOCOM3 PICOCOM3 3146
+picocom4 MACH_PICOCOM4 PICOCOM4 3147
+serrano MACH_SERRANO SERRANO 3148
+doubleshot MACH_DOUBLESHOT DOUBLESHOT 3149
+evsy MACH_EVSY EVSY 3150
+huashan MACH_HUASHAN HUASHAN 3151
+lausanne MACH_LAUSANNE LAUSANNE 3152
+emerald MACH_EMERALD EMERALD 3153
+tqma35 MACH_TQMA35 TQMA35 3154
+marvel MACH_MARVEL MARVEL 3155
+manuae MACH_MANUAE MANUAE 3156
+chacha MACH_CHACHA CHACHA 3157
+lemon MACH_LEMON LEMON 3158
+csc MACH_CSC CSC 3159
+gira_knxip_router MACH_GIRA_KNXIP_ROUTER GIRA_KNXIP_ROUTER 3160
+t20 MACH_T20 T20 3161
+hdmini MACH_HDMINI HDMINI 3162
+sciphone_g2 MACH_SCIPHONE_G2 SCIPHONE_G2 3163
+express MACH_EXPRESS EXPRESS 3164
+express_kt MACH_EXPRESS_KT EXPRESS_KT 3165
+maximasp MACH_MAXIMASP MAXIMASP 3166
+nitrogen_imx51 MACH_NITROGEN_IMX51 NITROGEN_IMX51 3167
+nitrogen_imx53 MACH_NITROGEN_IMX53 NITROGEN_IMX53 3168
+sunfire MACH_SUNFIRE SUNFIRE 3169
+arowana MACH_AROWANA AROWANA 3170
+tegra_daytona MACH_TEGRA_DAYTONA TEGRA_DAYTONA 3171
+tegra_swordfish MACH_TEGRA_SWORDFISH TEGRA_SWORDFISH 3172
+edison MACH_EDISON EDISON 3173
+svp8500v1 MACH_SVP8500V1 SVP8500V1 3174
+svp8500v2 MACH_SVP8500V2 SVP8500V2 3175
+svp5500 MACH_SVP5500 SVP5500 3176
+b5500 MACH_B5500 B5500 3177
+s5500 MACH_S5500 S5500 3178
+icon MACH_ICON ICON 3179
+elephant MACH_ELEPHANT ELEPHANT 3180
+msm8x60_fusion MACH_MSM8X60_FUSION MSM8X60_FUSION 3181
+shooter MACH_SHOOTER SHOOTER 3182
+spade_lte MACH_SPADE_LTE SPADE_LTE 3183
+philhwani MACH_PHILHWANI PHILHWANI 3184
+gsncomm MACH_GSNCOMM GSNCOMM 3185
+strasbourg_a2 MACH_STRASBOURG_A2 STRASBOURG_A2 3186
+mmm MACH_MMM MMM 3187
+davinci_dm365_bv MACH_DAVINCI_DM365_BV DAVINCI_DM365_BV 3188
+ag5evm MACH_AG5EVM AG5EVM 3189
+sc575plc MACH_SC575PLC SC575PLC 3190
+sc575hmi MACH_SC575IPC SC575IPC 3191
+omap3_tdm3730 MACH_OMAP3_TDM3730 OMAP3_TDM3730 3192
+g7 MACH_G7 G7 3193
+top9000_eval MACH_TOP9000_EVAL TOP9000_EVAL 3194
+top9000_su MACH_TOP9000_SU TOP9000_SU 3195
+utm300 MACH_UTM300 UTM300 3196
+tsunagi MACH_TSUNAGI TSUNAGI 3197
+ts75xx MACH_TS75XX TS75XX 3198
+msm8x60_fusn_ffa MACH_MSM8X60_FUSN_FFA MSM8X60_FUSN_FFA 3199
+ts47xx MACH_TS47XX TS47XX 3200
+da850_k5 MACH_DA850_K5 DA850_K5 3201
+ax502 MACH_AX502 AX502 3202
+igep0032 MACH_IGEP0032 IGEP0032 3203
+antero MACH_ANTERO ANTERO 3204
+synergy MACH_SYNERGY SYNERGY 3205
+ics_if_voip MACH_ICS_IF_VOIP ICS_IF_VOIP 3206
+wlf_cragg_6410 MACH_WLF_CRAGG_6410 WLF_CRAGG_6410 3207
+punica MACH_PUNICA PUNICA 3208
+sbc_nt250 MACH_SBC_NT250 SBC_NT250 3209
+mx27_wmultra MACH_MX27_WMULTRA MX27_WMULTRA 3210
+mackerel MACH_MACKEREL MACKEREL 3211
+fa9x27 MACH_FA9X27 FA9X27 3213
+ns2816tb MACH_NS2816TB NS2816TB 3214
+ns2816_ntpad MACH_NS2816_NTPAD NS2816_NTPAD 3215
+ns2816_ntnb MACH_NS2816_NTNB NS2816_NTNB 3216
+kaen MACH_KAEN KAEN 3217
+nv1000 MACH_NV1000 NV1000 3218
+nuc950ts MACH_NUC950TS NUC950TS 3219
+nokia_rm680 MACH_NOKIA_RM680 NOKIA_RM680 3220
+ast2200 MACH_AST2200 AST2200 3221
+lead MACH_LEAD LEAD 3222
+unino1 MACH_UNINO1 UNINO1 3223
+greeco MACH_GREECO GREECO 3224
+verdi MACH_VERDI VERDI 3225
+dm6446_adbox MACH_DM6446_ADBOX DM6446_ADBOX 3226
+quad_salsa MACH_QUAD_SALSA QUAD_SALSA 3227
+abb_gma_1_1 MACH_ABB_GMA_1_1 ABB_GMA_1_1 3228
+svcid MACH_SVCID SVCID 3229
+msm8960_sim MACH_MSM8960_SIM MSM8960_SIM 3230
+msm8960_rumi3 MACH_MSM8960_RUMI3 MSM8960_RUMI3 3231
+icon_g MACH_ICON_G ICON_G 3232
+mb3 MACH_MB3 MB3 3233
+gsia18s MACH_GSIA18S GSIA18S 3234
+pivicc MACH_PIVICC PIVICC 3235
+pcm048 MACH_PCM048 PCM048 3236
+dds MACH_DDS DDS 3237
+chalten_xa1 MACH_CHALTEN_XA1 CHALTEN_XA1 3238
mov pc, lr
ENDPROC(vfp_save_state)
+ .align
last_VFP_context_address:
.word last_VFP_context
*/
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/unistd.h>
#include <linux/user.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
}
static int
-simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+simscsi_queuecommand_lck (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
{
unsigned int target_id = sc->device->id;
char fname[MAX_ROOT_LEN+16];
return 0;
}
+static DEF_SCSI_QCMD(simscsi_queuecommand)
+
static int
simscsi_host_reset (struct scsi_cmnd *sc)
{
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
--- /dev/null
+/* Access to user system call parameters and results
+ *
+ * See asm-generic/syscall.h for function descriptions.
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_SYSCALL_H
+#define _ASM_SYSCALL_H
+
+#include <linux/sched.h>
+#include <linux/err.h>
+
+extern const unsigned long sys_call_table[];
+
+static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
+{
+ return regs->orig_d0;
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ regs->d0 = regs->orig_d0;
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ unsigned long error = regs->d0;
+ return IS_ERR_VALUE(error) ? error : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return regs->d0;
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+ struct pt_regs *regs,
+ int error, long val)
+{
+ regs->d0 = (long) error ?: val;
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ unsigned long *args)
+{
+ switch (i) {
+ case 0:
+ if (!n--) break;
+ *args++ = regs->a0;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->d1;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->a3;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->a2;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->d3;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->d2;
+ case 6:
+ if (!n--) break;
+ default:
+ BUG();
+ break;
+ }
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ const unsigned long *args)
+{
+ switch (i) {
+ case 0:
+ if (!n--) break;
+ regs->a0 = *args++;
+ case 1:
+ if (!n--) break;
+ regs->d1 = *args++;
+ case 2:
+ if (!n--) break;
+ regs->a3 = *args++;
+ case 3:
+ if (!n--) break;
+ regs->a2 = *args++;
+ case 4:
+ if (!n--) break;
+ regs->d3 = *args++;
+ case 5:
+ if (!n--) break;
+ regs->d2 = *args++;
+ case 6:
+ if (!n--) break;
+ default:
+ BUG();
+ break;
+ }
+}
+
+#endif /* _ASM_SYSCALL_H */
GDBPORT_SERIAL_IER = UART_IER_RDI | UART_IER_RLSI;
/* permit level 0 IRQs to take place */
- local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
+ arch_local_change_intr_mask_level(
+ NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
}
/*
tmp = *gdbstub_port->_control;
/* permit level 0 IRQs only */
- local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
+ arch_local_change_intr_mask_level(
+ NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
}
/*
asm volatile("mov mdr,%0" : "=d"(mdr));
local_save_flags(epsw);
- local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
+ arch_local_change_intr_mask_level(
+ NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
gdbstub_store_fpu();
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/namei.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/utsname.h>
#include <linux/vfs.h>
smp_send_all_nop();
}
-void no_ack_irq(unsigned int irq) { }
-void no_end_irq(unsigned int irq) { }
-
void cpu_ack_irq(unsigned int irq)
{
unsigned long mask = EIEM_MASK(irq);
/* for iosapic interrupts */
if (type) {
- set_irq_chip_and_handler(irq, type, handle_level_irq);
+ set_irq_chip_and_handler(irq, type, handle_percpu_irq);
set_irq_chip_data(irq, data);
cpu_unmask_irq(irq);
}
int i;
for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
set_irq_chip_and_handler(i, &cpu_interrupt_type,
- handle_level_irq);
+ handle_percpu_irq);
}
set_irq_handler(TIMER_IRQ, handle_percpu_irq);
sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
{
struct rt_sigframe __user *frame;
- struct siginfo si;
sigset_t set;
unsigned long usp = (regs->gr[30] & ~(0x01UL));
unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
give_sigsegv:
DBG(1,"sys_rt_sigreturn: Sending SIGSEGV\n");
- si.si_signo = SIGSEGV;
- si.si_errno = 0;
- si.si_code = SI_KERNEL;
- si.si_pid = task_pid_vnr(current);
- si.si_uid = current_uid();
- si.si_addr = &frame->uc;
- force_sig_info(SIGSEGV, &si, current);
+ force_sig(SIGSEGV, current);
return;
}
#include <linux/times.h>
#include <linux/time.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
bool
default y if !PPC64
+config 32BIT
+ bool
+ default y if PPC32
+
config 64BIT
bool
default y if PPC64
cntlzw r0,r5 # we are shifting the dividend right
li r10,-1 # to make it < 2^32, and shifting
srw r10,r10,r0 # the divisor right the same amount,
- add r9,r4,r10 # rounding up (so the estimate cannot
+ addc r9,r4,r10 # rounding up (so the estimate cannot
andc r11,r6,r10 # ever be too large, only too small)
andc r9,r9,r10
+ addze r9,r9
or r11,r5,r11
rotlw r9,r9,r0
rotlw r11,r11,r0
/* FP registers 32 -> 63 */
#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
if (current)
- memcpy(mem, current->thread.evr[regno-32],
+ memcpy(mem, ¤t->thread.evr[regno-32],
dbg_reg_def[regno].size);
#else
/* fp registers not used by kernel, leave zero */
if (regno >= 32 && regno < 64) {
/* FP registers 32 -> 63 */
#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
- memcpy(current->thread.evr[regno-32], mem,
+ memcpy(¤t->thread.evr[regno-32], mem,
dbg_reg_def[regno].size);
#else
/* fp registers not used by kernel, leave zero */
}
/*
- * Called into from start_kernel, after lock_kernel has been called.
- * Initializes bootmem, which is unsed to manage page allocation until
- * mem_init is called.
+ * Called into from start_kernel this initializes bootmem, which is used
+ * to manage page allocation until mem_init is called.
*/
void __init setup_arch(char **cmdline_p)
{
#include <linux/resource.h>
#include <linux/times.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
else
#endif /* CONFIG_PPC_HAS_HASH_64K */
rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize,
- subpage_protection(pgdir, ea));
+ subpage_protection(mm, ea));
/* Dump some info in case of hash insertion failure, they should
* never happen so it is really useful to know if/when they do
static void pte_free_submit(struct pte_freelist_batch *batch)
{
- call_rcu(&batch->rcu, pte_free_rcu_callback);
+ call_rcu_sched(&batch->rcu, pte_free_rcu_callback);
}
void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
cmpldi cr0,r15,0 /* Check for user region */
std r14,EX_TLB_ESR(r12) /* write crazy -1 to frame */
beq normal_tlb_miss
+
+ li r11,_PAGE_PRESENT|_PAGE_BAP_SX /* Base perm */
+ oris r11,r11,_PAGE_ACCESSED@h
/* XXX replace the RMW cycles with immediate loads + writes */
-1: mfspr r10,SPRN_MAS1
+ mfspr r10,SPRN_MAS1
cmpldi cr0,r15,8 /* Check for vmalloc region */
rlwinm r10,r10,0,16,1 /* Clear TID */
mtspr SPRN_MAS1,r10
ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000);
/* Finally limit subsequent allocations */
- memblock_set_current_limit(ppc64_memblock_base + ppc64_rma_size);
+ memblock_set_current_limit(first_memblock_base + ppc64_rma_size);
}
#endif /* CONFIG_PPC64 */
config PPC_PSERIES_DEBUG
depends on PPC_PSERIES && PPC_EARLY_DEBUG
bool "Enable extra debug logging in platforms/pseries"
+ help
+ Say Y here if you want the pseries core to produce a bunch of
+ debug messages to the system log. Select this if you are having a
+ problem with the pseries core and want to see more of what is
+ going on. This does not enable debugging in lpar.c, which must
+ be manually done due to its verbosity.
default y
config PPC_SMLPAR
* Please address comments and feedback to Linas Vepstas <linas@austin.ibm.com>
*/
-#undef DEBUG
-
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/list.h>
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#undef DEBUG
-
#include <linux/pci.h>
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
source "lib/Kconfig.debug"
+config STRICT_DEVMEM
+ def_bool y
+ prompt "Filter access to /dev/mem"
+ ---help---
+ This option restricts access to /dev/mem. If this option is
+ disabled, you allow userspace access to all memory, including
+ kernel and userspace memory. Accidental memory access is likely
+ to be disastrous.
+ Memory access is required for experts who want to debug the kernel.
+
+ If you are unsure, say Y.
+
config DEBUG_STRICT_USER_COPY_CHECKS
bool "Strict user copy size checks"
---help---
void arch_free_page(struct page *page, int order);
void arch_alloc_page(struct page *page, int order);
+static inline int devmem_is_allowed(unsigned long pfn)
+{
+ return 0;
+}
+
#define HAVE_ARCH_FREE_PAGE
#define HAVE_ARCH_ALLOC_PAGE
#include <linux/resource.h>
#include <linux/times.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <asm/sections.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/hardirq.h>
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
/* Set the PER control regs, turns on single step for this address */
__ctl_load(kprobe_per_regs, 9, 11);
regs->psw.mask |= PSW_MASK_PER;
- regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
+ regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
}
static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
__get_cpu_var(current_kprobe) = p;
/* Save the interrupt and per flags */
kcb->kprobe_saved_imask = regs->psw.mask &
- (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
+ (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);
/* Save the control regs that govern PER */
__ctl_store(kcb->kprobe_saved_ctl, 9, 11);
}
return 1;
ss_probe:
- if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
- local_irq_disable();
prepare_singlestep(p, regs);
kcb->kprobe_status = KPROBE_HIT_SS;
return 1;
struct hlist_node *node, *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+ kprobe_opcode_t *correct_ret_addr = NULL;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/* another task is sharing our hash bucket */
continue;
- if (ri->rp && ri->rp->handler)
- ri->rp->handler(ri, regs);
+ orig_ret_address = (unsigned long)ri->ret_addr;
+
+ if (orig_ret_address != trampoline_address)
+ /*
+ * This is the real return address. Any other
+ * instances associated with this task are for
+ * other calls deeper on the call stack
+ */
+ break;
+ }
+
+ kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
+ correct_ret_addr = ri->ret_addr;
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+ continue;
orig_ret_address = (unsigned long)ri->ret_addr;
+
+ if (ri->rp && ri->rp->handler) {
+ ri->ret_addr = correct_ret_addr;
+ ri->rp->handler(ri, regs);
+ }
+
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address) {
break;
}
}
- kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE;
reset_current_kprobe();
goto out;
}
reset_current_kprobe();
- if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
- local_irq_enable();
out:
preempt_enable_no_resched();
return 1;
}
-int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
{
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
restore_previous_kprobe(kcb);
else {
reset_current_kprobe();
- if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
- local_irq_enable();
}
preempt_enable_no_resched();
break;
return 0;
}
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+ int ret;
+
+ if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+ local_irq_disable();
+ ret = kprobe_trap_handler(regs, trapnr);
+ if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+ local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
+ return ret;
+}
+
/*
* Wrapper routine to for handling exceptions.
*/
unsigned long val, void *data)
{
struct die_args *args = (struct die_args *)data;
+ struct pt_regs *regs = args->regs;
int ret = NOTIFY_DONE;
+ if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+ local_irq_disable();
+
switch (val) {
case DIE_BPT:
if (kprobe_handler(args->regs))
ret = NOTIFY_STOP;
break;
case DIE_TRAP:
- /* kprobe_running() needs smp_processor_id() */
- preempt_disable();
- if (kprobe_running() &&
- kprobe_fault_handler(args->regs, args->trapnr))
+ if (!preemptible() && kprobe_running() &&
+ kprobe_trap_handler(args->regs, args->trapnr))
ret = NOTIFY_STOP;
- preempt_enable();
break;
default:
break;
}
+
+ if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+ local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
+
return ret;
}
/* setup return addr to the jprobe handler routine */
regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE;
+ regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
/* r14 is the function return address */
kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14];
static int notrace s390_revalidate_registers(struct mci *mci)
{
int kill_task;
- u64 tmpclock;
u64 zero;
void *fpt_save_area, *fpt_creg_save_area;
: "0", "cc");
#endif
/* Revalidate clock comparator register */
- asm volatile(
- " stck 0(%1)\n"
- " sckc 0(%1)"
- : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
-
+ if (S390_lowcore.clock_comparator == -1)
+ set_clock_comparator(S390_lowcore.mcck_clock);
+ else
+ set_clock_comparator(S390_lowcore.clock_comparator);
/* Check if old PSW is valid */
if (!mci->wp)
/*
#include <linux/kernel_stat.h>
#include <linux/rcupdate.h>
#include <linux/posix-timers.h>
+#include <linux/cpu.h>
#include <asm/s390_ext.h>
#include <asm/timer.h>
__ctl_set_bit(0,10);
}
+static int __cpuinit s390_nohz_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ struct s390_idle_data *idle;
+ long cpu = (long) hcpu;
+
+ idle = &per_cpu(s390_idle, cpu);
+ switch (action) {
+ case CPU_DYING:
+ case CPU_DYING_FROZEN:
+ idle->nohz_delay = 0;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
void __init vtime_init(void)
{
/* request the cpu timer external interrupt */
/* Enable cpu timer interrupts on the boot cpu. */
init_cpu_vtimer();
+ cpu_notifier(s390_nohz_notify, 0);
}
{
unsigned long mask, cr0, cr0_saved;
u64 clock_saved;
+ u64 end;
+ mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
+ end = get_clock() + (usecs << 12);
clock_saved = local_tick_disable();
- set_clock_comparator(get_clock() + (usecs << 12));
__ctl_store(cr0_saved, 0, 0);
cr0 = (cr0_saved & 0xffff00e0) | 0x00000800;
__ctl_load(cr0 , 0, 0);
- mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
lockdep_off();
- trace_hardirqs_on();
- __load_psw_mask(mask);
- local_irq_disable();
+ do {
+ set_clock_comparator(end);
+ trace_hardirqs_on();
+ __load_psw_mask(mask);
+ local_irq_disable();
+ } while (get_clock() < end);
lockdep_on();
__ctl_load(cr0_saved, 0, 0);
local_tick_enable(clock_saved);
static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr)
{
- unsigned long mask, result;
+ unsigned long mask;
pte_t *ptep, pte;
struct page *page;
- result = write ? 0 : _PAGE_RO;
- mask = result | _PAGE_INVALID | _PAGE_SPECIAL;
+ mask = (write ? _PAGE_RO : 0) | _PAGE_INVALID | _PAGE_SPECIAL;
ptep = ((pte_t *) pmd_deref(pmd)) + pte_index(addr);
do {
pte = *ptep;
barrier();
- if ((pte_val(pte) & mask) != result)
+ if ((pte_val(pte) & mask) != 0)
return 0;
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
page = pte_page(pte);
select HAVE_SPARSE_IRQ
select RTC_LIB
select GENERIC_ATOMIC64
- select GENERIC_HARDIRQS_NO_DEPRECATED
+ # Support the deprecated APIs until MFD and GPIOLIB catch up.
+ select GENERIC_HARDIRQS_NO_DEPRECATED if !MFD_SUPPORT && !GPIOLIB
help
The SuperH is a RISC processor targeted for use in embedded systems
and consumer electronics; it was also used in the Sega Dreamcast
};
/* FSI */
-/*
- * FSI-B use external clock which came from da7210.
- * So, we should change parent of fsi
- */
-#define FCLKBCR 0xa415000c
-static void fsimck_init(struct clk *clk)
-{
- u32 status = __raw_readl(clk->enable_reg);
-
- /* use external clock */
- status &= ~0x000000ff;
- status |= 0x00000080;
-
- __raw_writel(status, clk->enable_reg);
-}
-
-static struct clk_ops fsimck_clk_ops = {
- .init = fsimck_init,
-};
-
-static struct clk fsimckb_clk = {
- .ops = &fsimck_clk_ops,
- .enable_reg = (void __iomem *)FCLKBCR,
- .rate = 0, /* unknown */
-};
-
static struct sh_fsi_platform_info fsi_info = {
.portb_flags = SH_FSI_BRS_INV |
SH_FSI_OUT_SLAVE_MODE |
/* change parent of FSI B */
clk = clk_get(NULL, "fsib_clk");
if (!IS_ERR(clk)) {
- clk_register(&fsimckb_clk);
- clk_set_parent(clk, &fsimckb_clk);
- clk_set_rate(clk, 11000);
- clk_set_rate(&fsimckb_clk, 11000);
+ /* 48kHz dummy clock was used to make sure 1/1 divide */
+ clk_set_rate(&sh7724_fsimckb_clk, 48000);
+ clk_set_parent(clk, &sh7724_fsimckb_clk);
+ clk_set_rate(clk, 48000);
clk_put(clk);
}
};
/* FSI */
-/*
- * FSI-A use external clock which came from ak464x.
- * So, we should change parent of fsi
- */
-#define FCLKACR 0xa4150008
-static void fsimck_init(struct clk *clk)
-{
- u32 status = __raw_readl(clk->enable_reg);
-
- /* use external clock */
- status &= ~0x000000ff;
- status |= 0x00000080;
- __raw_writel(status, clk->enable_reg);
-}
-
-static struct clk_ops fsimck_clk_ops = {
- .init = fsimck_init,
-};
-
-static struct clk fsimcka_clk = {
- .ops = &fsimck_clk_ops,
- .enable_reg = (void __iomem *)FCLKACR,
- .rate = 0, /* unknown */
-};
-
/* change J20, J21, J22 pin to 1-2 connection to use slave mode */
static struct sh_fsi_platform_info fsi_info = {
.porta_flags = SH_FSI_BRS_INV |
gpio_request(GPIO_FN_KEYOUT0, NULL);
/* enable FSI */
- gpio_request(GPIO_FN_FSIMCKB, NULL);
gpio_request(GPIO_FN_FSIMCKA, NULL);
+ gpio_request(GPIO_FN_FSIIASD, NULL);
gpio_request(GPIO_FN_FSIOASD, NULL);
gpio_request(GPIO_FN_FSIIABCK, NULL);
gpio_request(GPIO_FN_FSIIALRCK, NULL);
gpio_request(GPIO_FN_FSIOABCK, NULL);
gpio_request(GPIO_FN_FSIOALRCK, NULL);
gpio_request(GPIO_FN_CLKAUDIOAO, NULL);
- gpio_request(GPIO_FN_FSIIBSD, NULL);
- gpio_request(GPIO_FN_FSIOBSD, NULL);
- gpio_request(GPIO_FN_FSIIBBCK, NULL);
- gpio_request(GPIO_FN_FSIIBLRCK, NULL);
- gpio_request(GPIO_FN_FSIOBBCK, NULL);
- gpio_request(GPIO_FN_FSIOBLRCK, NULL);
- gpio_request(GPIO_FN_CLKAUDIOBO, NULL);
- gpio_request(GPIO_FN_FSIIASD, NULL);
/* set SPU2 clock to 83.4 MHz */
clk = clk_get(NULL, "spu_clk");
- if (clk) {
+ if (!IS_ERR(clk)) {
clk_set_rate(clk, clk_round_rate(clk, 83333333));
clk_put(clk);
}
/* change parent of FSI A */
clk = clk_get(NULL, "fsia_clk");
- if (clk) {
- clk_register(&fsimcka_clk);
- clk_set_parent(clk, &fsimcka_clk);
- clk_set_rate(clk, 11000);
- clk_set_rate(&fsimcka_clk, 11000);
+ if (!IS_ERR(clk)) {
+ /* 48kHz dummy clock was used to make sure 1/1 divide */
+ clk_set_rate(&sh7724_fsimcka_clk, 48000);
+ clk_set_parent(clk, &sh7724_fsimcka_clk);
+ clk_set_rate(clk, 48000);
clk_put(clk);
}
void *kmap_coherent(struct page *page, unsigned long addr);
void kunmap_coherent(void *kvaddr);
-#define PG_dcache_dirty PG_arch_1
+#define PG_dcache_clean PG_arch_1
void cpu_cache_init(void);
#define ARCH_HAS_PREFETCHW
static inline void prefetch(void *x)
{
- __asm__ __volatile__ ("pref @%0\n\t" : : "r" (x) : "memory");
+ __builtin_prefetch(x, 0, 3);
}
-#define prefetchw(x) prefetch(x)
+static inline void prefetchw(void *x)
+{
+ __builtin_prefetch(x, 1, 3);
+}
#endif
#endif /* __KERNEL__ */
#define __NR_sendmsg 355
#define __NR_recvmsg 356
#define __NR_recvmmsg 357
+#define __NR_accept4 358
-#define NR_syscalls 358
+#define NR_syscalls 359
#ifdef __KERNEL__
SHDMA_SLAVE_SDHI1_RX,
};
+extern struct clk sh7724_fsimcka_clk;
+extern struct clk sh7724_fsimckb_clk;
+
#endif /* __ASM_SH7724_H__ */
return 0;
}
-static int shoc_clk_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+static int shoc_clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long frqcr3;
unsigned int tmp;
.parent = &pll_clk,
};
+/* External input clock (pin name: FSIMCKA/FSIMCKB ) */
+struct clk sh7724_fsimcka_clk = {
+};
+
+struct clk sh7724_fsimckb_clk = {
+};
+
static struct clk *main_clks[] = {
&r_clk,
&extal_clk,
&fll_clk,
&pll_clk,
&div3_clk,
+ &sh7724_fsimcka_clk,
+ &sh7724_fsimckb_clk,
};
static void div4_kick(struct clk *clk)
[DIV4_M1] = DIV4(FRQCRB, 4, 0x2f7c, CLK_ENABLE_ON_INIT),
};
-enum { DIV6_V, DIV6_FA, DIV6_FB, DIV6_I, DIV6_S, DIV6_NR };
+enum { DIV6_V, DIV6_I, DIV6_S, DIV6_NR };
static struct clk div6_clks[DIV6_NR] = {
[DIV6_V] = SH_CLK_DIV6(&div3_clk, VCLKCR, 0),
- [DIV6_FA] = SH_CLK_DIV6(&div3_clk, FCLKACR, 0),
- [DIV6_FB] = SH_CLK_DIV6(&div3_clk, FCLKBCR, 0),
[DIV6_I] = SH_CLK_DIV6(&div3_clk, IRDACLKCR, 0),
[DIV6_S] = SH_CLK_DIV6(&div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT),
};
+enum { DIV6_FA, DIV6_FB, DIV6_REPARENT_NR };
+
+/* Indices are important - they are the actual src selecting values */
+static struct clk *fclkacr_parent[] = {
+ [0] = &div3_clk,
+ [1] = NULL,
+ [2] = &sh7724_fsimcka_clk,
+ [3] = NULL,
+};
+
+static struct clk *fclkbcr_parent[] = {
+ [0] = &div3_clk,
+ [1] = NULL,
+ [2] = &sh7724_fsimckb_clk,
+ [3] = NULL,
+};
+
+static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
+ [DIV6_FA] = SH_CLK_DIV6_EXT(&div3_clk, FCLKACR, 0,
+ fclkacr_parent, ARRAY_SIZE(fclkacr_parent), 6, 2),
+ [DIV6_FB] = SH_CLK_DIV6_EXT(&div3_clk, FCLKBCR, 0,
+ fclkbcr_parent, ARRAY_SIZE(fclkbcr_parent), 6, 2),
+};
+
static struct clk mstp_clks[HWBLK_NR] = {
SH_HWBLK_CLK(HWBLK_TLB, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
SH_HWBLK_CLK(HWBLK_IC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
/* DIV6 clocks */
CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
- CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FA]),
- CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FB]),
+ CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FA]),
+ CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FB]),
CLKDEV_CON_ID("irda_clk", &div6_clks[DIV6_I]),
CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_S]),
if (!ret)
ret = sh_clk_div6_register(div6_clks, DIV6_NR);
+ if (!ret)
+ ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR);
+
if (!ret)
ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR);
}
if (op & CACHEFLUSH_I)
- flush_cache_all();
+ flush_icache_range(addr, addr+len);
up_read(¤t->mm->mmap_sem);
return 0;
.long sys_sendmsg /* 355 */
.long sys_recvmsg
.long sys_recvmmsg
+ .long sys_accept4
* fill out .eh_frame -- PFM. */
.LEND_vsyscall:
.size __kernel_vsyscall,.-.LSTART_vsyscall
- .previous
.section .eh_frame,"a",@progbits
+ .previous
.LCIE:
.ualong .LCIE_end - .LCIE_start
.LCIE_start:
struct address_space *mapping = page_mapping(page);
if (mapping && !mapping_mapped(mapping))
- set_bit(PG_dcache_dirty, &page->flags);
+ clear_bit(PG_dcache_clean, &page->flags);
else
#endif
flush_cache_one(CACHE_OC_ADDRESS_ARRAY |
* another ASID than the current one.
*/
map_coherent = (current_cpu_data.dcache.n_aliases &&
- !test_bit(PG_dcache_dirty, &page->flags) &&
+ test_bit(PG_dcache_clean, &page->flags) &&
page_mapped(page));
if (map_coherent)
vaddr = kmap_coherent(page, address);
struct address_space *mapping = page_mapping(page);
if (mapping && !mapping_mapped(mapping))
- set_bit(PG_dcache_dirty, &page->flags);
+ clear_bit(PG_dcache_clean, &page->flags);
else
__flush_dcache_page(__pa(page_address(page)));
}
unsigned long len)
{
if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
- !test_bit(PG_dcache_dirty, &page->flags)) {
+ test_bit(PG_dcache_clean, &page->flags)) {
void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
memcpy(vto, src, len);
kunmap_coherent(vto);
} else {
memcpy(dst, src, len);
if (boot_cpu_data.dcache.n_aliases)
- set_bit(PG_dcache_dirty, &page->flags);
+ clear_bit(PG_dcache_clean, &page->flags);
}
if (vma->vm_flags & VM_EXEC)
unsigned long len)
{
if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
- !test_bit(PG_dcache_dirty, &page->flags)) {
+ test_bit(PG_dcache_clean, &page->flags)) {
void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
memcpy(dst, vfrom, len);
kunmap_coherent(vfrom);
} else {
memcpy(dst, src, len);
if (boot_cpu_data.dcache.n_aliases)
- set_bit(PG_dcache_dirty, &page->flags);
+ clear_bit(PG_dcache_clean, &page->flags);
}
}
vto = kmap_atomic(to, KM_USER1);
if (boot_cpu_data.dcache.n_aliases && page_mapped(from) &&
- !test_bit(PG_dcache_dirty, &from->flags)) {
+ test_bit(PG_dcache_clean, &from->flags)) {
vfrom = kmap_coherent(from, vaddr);
copy_page(vto, vfrom);
kunmap_coherent(vfrom);
page = pfn_to_page(pfn);
if (pfn_valid(pfn)) {
- int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
+ int dirty = !test_and_set_bit(PG_dcache_clean, &page->flags);
if (dirty)
__flush_purge_region(page_address(page), PAGE_SIZE);
}
if (pages_do_alias(addr, vmaddr)) {
if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
- !test_bit(PG_dcache_dirty, &page->flags)) {
+ test_bit(PG_dcache_clean, &page->flags)) {
void *kaddr;
kaddr = kmap_coherent(page, vmaddr);
enum fixed_addresses idx;
unsigned long vaddr;
- BUG_ON(test_bit(PG_dcache_dirty, &page->flags));
+ BUG_ON(!test_bit(PG_dcache_clean, &page->flags));
pagefault_disable();
int (*v2_dev_open)(char *devpath);
void (*v2_dev_close)(int d);
int (*v2_dev_read)(int d, char *buf, int nbytes);
- int (*v2_dev_write)(int d, char *buf, int nbytes);
+ int (*v2_dev_write)(int d, const char *buf, int nbytes);
int (*v2_dev_seek)(int d, int hi, int lo);
/* Never issued (multistage load support) */
extern char *prom_mapio(char *virt_hint, int io_space, unsigned int phys_addr, unsigned int num_bytes);
extern void prom_unmapio(char *virt_addr, unsigned int num_bytes);
-/* Device operations. */
-
-/* Open the device described by the passed string. Note, that the format
- * of the string is different on V0 vs. V2->higher proms. The caller must
- * know what he/she is doing! Returns the device descriptor, an int.
- */
-extern int prom_devopen(char *device_string);
-
-/* Close a previously opened device described by the passed integer
- * descriptor.
- */
-extern int prom_devclose(int device_handle);
-
-/* Do a seek operation on the device described by the passed integer
- * descriptor.
- */
-extern void prom_seek(int device_handle, unsigned int seek_hival,
- unsigned int seek_lowval);
-
/* Miscellaneous routines, don't really fit in any category per se. */
/* Reboot the machine with the command line passed. */
/* Get the prom firmware revision. */
extern int prom_getprev(void);
-/* Character operations to/from the console.... */
-
-/* Non-blocking get character from console. */
-extern int prom_nbgetchar(void);
-
-/* Non-blocking put character to console. */
-extern int prom_nbputchar(char character);
-
-/* Blocking get character from console. */
-extern char prom_getchar(void);
-
-/* Blocking put character to console. */
-extern void prom_putchar(char character);
+/* Write a buffer of characters to the console. */
+extern void prom_console_write_buf(const char *buf, int len);
/* Prom's internal routines, don't use in kernel/boot code. */
extern void prom_printf(const char *fmt, ...);
extern int prom_setprop(phandle node, const char *prop_name, char *prop_value,
int value_size);
-extern phandle prom_pathtoinode(char *path);
extern phandle prom_inst2pkg(int);
/* Dorking with Bus ranges... */
/* Boot argument acquisition, returns the boot command line string. */
extern char *prom_getbootargs(void);
-/* Device utilities. */
-
-/* Device operations. */
-
-/* Open the device described by the passed string. Note, that the format
- * of the string is different on V0 vs. V2->higher proms. The caller must
- * know what he/she is doing! Returns the device descriptor, an int.
- */
-extern int prom_devopen(const char *device_string);
-
-/* Close a previously opened device described by the passed integer
- * descriptor.
- */
-extern int prom_devclose(int device_handle);
-
-/* Do a seek operation on the device described by the passed integer
- * descriptor.
- */
-extern void prom_seek(int device_handle, unsigned int seek_hival,
- unsigned int seek_lowval);
-
/* Miscellaneous routines, don't really fit in any category per se. */
/* Reboot the machine with the command line passed. */
/* Halt and power-off the machine. */
extern void prom_halt_power_off(void) __attribute__ ((noreturn));
-/* Set the PROM 'sync' callback function to the passed function pointer.
- * When the user gives the 'sync' command at the prom prompt while the
- * kernel is still active, the prom will call this routine.
- *
- */
-typedef int (*callback_func_t)(long *cmd);
-extern void prom_setcallback(callback_func_t func_ptr);
-
/* Acquire the IDPROM of the root node in the prom device tree. This
* gets passed a buffer where you would like it stuffed. The return value
* is the format type of this idprom or 0xff on error.
*/
extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size);
-/* Character operations to/from the console.... */
-
-/* Non-blocking get character from console. */
-extern int prom_nbgetchar(void);
-
-/* Non-blocking put character to console. */
-extern int prom_nbputchar(char character);
-
-/* Blocking get character from console. */
-extern char prom_getchar(void);
-
-/* Blocking put character to console. */
-extern void prom_putchar(char character);
+/* Write a buffer of characters to the console. */
+extern void prom_console_write_buf(const char *buf, int len);
/* Prom's internal routines, don't use in kernel/boot code. */
extern void prom_printf(const char *fmt, ...);
extern int prom_setprop(phandle node, const char *prop_name, char *prop_value,
int value_size);
-extern phandle prom_pathtoinode(const char *path);
extern phandle prom_inst2pkg(int);
-extern int prom_service_exists(const char *service_name);
extern void prom_sun4v_guest_soft_state(void);
extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
if (leon3_gptimer_regs && leon3_irqctrl_regs) {
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].val, 0);
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].rld,
- (((1000000 / 100) - 1)));
+ (((1000000 / HZ) - 1)));
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0);
#ifdef CONFIG_SMP
}
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0);
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/100) - 1)));
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/HZ) - 1)));
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0);
# endif
#include <linux/sched.h>
#include <linux/threads.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/init.h>
#include <linux/resource.h>
#include <linux/times.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/mman.h>
#include <linux/utsname.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/ipc.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/perf_event.h>
enum direction {
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
lib-y := bootstr_$(BITS).o
lib-$(CONFIG_SPARC32) += devmap.o
-lib-y += devops_$(BITS).o
lib-y += init_$(BITS).o
lib-$(CONFIG_SPARC32) += memory.o
lib-y += misc_$(BITS).o
extern void restore_current(void);
-/* Non blocking get character from console input device, returns -1
- * if no input was taken. This can be used for polling.
- */
-int
-prom_nbgetchar(void)
-{
- static char inc;
- int i = -1;
- unsigned long flags;
-
- spin_lock_irqsave(&prom_lock, flags);
- switch(prom_vers) {
- case PROM_V0:
- i = (*(romvec->pv_nbgetchar))();
- break;
- case PROM_V2:
- case PROM_V3:
- if( (*(romvec->pv_v2devops).v2_dev_read)(*romvec->pv_v2bootargs.fd_stdin , &inc, 0x1) == 1) {
- i = inc;
- } else {
- i = -1;
- }
- break;
- default:
- i = -1;
- break;
- };
- restore_current();
- spin_unlock_irqrestore(&prom_lock, flags);
- return i; /* Ugh, we could spin forever on unsupported proms ;( */
-}
-
/* Non blocking put character to console device, returns -1 if
* unsuccessful.
*/
-int
-prom_nbputchar(char c)
+static int prom_nbputchar(const char *buf)
{
- static char outc;
unsigned long flags;
int i = -1;
spin_lock_irqsave(&prom_lock, flags);
switch(prom_vers) {
case PROM_V0:
- i = (*(romvec->pv_nbputchar))(c);
+ i = (*(romvec->pv_nbputchar))(*buf);
break;
case PROM_V2:
case PROM_V3:
- outc = c;
- if( (*(romvec->pv_v2devops).v2_dev_write)(*romvec->pv_v2bootargs.fd_stdout, &outc, 0x1) == 1)
+ if ((*(romvec->pv_v2devops).v2_dev_write)(*romvec->pv_v2bootargs.fd_stdout,
+ buf, 0x1) == 1)
i = 0;
- else
- i = -1;
break;
default:
- i = -1;
break;
};
restore_current();
return i; /* Ugh, we could spin forever on unsupported proms ;( */
}
-/* Blocking version of get character routine above. */
-char
-prom_getchar(void)
+void prom_console_write_buf(const char *buf, int len)
{
- int character;
- while((character = prom_nbgetchar()) == -1) ;
- return (char) character;
+ while (len) {
+ int n = prom_nbputchar(buf);
+ if (n)
+ continue;
+ len--;
+ buf++;
+ }
}
-/* Blocking version of put character routine above. */
-void
-prom_putchar(char c)
-{
- while(prom_nbputchar(c) == -1) ;
-}
extern int prom_stdin, prom_stdout;
-/* Non blocking get character from console input device, returns -1
- * if no input was taken. This can be used for polling.
- */
-inline int
-prom_nbgetchar(void)
-{
- unsigned long args[7];
- char inc;
-
- args[0] = (unsigned long) "read";
- args[1] = 3;
- args[2] = 1;
- args[3] = (unsigned int) prom_stdin;
- args[4] = (unsigned long) &inc;
- args[5] = 1;
- args[6] = (unsigned long) -1;
-
- p1275_cmd_direct(args);
-
- if (args[6] == 1)
- return inc;
- return -1;
-}
-
-/* Non blocking put character to console device, returns -1 if
- * unsuccessful.
- */
-inline int
-prom_nbputchar(char c)
+static int __prom_console_write_buf(const char *buf, int len)
{
unsigned long args[7];
- char outc;
-
- outc = c;
+ int ret;
args[0] = (unsigned long) "write";
args[1] = 3;
args[2] = 1;
args[3] = (unsigned int) prom_stdout;
- args[4] = (unsigned long) &outc;
- args[5] = 1;
+ args[4] = (unsigned long) buf;
+ args[5] = (unsigned int) len;
args[6] = (unsigned long) -1;
p1275_cmd_direct(args);
- if (args[6] == 1)
- return 0;
- else
+ ret = (int) args[6];
+ if (ret < 0)
return -1;
+ return ret;
}
-/* Blocking version of get character routine above. */
-char
-prom_getchar(void)
-{
- int character;
- while((character = prom_nbgetchar()) == -1) ;
- return (char) character;
-}
-
-/* Blocking version of put character routine above. */
-void
-prom_putchar(char c)
+void prom_console_write_buf(const char *buf, int len)
{
- prom_nbputchar(c);
-}
-
-void
-prom_puts(const char *s, int len)
-{
- unsigned long args[7];
-
- args[0] = (unsigned long) "write";
- args[1] = 3;
- args[2] = 1;
- args[3] = (unsigned int) prom_stdout;
- args[4] = (unsigned long) s;
- args[5] = len;
- args[6] = (unsigned long) -1;
-
- p1275_cmd_direct(args);
+ while (len) {
+ int n = __prom_console_write_buf(buf, len);
+ if (n < 0)
+ continue;
+ len -= n;
+ buf += len;
+ }
}
+++ /dev/null
-/*
- * devops.c: Device operations using the PROM.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-
-extern void restore_current(void);
-
-/* Open the device described by the string 'dstr'. Returns the handle
- * to that device used for subsequent operations on that device.
- * Returns -1 on failure.
- */
-int
-prom_devopen(char *dstr)
-{
- int handle;
- unsigned long flags;
- spin_lock_irqsave(&prom_lock, flags);
- switch(prom_vers) {
- case PROM_V0:
- handle = (*(romvec->pv_v0devops.v0_devopen))(dstr);
- if(handle == 0) handle = -1;
- break;
- case PROM_V2:
- case PROM_V3:
- handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr);
- break;
- default:
- handle = -1;
- break;
- };
- restore_current();
- spin_unlock_irqrestore(&prom_lock, flags);
-
- return handle;
-}
-
-/* Close the device described by device handle 'dhandle'. */
-int
-prom_devclose(int dhandle)
-{
- unsigned long flags;
- spin_lock_irqsave(&prom_lock, flags);
- switch(prom_vers) {
- case PROM_V0:
- (*(romvec->pv_v0devops.v0_devclose))(dhandle);
- break;
- case PROM_V2:
- case PROM_V3:
- (*(romvec->pv_v2devops.v2_dev_close))(dhandle);
- break;
- default:
- break;
- };
- restore_current();
- spin_unlock_irqrestore(&prom_lock, flags);
- return 0;
-}
-
-/* Seek to specified location described by 'seekhi' and 'seeklo'
- * for device 'dhandle'.
- */
-void
-prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
-{
- unsigned long flags;
- spin_lock_irqsave(&prom_lock, flags);
- switch(prom_vers) {
- case PROM_V0:
- (*(romvec->pv_v0devops.v0_seekdev))(dhandle, seekhi, seeklo);
- break;
- case PROM_V2:
- case PROM_V3:
- (*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo);
- break;
- default:
- break;
- };
- restore_current();
- spin_unlock_irqrestore(&prom_lock, flags);
-}
+++ /dev/null
-/*
- * devops.c: Device operations using the PROM.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-
-/* Open the device described by the string 'dstr'. Returns the handle
- * to that device used for subsequent operations on that device.
- * Returns 0 on failure.
- */
-int
-prom_devopen(const char *dstr)
-{
- unsigned long args[5];
-
- args[0] = (unsigned long) "open";
- args[1] = 1;
- args[2] = 1;
- args[3] = (unsigned long) dstr;
- args[4] = (unsigned long) -1;
-
- p1275_cmd_direct(args);
-
- return (int) args[4];
-}
-
-/* Close the device described by device handle 'dhandle'. */
-int
-prom_devclose(int dhandle)
-{
- unsigned long args[4];
-
- args[0] = (unsigned long) "close";
- args[1] = 1;
- args[2] = 0;
- args[3] = (unsigned int) dhandle;
-
- p1275_cmd_direct(args);
-
- return 0;
-}
-
-/* Seek to specified location described by 'seekhi' and 'seeklo'
- * for device 'dhandle'.
- */
-void
-prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
-{
- unsigned long args[7];
-
- args[0] = (unsigned long) "seek";
- args[1] = 3;
- args[2] = 1;
- args[3] = (unsigned int) dhandle;
- args[4] = seekhi;
- args[5] = seeklo;
- args[6] = (unsigned long) -1;
-
- p1275_cmd_direct(args);
-}
#include <asm/system.h>
#include <asm/ldc.h>
-int prom_service_exists(const char *service_name)
+static int prom_service_exists(const char *service_name)
{
unsigned long args[5];
prom_halt();
}
-/* Set prom sync handler to call function 'funcp'. */
-void prom_setcallback(callback_func_t funcp)
-{
- unsigned long args[5];
- if (!funcp)
- return;
- args[0] = (unsigned long) "set-callback";
- args[1] = 1;
- args[2] = 1;
- args[3] = (unsigned long) funcp;
- args[4] = (unsigned long) -1;
- p1275_cmd_direct(args);
-}
-
/* Get the idprom and stuff it into buffer 'idbuf'. Returns the
* format type. 'num_bytes' is the number of bytes that your idbuf
* has space for. Returns 0xff on error.
#include <linux/kernel.h>
#include <linux/compiler.h>
+#include <linux/spinlock.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
+#define CONSOLE_WRITE_BUF_SIZE 1024
+
static char ppbuf[1024];
+static char console_write_buf[CONSOLE_WRITE_BUF_SIZE];
+static DEFINE_RAW_SPINLOCK(console_write_lock);
void notrace prom_write(const char *buf, unsigned int n)
{
- char ch;
+ unsigned int dest_len;
+ unsigned long flags;
+ char *dest;
+
+ dest = console_write_buf;
+ raw_spin_lock_irqsave(&console_write_lock, flags);
- while (n != 0) {
- --n;
- if ((ch = *buf++) == '\n')
- prom_putchar('\r');
- prom_putchar(ch);
+ dest_len = 0;
+ while (n-- != 0) {
+ char ch = *buf++;
+ if (ch == '\n') {
+ *dest++ = '\r';
+ dest_len++;
+ }
+ *dest++ = ch;
+ dest_len++;
+ if (dest_len >= CONSOLE_WRITE_BUF_SIZE - 1) {
+ prom_console_write_buf(console_write_buf, dest_len);
+ dest = console_write_buf;
+ dest_len = 0;
+ }
}
+ if (dest_len)
+ prom_console_write_buf(console_write_buf, dest_len);
+
+ raw_spin_unlock_irqrestore(&console_write_lock, flags);
}
void notrace prom_printf(const char *fmt, ...)
if (node == -1) return 0;
return node;
}
-
-/* Return 'node' assigned to a particular prom 'path'
- * FIXME: Should work for v0 as well
- */
-phandle prom_pathtoinode(char *path)
-{
- phandle node;
- int inst;
-
- inst = prom_devopen (path);
- if (inst == -1) return 0;
- node = prom_inst2pkg (inst);
- prom_devclose (inst);
- if (node == -1) return 0;
- return node;
-}
return node;
}
-/* Return 'node' assigned to a particular prom 'path'
- * FIXME: Should work for v0 as well
- */
-phandle prom_pathtoinode(const char *path)
-{
- phandle node;
- int inst;
-
- inst = prom_devopen (path);
- if (inst == 0)
- return 0;
- node = prom_inst2pkg(inst);
- prom_devclose(inst);
- if (node == -1)
- return 0;
- return node;
-}
-
int prom_ihandle2path(int handle, char *buffer, int bufsize)
{
unsigned long args[7];
menu "Bus options"
+config PCI
+ bool "PCI support"
+ default y
+ select PCI_DOMAINS
+ ---help---
+ Enable PCI root complex support, so PCIe endpoint devices can
+ be attached to the Tile chip. Many, but not all, PCI devices
+ are supported under Tilera's root complex driver.
+
+config PCI_DOMAINS
+ bool
+
config NO_IOMEM
def_bool !PCI
mb_incoherent();
}
+/*
+ * Flush & invalidate a VA range that is homed remotely on a single core,
+ * waiting until the memory controller holds the flushed values.
+ */
+static inline void finv_buffer_remote(void *buffer, size_t size)
+{
+ char *p;
+ int i;
+
+ /*
+ * Flush and invalidate the buffer out of the local L1/L2
+ * and request the home cache to flush and invalidate as well.
+ */
+ __finv_buffer(buffer, size);
+
+ /*
+ * Wait for the home cache to acknowledge that it has processed
+ * all the flush-and-invalidate requests. This does not mean
+ * that the flushed data has reached the memory controller yet,
+ * but it does mean the home cache is processing the flushes.
+ */
+ __insn_mf();
+
+ /*
+ * Issue a load to the last cache line, which can't complete
+ * until all the previously-issued flushes to the same memory
+ * controller have also completed. If we weren't striping
+ * memory, that one load would be sufficient, but since we may
+ * be, we also need to back up to the last load issued to
+ * another memory controller, which would be the point where
+ * we crossed an 8KB boundary (the granularity of striping
+ * across memory controllers). Keep backing up and doing this
+ * until we are before the beginning of the buffer, or have
+ * hit all the controllers.
+ */
+ for (i = 0, p = (char *)buffer + size - 1;
+ i < (1 << CHIP_LOG_NUM_MSHIMS()) && p >= (char *)buffer;
+ ++i) {
+ const unsigned long STRIPE_WIDTH = 8192;
+
+ /* Force a load instruction to issue. */
+ *(volatile char *)p;
+
+ /* Jump to end of previous stripe. */
+ p -= STRIPE_WIDTH;
+ p = (char *)((unsigned long)p | (STRIPE_WIDTH - 1));
+ }
+
+ /* Wait for the loads (and thus flushes) to have completed. */
+ __insn_mf();
+}
+
#endif /* _ASM_TILE_CACHEFLUSH_H */
#define ioremap_writethrough(physaddr, size) ioremap(physaddr, size)
#define ioremap_fullcache(physaddr, size) ioremap(physaddr, size)
-void __iomem *ioport_map(unsigned long port, unsigned int len);
-extern inline void ioport_unmap(void __iomem *addr) {}
-
#define mmiowb()
/* Conversion between virtual and physical mappings. */
* we never run, uses them unconditionally.
*/
-static inline int ioport_panic(void)
+static inline long ioport_panic(void)
{
panic("inb/outb and friends do not exist on tile");
return 0;
}
+static inline void __iomem *ioport_map(unsigned long port, unsigned int len)
+{
+ return (void __iomem *) ioport_panic();
+}
+
+static inline void ioport_unmap(void __iomem *addr)
+{
+ ioport_panic();
+}
+
static inline u8 inb(unsigned long addr)
{
return ioport_panic();
+++ /dev/null
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for
- * more details.
- */
-
-#ifndef _ASM_TILE_PCI_BRIDGE_H
-#define _ASM_TILE_PCI_BRIDGE_H
-
-#include <linux/ioport.h>
-#include <linux/pci.h>
-
-struct device_node;
-struct pci_controller;
-
-/*
- * pci_io_base returns the memory address at which you can access
- * the I/O space for PCI bus number `bus' (or NULL on error).
- */
-extern void __iomem *pci_bus_io_base(unsigned int bus);
-extern unsigned long pci_bus_io_base_phys(unsigned int bus);
-extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
-
-/* Allocate a new PCI host bridge structure */
-extern struct pci_controller *pcibios_alloc_controller(void);
-
-/* Helper function for setting up resources */
-extern void pci_init_resource(struct resource *res, unsigned long start,
- unsigned long end, int flags, char *name);
-
-/* Get the PCI host controller for a bus */
-extern struct pci_controller *pci_bus_to_hose(int bus);
-
-/*
- * Structure of a PCI controller (host bridge)
- */
-struct pci_controller {
- int index; /* PCI domain number */
- struct pci_bus *root_bus;
-
- int first_busno;
- int last_busno;
-
- int hv_cfg_fd[2]; /* config{0,1} fds for this PCIe controller */
- int hv_mem_fd; /* fd to Hypervisor for MMIO operations */
-
- struct pci_ops *ops;
-
- int irq_base; /* Base IRQ from the Hypervisor */
- int plx_gen1; /* flag for PLX Gen 1 configuration */
-
- /* Address ranges that are routed to this controller/bridge. */
- struct resource mem_resources[3];
-};
-
-static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
-{
- return bus->sysdata;
-}
-
-extern void setup_indirect_pci_nomap(struct pci_controller *hose,
- void __iomem *cfg_addr, void __iomem *cfg_data);
-extern void setup_indirect_pci(struct pci_controller *hose,
- u32 cfg_addr, u32 cfg_data);
-extern void setup_grackle(struct pci_controller *hose);
-
-extern unsigned char common_swizzle(struct pci_dev *, unsigned char *);
-
-/*
- * The following code swizzles for exactly one bridge. The routine
- * common_swizzle below handles multiple bridges. But there are a
- * some boards that don't follow the PCI spec's suggestion so we
- * break this piece out separately.
- */
-static inline unsigned char bridge_swizzle(unsigned char pin,
- unsigned char idsel)
-{
- return (((pin-1) + idsel) % 4) + 1;
-}
-
-/*
- * The following macro is used to lookup irqs in a standard table
- * format for those PPC systems that do not already have PCI
- * interrupts properly routed.
- */
-/* FIXME - double check this */
-#define PCI_IRQ_TABLE_LOOKUP ({ \
- long _ctl_ = -1; \
- if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot) \
- _ctl_ = pci_irq_table[idsel - min_idsel][pin-1]; \
- _ctl_; \
-})
-
-/*
- * Scan the buses below a given PCI host bridge and assign suitable
- * resources to all devices found.
- */
-extern int pciauto_bus_scan(struct pci_controller *, int);
-
-#ifdef CONFIG_PCI
-extern unsigned long pci_address_to_pio(phys_addr_t address);
-#else
-static inline unsigned long pci_address_to_pio(phys_addr_t address)
-{
- return (unsigned long)-1;
-}
-#endif
-
-#endif /* _ASM_TILE_PCI_BRIDGE_H */
#ifndef _ASM_TILE_PCI_H
#define _ASM_TILE_PCI_H
-#include <asm/pci-bridge.h>
+#include <linux/pci.h>
+
+/*
+ * Structure of a PCI controller (host bridge)
+ */
+struct pci_controller {
+ int index; /* PCI domain number */
+ struct pci_bus *root_bus;
+
+ int first_busno;
+ int last_busno;
+
+ int hv_cfg_fd[2]; /* config{0,1} fds for this PCIe controller */
+ int hv_mem_fd; /* fd to Hypervisor for MMIO operations */
+
+ struct pci_ops *ops;
+
+ int irq_base; /* Base IRQ from the Hypervisor */
+ int plx_gen1; /* flag for PLX Gen 1 configuration */
+
+ /* Address ranges that are routed to this controller/bridge. */
+ struct resource mem_resources[3];
+};
/*
* The hypervisor maps the entirety of CPA-space as bus addresses, so
*/
#define PCI_DMA_BUS_IS_PHYS 1
-struct pci_controller *pci_bus_to_hose(int bus);
-unsigned char __init common_swizzle(struct pci_dev *dev, unsigned char *pinp);
int __init tile_pci_init(void);
-void pci_iounmap(struct pci_dev *dev, void __iomem *addr);
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
-void __devinit pcibios_fixup_bus(struct pci_bus *bus);
-int __devinit _tile_cfg_read(struct pci_controller *hose,
- int bus,
- int slot,
- int function,
- int offset,
- int size,
- u32 *val);
-int __devinit _tile_cfg_write(struct pci_controller *hose,
- int bus,
- int slot,
- int function,
- int offset,
- int size,
- u32 val);
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {}
-/*
- * These are used to to config reads and writes in the early stages of
- * setup before the driver infrastructure has been set up enough to be
- * able to do config reads and writes.
- */
-#define early_cfg_read(where, size, value) \
- _tile_cfg_read(controller, \
- current_bus, \
- pci_slot, \
- pci_fn, \
- where, \
- size, \
- value)
-
-#define early_cfg_write(where, size, value) \
- _tile_cfg_write(controller, \
- current_bus, \
- pci_slot, \
- pci_fn, \
- where, \
- size, \
- value)
-
-
-
-#define PCICFG_BYTE 1
-#define PCICFG_WORD 2
-#define PCICFG_DWORD 4
+void __devinit pcibios_fixup_bus(struct pci_bus *bus);
#define TILE_NUM_PCIE 2
}
/*
- * I/O space is currently not supported.
+ * pcibios_assign_all_busses() tells whether or not the bus numbers
+ * should be reassigned, in case the BIOS didn't do it correctly, or
+ * in case we don't have a BIOS and we want to let Linux do it.
*/
+static inline int pcibios_assign_all_busses(void)
+{
+ return 1;
+}
-#define TILE_PCIE_LOWER_IO 0x0
-#define TILE_PCIE_UPPER_IO 0x10000
-#define TILE_PCIE_PCIE_IO_SIZE 0x0000FFFF
-
-#define _PAGE_NO_CACHE 0
-#define _PAGE_GUARDED 0
-
-
-#define pcibios_assign_all_busses() pci_assign_all_buses
-extern int pci_assign_all_buses;
-
+/*
+ * No special bus mastering setup handling.
+ */
static inline void pcibios_set_master(struct pci_dev *dev)
{
- /* No special bus mastering setup handling */
}
#define PCIBIOS_MIN_MEM 0
-#define PCIBIOS_MIN_IO TILE_PCIE_LOWER_IO
+#define PCIBIOS_MIN_IO 0
/*
* This flag tells if the platform is TILEmpower that needs
* special configuration for the PLX switch chip.
*/
-extern int blade_pci;
+extern int tile_plx_gen1;
+
+/* Use any cpu for PCI. */
+#define cpumask_of_pcibus(bus) cpu_online_mask
/* implement the pci_ DMA API in terms of the generic device dma_ one */
#include <asm-generic/pci-dma-compat.h>
/* generic pci stuff */
#include <asm-generic/pci.h>
-/* Use any cpu for PCI. */
-#define cpumask_of_pcibus(bus) cpu_online_mask
-
#endif /* _ASM_TILE_PCI_H */
/* Are we using huge pages in the TLB for kernel data? */
extern int kdata_huge;
+/* Support standard Linux prefetching. */
+#define ARCH_HAS_PREFETCH
+#define prefetch(x) __builtin_prefetch(x)
#define PREFETCH_STRIDE CHIP_L2_LINE_SIZE()
+/* Bring a value into the L1D, faulting the TLB if necessary. */
+#ifdef __tilegx__
+#define prefetch_L1(x) __insn_prefetch_l1_fault((void *)(x))
+#else
+#define prefetch_L1(x) __insn_prefetch_L1((void *)(x))
+#endif
+
#else /* __ASSEMBLY__ */
/* Do some slow action (e.g. read a slow SPR). */
--- /dev/null
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/**
+ * @file drivers/xgbe/impl.h
+ * Implementation details for the NetIO library.
+ */
+
+#ifndef __DRV_XGBE_IMPL_H__
+#define __DRV_XGBE_IMPL_H__
+
+#include <hv/netio_errors.h>
+#include <hv/netio_intf.h>
+#include <hv/drv_xgbe_intf.h>
+
+
+/** How many groups we have (log2). */
+#define LOG2_NUM_GROUPS (12)
+/** How many groups we have. */
+#define NUM_GROUPS (1 << LOG2_NUM_GROUPS)
+
+/** Number of output requests we'll buffer per tile. */
+#define EPP_REQS_PER_TILE (32)
+
+/** Words used in an eDMA command without checksum acceleration. */
+#define EDMA_WDS_NO_CSUM 8
+/** Words used in an eDMA command with checksum acceleration. */
+#define EDMA_WDS_CSUM 10
+/** Total available words in the eDMA command FIFO. */
+#define EDMA_WDS_TOTAL 128
+
+
+/*
+ * FIXME: These definitions are internal and should have underscores!
+ * NOTE: The actual numeric values here are intentional and allow us to
+ * optimize the concept "if small ... else if large ... else ...", by
+ * checking for the low bit being set, and then for non-zero.
+ * These are used as array indices, so they must have the values (0, 1, 2)
+ * in some order.
+ */
+#define SIZE_SMALL (1) /**< Small packet queue. */
+#define SIZE_LARGE (2) /**< Large packet queue. */
+#define SIZE_JUMBO (0) /**< Jumbo packet queue. */
+
+/** The number of "SIZE_xxx" values. */
+#define NETIO_NUM_SIZES 3
+
+
+/*
+ * Default numbers of packets for IPP drivers. These values are chosen
+ * such that CIPP1 will not overflow its L2 cache.
+ */
+
+/** The default number of small packets. */
+#define NETIO_DEFAULT_SMALL_PACKETS 2750
+/** The default number of large packets. */
+#define NETIO_DEFAULT_LARGE_PACKETS 2500
+/** The default number of jumbo packets. */
+#define NETIO_DEFAULT_JUMBO_PACKETS 250
+
+
+/** Log2 of the size of a memory arena. */
+#define NETIO_ARENA_SHIFT 24 /* 16 MB */
+/** Size of a memory arena. */
+#define NETIO_ARENA_SIZE (1 << NETIO_ARENA_SHIFT)
+
+
+/** A queue of packets.
+ *
+ * This structure partially defines a queue of packets waiting to be
+ * processed. The queue as a whole is written to by an interrupt handler and
+ * read by non-interrupt code; this data structure is what's touched by the
+ * interrupt handler. The other part of the queue state, the read offset, is
+ * kept in user space, not in hypervisor space, so it is in a separate data
+ * structure.
+ *
+ * The read offset (__packet_receive_read in the user part of the queue
+ * structure) points to the next packet to be read. When the read offset is
+ * equal to the write offset, the queue is empty; therefore the queue must
+ * contain one more slot than the required maximum queue size.
+ *
+ * Here's an example of all 3 state variables and what they mean. All
+ * pointers move left to right.
+ *
+ * @code
+ * I I V V V V I I I I
+ * 0 1 2 3 4 5 6 7 8 9 10
+ * ^ ^ ^ ^
+ * | | |
+ * | | __last_packet_plus_one
+ * | __buffer_write
+ * __packet_receive_read
+ * @endcode
+ *
+ * This queue has 10 slots, and thus can hold 9 packets (_last_packet_plus_one
+ * = 10). The read pointer is at 2, and the write pointer is at 6; thus,
+ * there are valid, unread packets in slots 2, 3, 4, and 5. The remaining
+ * slots are invalid (do not contain a packet).
+ */
+typedef struct {
+ /** Byte offset of the next notify packet to be written: zero for the first
+ * packet on the queue, sizeof (netio_pkt_t) for the second packet on the
+ * queue, etc. */
+ volatile uint32_t __packet_write;
+
+ /** Offset of the packet after the last valid packet (i.e., when any
+ * pointer is incremented to this value, it wraps back to zero). */
+ uint32_t __last_packet_plus_one;
+}
+__netio_packet_queue_t;
+
+
+/** A queue of buffers.
+ *
+ * This structure partially defines a queue of empty buffers which have been
+ * obtained via requests to the IPP. (The elements of the queue are packet
+ * handles, which are transformed into a full netio_pkt_t when the buffer is
+ * retrieved.) The queue as a whole is written to by an interrupt handler and
+ * read by non-interrupt code; this data structure is what's touched by the
+ * interrupt handler. The other parts of the queue state, the read offset and
+ * requested write offset, are kept in user space, not in hypervisor space, so
+ * they are in a separate data structure.
+ *
+ * The read offset (__buffer_read in the user part of the queue structure)
+ * points to the next buffer to be read. When the read offset is equal to the
+ * write offset, the queue is empty; therefore the queue must contain one more
+ * slot than the required maximum queue size.
+ *
+ * The requested write offset (__buffer_requested_write in the user part of
+ * the queue structure) points to the slot which will hold the next buffer we
+ * request from the IPP, once we get around to sending such a request. When
+ * the requested write offset is equal to the write offset, no requests for
+ * new buffers are outstanding; when the requested write offset is one greater
+ * than the read offset, no more requests may be sent.
+ *
+ * Note that, unlike the packet_queue, the buffer_queue places incoming
+ * buffers at decreasing addresses. This makes the check for "is it time to
+ * wrap the buffer pointer" cheaper in the assembly code which receives new
+ * buffers, and means that the value which defines the queue size,
+ * __last_buffer, is different than in the packet queue. Also, the offset
+ * used in the packet_queue is already scaled by the size of a packet; here we
+ * use unscaled slot indices for the offsets. (These differences are
+ * historical, and in the future it's possible that the packet_queue will look
+ * more like this queue.)
+ *
+ * @code
+ * Here's an example of all 4 state variables and what they mean. Remember:
+ * all pointers move right to left.
+ *
+ * V V V I I R R V V V
+ * 0 1 2 3 4 5 6 7 8 9
+ * ^ ^ ^ ^
+ * | | | |
+ * | | | __last_buffer
+ * | | __buffer_write
+ * | __buffer_requested_write
+ * __buffer_read
+ * @endcode
+ *
+ * This queue has 10 slots, and thus can hold 9 buffers (_last_buffer = 9).
+ * The read pointer is at 2, and the write pointer is at 6; thus, there are
+ * valid, unread buffers in slots 2, 1, 0, 9, 8, and 7. The requested write
+ * pointer is at 4; thus, requests have been made to the IPP for buffers which
+ * will be placed in slots 6 and 5 when they arrive. Finally, the remaining
+ * slots are invalid (do not contain a buffer).
+ */
+typedef struct
+{
+ /** Ordinal number of the next buffer to be written: 0 for the first slot in
+ * the queue, 1 for the second slot in the queue, etc. */
+ volatile uint32_t __buffer_write;
+
+ /** Ordinal number of the last buffer (i.e., when any pointer is decremented
+ * below zero, it is reloaded with this value). */
+ uint32_t __last_buffer;
+}
+__netio_buffer_queue_t;
+
+
+/**
+ * An object for providing Ethernet packets to a process.
+ */
+typedef struct __netio_queue_impl_t
+{
+ /** The queue of packets waiting to be received. */
+ __netio_packet_queue_t __packet_receive_queue;
+ /** The intr bit mask that IDs this device. */
+ unsigned int __intr_id;
+ /** Offset to queues of empty buffers, one per size. */
+ uint32_t __buffer_queue[NETIO_NUM_SIZES];
+ /** The address of the first EPP tile, or -1 if no EPP. */
+ /* ISSUE: Actually this is always "0" or "~0". */
+ uint32_t __epp_location;
+ /** The queue ID that this queue represents. */
+ unsigned int __queue_id;
+ /** Number of acknowledgements received. */
+ volatile uint32_t __acks_received;
+ /** Last completion number received for packet_sendv. */
+ volatile uint32_t __last_completion_rcv;
+ /** Number of packets allowed to be outstanding. */
+ uint32_t __max_outstanding;
+ /** First VA available for packets. */
+ void* __va_0;
+ /** First VA in second range available for packets. */
+ void* __va_1;
+ /** Padding to align the "__packets" field to the size of a netio_pkt_t. */
+ uint32_t __padding[3];
+ /** The packets themselves. */
+ netio_pkt_t __packets[0];
+}
+netio_queue_impl_t;
+
+
+/**
+ * An object for managing the user end of a NetIO queue.
+ */
+typedef struct __netio_queue_user_impl_t
+{
+ /** The next incoming packet to be read. */
+ uint32_t __packet_receive_read;
+ /** The next empty buffers to be read, one index per size. */
+ uint8_t __buffer_read[NETIO_NUM_SIZES];
+ /** Where the empty buffer we next request from the IPP will go, one index
+ * per size. */
+ uint8_t __buffer_requested_write[NETIO_NUM_SIZES];
+ /** PCIe interface flag. */
+ uint8_t __pcie;
+ /** Number of packets left to be received before we send a credit update. */
+ uint32_t __receive_credit_remaining;
+ /** Value placed in __receive_credit_remaining when it reaches zero. */
+ uint32_t __receive_credit_interval;
+ /** First fast I/O routine index. */
+ uint32_t __fastio_index;
+ /** Number of acknowledgements expected. */
+ uint32_t __acks_outstanding;
+ /** Last completion number requested. */
+ uint32_t __last_completion_req;
+ /** File descriptor for driver. */
+ int __fd;
+}
+netio_queue_user_impl_t;
+
+
+#define NETIO_GROUP_CHUNK_SIZE 64 /**< Max # groups in one IPP request */
+#define NETIO_BUCKET_CHUNK_SIZE 64 /**< Max # buckets in one IPP request */
+
+
+/** Internal structure used to convey packet send information to the
+ * hypervisor. FIXME: Actually, it's not used for that anymore, but
+ * netio_packet_send() still uses it internally.
+ */
+typedef struct
+{
+ uint16_t flags; /**< Packet flags (__NETIO_SEND_FLG_xxx) */
+ uint16_t transfer_size; /**< Size of packet */
+ uint32_t va; /**< VA of start of packet */
+ __netio_pkt_handle_t handle; /**< Packet handle */
+ uint32_t csum0; /**< First checksum word */
+ uint32_t csum1; /**< Second checksum word */
+}
+__netio_send_cmd_t;
+
+
+/** Flags used in two contexts:
+ * - As the "flags" member in the __netio_send_cmd_t, above; used only
+ * for netio_pkt_send_{prepare,commit}.
+ * - As part of the flags passed to the various send packet fast I/O calls.
+ */
+
+/** Need acknowledgement on this packet. Note that some code in the
+ * normal send_pkt fast I/O handler assumes that this is equal to 1. */
+#define __NETIO_SEND_FLG_ACK 0x1
+
+/** Do checksum on this packet. (Only used with the __netio_send_cmd_t;
+ * normal packet sends use a special fast I/O index to denote checksumming,
+ * and multi-segment sends test the checksum descriptor.) */
+#define __NETIO_SEND_FLG_CSUM 0x2
+
+/** Get a completion on this packet. Only used with multi-segment sends. */
+#define __NETIO_SEND_FLG_COMPLETION 0x4
+
+/** Position of the number-of-extra-segments value in the flags word.
+ Only used with multi-segment sends. */
+#define __NETIO_SEND_FLG_XSEG_SHIFT 3
+
+/** Width of the number-of-extra-segments value in the flags word. */
+#define __NETIO_SEND_FLG_XSEG_WIDTH 2
+
+#endif /* __DRV_XGBE_IMPL_H__ */
--- /dev/null
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/**
+ * @file drv_xgbe_intf.h
+ * Interface to the hypervisor XGBE driver.
+ */
+
+#ifndef __DRV_XGBE_INTF_H__
+#define __DRV_XGBE_INTF_H__
+
+/**
+ * An object for forwarding VAs and PAs to the hypervisor.
+ * @ingroup types
+ *
+ * This allows the supervisor to specify a number of areas of memory to
+ * store packet buffers.
+ */
+typedef struct
+{
+ /** The physical address of the memory. */
+ HV_PhysAddr pa;
+ /** Page table entry for the memory. This is only used to derive the
+ * memory's caching mode; the PA bits are ignored. */
+ HV_PTE pte;
+ /** The virtual address of the memory. */
+ HV_VirtAddr va;
+ /** Size (in bytes) of the memory area. */
+ int size;
+
+}
+netio_ipp_address_t;
+
+/** The various pread/pwrite offsets into the hypervisor-level driver.
+ * @ingroup types
+ */
+typedef enum
+{
+ /** Inform the Linux driver of the address of the NetIO arena memory.
+ * This offset is actually only used to convey information from netio
+ * to the Linux driver; it never makes it from there to the hypervisor.
+ * Write-only; takes a uint32_t specifying the VA address. */
+ NETIO_FIXED_ADDR = 0x5000000000000000ULL,
+
+ /** Inform the Linux driver of the size of the NetIO arena memory.
+ * This offset is actually only used to convey information from netio
+ * to the Linux driver; it never makes it from there to the hypervisor.
+ * Write-only; takes a uint32_t specifying the VA size. */
+ NETIO_FIXED_SIZE = 0x5100000000000000ULL,
+
+ /** Register current tile with IPP. Write then read: write, takes a
+ * netio_input_config_t, read returns a pointer to a netio_queue_impl_t. */
+ NETIO_IPP_INPUT_REGISTER_OFF = 0x6000000000000000ULL,
+
+ /** Unregister current tile from IPP. Write-only, takes a dummy argument. */
+ NETIO_IPP_INPUT_UNREGISTER_OFF = 0x6100000000000000ULL,
+
+ /** Start packets flowing. Write-only, takes a dummy argument. */
+ NETIO_IPP_INPUT_INIT_OFF = 0x6200000000000000ULL,
+
+ /** Stop packets flowing. Write-only, takes a dummy argument. */
+ NETIO_IPP_INPUT_UNINIT_OFF = 0x6300000000000000ULL,
+
+ /** Configure group (typically we group on VLAN). Write-only: takes an
+ * array of netio_group_t's, low 24 bits of the offset is the base group
+ * number times the size of a netio_group_t. */
+ NETIO_IPP_INPUT_GROUP_CFG_OFF = 0x6400000000000000ULL,
+
+ /** Configure bucket. Write-only: takes an array of netio_bucket_t's, low
+ * 24 bits of the offset is the base bucket number times the size of a
+ * netio_bucket_t. */
+ NETIO_IPP_INPUT_BUCKET_CFG_OFF = 0x6500000000000000ULL,
+
+ /** Get/set a parameter. Read or write: read or write data is the parameter
+ * value, low 32 bits of the offset is a __netio_getset_offset_t. */
+ NETIO_IPP_PARAM_OFF = 0x6600000000000000ULL,
+
+ /** Get fast I/O index. Read-only; returns a 4-byte base index value. */
+ NETIO_IPP_GET_FASTIO_OFF = 0x6700000000000000ULL,
+
+ /** Configure hijack IP address. Packets with this IPv4 dest address
+ * go to bucket NETIO_NUM_BUCKETS - 1. Write-only: takes an IP address
+ * in some standard form. FIXME: Define the form! */
+ NETIO_IPP_INPUT_HIJACK_CFG_OFF = 0x6800000000000000ULL,
+
+ /**
+ * Offsets beyond this point are reserved for the supervisor (although that
+ * enforcement must be done by the supervisor driver itself).
+ */
+ NETIO_IPP_USER_MAX_OFF = 0x6FFFFFFFFFFFFFFFULL,
+
+ /** Register I/O memory. Write-only, takes a netio_ipp_address_t. */
+ NETIO_IPP_IOMEM_REGISTER_OFF = 0x7000000000000000ULL,
+
+ /** Unregister I/O memory. Write-only, takes a netio_ipp_address_t. */
+ NETIO_IPP_IOMEM_UNREGISTER_OFF = 0x7100000000000000ULL,
+
+ /* Offsets greater than 0x7FFFFFFF can't be used directly from Linux
+ * userspace code due to limitations in the pread/pwrite syscalls. */
+
+ /** Drain LIPP buffers. */
+ NETIO_IPP_DRAIN_OFF = 0xFA00000000000000ULL,
+
+ /** Supply a netio_ipp_address_t to be used as shared memory for the
+ * LEPP command queue. */
+ NETIO_EPP_SHM_OFF = 0xFB00000000000000ULL,
+
+ /* 0xFC... is currently unused. */
+
+ /** Stop IPP/EPP tiles. Write-only, takes a dummy argument. */
+ NETIO_IPP_STOP_SHIM_OFF = 0xFD00000000000000ULL,
+
+ /** Start IPP/EPP tiles. Write-only, takes a dummy argument. */
+ NETIO_IPP_START_SHIM_OFF = 0xFE00000000000000ULL,
+
+ /** Supply packet arena. Write-only, takes an array of
+ * netio_ipp_address_t values. */
+ NETIO_IPP_ADDRESS_OFF = 0xFF00000000000000ULL,
+} netio_hv_offset_t;
+
+/** Extract the base offset from an offset */
+#define NETIO_BASE_OFFSET(off) ((off) & 0xFF00000000000000ULL)
+/** Extract the local offset from an offset */
+#define NETIO_LOCAL_OFFSET(off) ((off) & 0x00FFFFFFFFFFFFFFULL)
+
+
+/**
+ * Get/set offset.
+ */
+typedef union
+{
+ struct
+ {
+ uint64_t addr:48; /**< Class-specific address */
+ unsigned int class:8; /**< Class (e.g., NETIO_PARAM) */
+ unsigned int opcode:8; /**< High 8 bits of NETIO_IPP_PARAM_OFF */
+ }
+ bits; /**< Bitfields */
+ uint64_t word; /**< Aggregated value to use as the offset */
+}
+__netio_getset_offset_t;
+
+/**
+ * Fast I/O index offsets (must be contiguous).
+ */
+typedef enum
+{
+ NETIO_FASTIO_ALLOCATE = 0, /**< Get empty packet buffer */
+ NETIO_FASTIO_FREE_BUFFER = 1, /**< Give buffer back to IPP */
+ NETIO_FASTIO_RETURN_CREDITS = 2, /**< Give credits to IPP */
+ NETIO_FASTIO_SEND_PKT_NOCK = 3, /**< Send a packet, no checksum */
+ NETIO_FASTIO_SEND_PKT_CK = 4, /**< Send a packet, with checksum */
+ NETIO_FASTIO_SEND_PKT_VEC = 5, /**< Send a vector of packets */
+ NETIO_FASTIO_SENDV_PKT = 6, /**< Sendv one packet */
+ NETIO_FASTIO_NUM_INDEX = 7, /**< Total number of fast I/O indices */
+} netio_fastio_index_t;
+
+/** 3-word return type for Fast I/O call. */
+typedef struct
+{
+ int err; /**< Error code. */
+ uint32_t val0; /**< Value. Meaning depends upon the specific call. */
+ uint32_t val1; /**< Value. Meaning depends upon the specific call. */
+} netio_fastio_rv3_t;
+
+/** 0-argument fast I/O call */
+int __netio_fastio0(uint32_t fastio_index);
+/** 1-argument fast I/O call */
+int __netio_fastio1(uint32_t fastio_index, uint32_t arg0);
+/** 3-argument fast I/O call, 2-word return value */
+netio_fastio_rv3_t __netio_fastio3_rv3(uint32_t fastio_index, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2);
+/** 4-argument fast I/O call */
+int __netio_fastio4(uint32_t fastio_index, uint32_t arg0, uint32_t arg1,
+ uint32_t arg2, uint32_t arg3);
+/** 6-argument fast I/O call */
+int __netio_fastio6(uint32_t fastio_index, uint32_t arg0, uint32_t arg1,
+ uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5);
+/** 9-argument fast I/O call */
+int __netio_fastio9(uint32_t fastio_index, uint32_t arg0, uint32_t arg1,
+ uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5,
+ uint32_t arg6, uint32_t arg7, uint32_t arg8);
+
+/** Allocate an empty packet.
+ * @param fastio_index Fast I/O index.
+ * @param size Size of the packet to allocate.
+ */
+#define __netio_fastio_allocate(fastio_index, size) \
+ __netio_fastio1((fastio_index) + NETIO_FASTIO_ALLOCATE, size)
+
+/** Free a buffer.
+ * @param fastio_index Fast I/O index.
+ * @param handle Handle for the packet to free.
+ */
+#define __netio_fastio_free_buffer(fastio_index, handle) \
+ __netio_fastio1((fastio_index) + NETIO_FASTIO_FREE_BUFFER, handle)
+
+/** Increment our receive credits.
+ * @param fastio_index Fast I/O index.
+ * @param credits Number of credits to add.
+ */
+#define __netio_fastio_return_credits(fastio_index, credits) \
+ __netio_fastio1((fastio_index) + NETIO_FASTIO_RETURN_CREDITS, credits)
+
+/** Send packet, no checksum.
+ * @param fastio_index Fast I/O index.
+ * @param ackflag Nonzero if we want an ack.
+ * @param size Size of the packet.
+ * @param va Virtual address of start of packet.
+ * @param handle Packet handle.
+ */
+#define __netio_fastio_send_pkt_nock(fastio_index, ackflag, size, va, handle) \
+ __netio_fastio4((fastio_index) + NETIO_FASTIO_SEND_PKT_NOCK, ackflag, \
+ size, va, handle)
+
+/** Send packet, calculate checksum.
+ * @param fastio_index Fast I/O index.
+ * @param ackflag Nonzero if we want an ack.
+ * @param size Size of the packet.
+ * @param va Virtual address of start of packet.
+ * @param handle Packet handle.
+ * @param csum0 Shim checksum header.
+ * @param csum1 Checksum seed.
+ */
+#define __netio_fastio_send_pkt_ck(fastio_index, ackflag, size, va, handle, \
+ csum0, csum1) \
+ __netio_fastio6((fastio_index) + NETIO_FASTIO_SEND_PKT_CK, ackflag, \
+ size, va, handle, csum0, csum1)
+
+
+/** Format for the "csum0" argument to the __netio_fastio_send routines
+ * and LEPP. Note that this is currently exactly identical to the
+ * ShimProtocolOffloadHeader.
+ */
+typedef union
+{
+ struct
+ {
+ unsigned int start_byte:7; /**< The first byte to be checksummed */
+ unsigned int count:14; /**< Number of bytes to be checksummed. */
+ unsigned int destination_byte:7; /**< The byte to write the checksum to. */
+ unsigned int reserved:4; /**< Reserved. */
+ } bits; /**< Decomposed method of access. */
+ unsigned int word; /**< To send out the IDN. */
+} __netio_checksum_header_t;
+
+
+/** Sendv packet with 1 or 2 segments.
+ * @param fastio_index Fast I/O index.
+ * @param flags Ack/csum/notify flags in low 3 bits; number of segments minus
+ * 1 in next 2 bits; expected checksum in high 16 bits.
+ * @param confno Confirmation number to request, if notify flag set.
+ * @param csum0 Checksum descriptor; if zero, no checksum.
+ * @param va_F Virtual address of first segment.
+ * @param va_L Virtual address of last segment, if 2 segments.
+ * @param len_F_L Length of first segment in low 16 bits; length of last
+ * segment, if 2 segments, in high 16 bits.
+ */
+#define __netio_fastio_sendv_pkt_1_2(fastio_index, flags, confno, csum0, \
+ va_F, va_L, len_F_L) \
+ __netio_fastio6((fastio_index) + NETIO_FASTIO_SENDV_PKT, flags, confno, \
+ csum0, va_F, va_L, len_F_L)
+
+/** Send packet on PCIe interface.
+ * @param fastio_index Fast I/O index.
+ * @param flags Ack/csum/notify flags in low 3 bits.
+ * @param confno Confirmation number to request, if notify flag set.
+ * @param csum0 Checksum descriptor; Hard wired 0, not needed for PCIe.
+ * @param va_F Virtual address of the packet buffer.
+ * @param va_L Virtual address of last segment, if 2 segments. Hard wired 0.
+ * @param len_F_L Length of the packet buffer in low 16 bits.
+ */
+#define __netio_fastio_send_pcie_pkt(fastio_index, flags, confno, csum0, \
+ va_F, va_L, len_F_L) \
+ __netio_fastio6((fastio_index) + PCIE_FASTIO_SENDV_PKT, flags, confno, \
+ csum0, va_F, va_L, len_F_L)
+
+/** Sendv packet with 3 or 4 segments.
+ * @param fastio_index Fast I/O index.
+ * @param flags Ack/csum/notify flags in low 3 bits; number of segments minus
+ * 1 in next 2 bits; expected checksum in high 16 bits.
+ * @param confno Confirmation number to request, if notify flag set.
+ * @param csum0 Checksum descriptor; if zero, no checksum.
+ * @param va_F Virtual address of first segment.
+ * @param va_L Virtual address of last segment (third segment if 3 segments,
+ * fourth segment if 4 segments).
+ * @param len_F_L Length of first segment in low 16 bits; length of last
+ * segment in high 16 bits.
+ * @param va_M0 Virtual address of "middle 0" segment; this segment is sent
+ * second when there are three segments, and third if there are four.
+ * @param va_M1 Virtual address of "middle 1" segment; this segment is sent
+ * second when there are four segments.
+ * @param len_M0_M1 Length of middle 0 segment in low 16 bits; length of middle
+ * 1 segment, if 4 segments, in high 16 bits.
+ */
+#define __netio_fastio_sendv_pkt_3_4(fastio_index, flags, confno, csum0, va_F, \
+ va_L, len_F_L, va_M0, va_M1, len_M0_M1) \
+ __netio_fastio9((fastio_index) + NETIO_FASTIO_SENDV_PKT, flags, confno, \
+ csum0, va_F, va_L, len_F_L, va_M0, va_M1, len_M0_M1)
+
+/** Send vector of packets.
+ * @param fastio_index Fast I/O index.
+ * @param seqno Number of packets transmitted so far on this interface;
+ * used to decide which packets should be acknowledged.
+ * @param nentries Number of entries in vector.
+ * @param va Virtual address of start of vector entry array.
+ * @return 3-word netio_fastio_rv3_t structure. The structure's err member
+ * is an error code, or zero if no error. The val0 member is the
+ * updated value of seqno; it has been incremented by 1 for each
+ * packet sent. That increment may be less than nentries if an
+ * error occured, or if some of the entries in the vector contain
+ * handles equal to NETIO_PKT_HANDLE_NONE. The val1 member is the
+ * updated value of nentries; it has been decremented by 1 for each
+ * vector entry processed. Again, that decrement may be less than
+ * nentries (leaving the returned value positive) if an error
+ * occurred.
+ */
+#define __netio_fastio_send_pkt_vec(fastio_index, seqno, nentries, va) \
+ __netio_fastio3_rv3((fastio_index) + NETIO_FASTIO_SEND_PKT_VEC, seqno, \
+ nentries, va)
+
+
+/** An egress DMA command for LEPP. */
+typedef struct
+{
+ /** Is this a TSO transfer?
+ *
+ * NOTE: This field is always 0, to distinguish it from
+ * lepp_tso_cmd_t. It must come first!
+ */
+ uint8_t tso : 1;
+
+ /** Unused padding bits. */
+ uint8_t _unused : 3;
+
+ /** Should this packet be sent directly from caches instead of DRAM,
+ * using hash-for-home to locate the packet data?
+ */
+ uint8_t hash_for_home : 1;
+
+ /** Should we compute a checksum? */
+ uint8_t compute_checksum : 1;
+
+ /** Is this the final buffer for this packet?
+ *
+ * A single packet can be split over several input buffers (a "gather"
+ * operation). This flag indicates that this is the last buffer
+ * in a packet.
+ */
+ uint8_t end_of_packet : 1;
+
+ /** Should LEPP advance 'comp_busy' when this DMA is fully finished? */
+ uint8_t send_completion : 1;
+
+ /** High bits of Client Physical Address of the start of the buffer
+ * to be egressed.
+ *
+ * NOTE: Only 6 bits are actually needed here, as CPAs are
+ * currently 38 bits. So two bits could be scavenged from this.
+ */
+ uint8_t cpa_hi;
+
+ /** The number of bytes to be egressed. */
+ uint16_t length;
+
+ /** Low 32 bits of Client Physical Address of the start of the buffer
+ * to be egressed.
+ */
+ uint32_t cpa_lo;
+
+ /** Checksum information (only used if 'compute_checksum'). */
+ __netio_checksum_header_t checksum_data;
+
+} lepp_cmd_t;
+
+
+/** A chunk of physical memory for a TSO egress. */
+typedef struct
+{
+ /** The low bits of the CPA. */
+ uint32_t cpa_lo;
+ /** The high bits of the CPA. */
+ uint16_t cpa_hi : 15;
+ /** Should this packet be sent directly from caches instead of DRAM,
+ * using hash-for-home to locate the packet data?
+ */
+ uint16_t hash_for_home : 1;
+ /** The length in bytes. */
+ uint16_t length;
+} lepp_frag_t;
+
+
+/** An LEPP command that handles TSO. */
+typedef struct
+{
+ /** Is this a TSO transfer?
+ *
+ * NOTE: This field is always 1, to distinguish it from
+ * lepp_cmd_t. It must come first!
+ */
+ uint8_t tso : 1;
+
+ /** Unused padding bits. */
+ uint8_t _unused : 7;
+
+ /** Size of the header[] array in bytes. It must be in the range
+ * [40, 127], which are the smallest header for a TCP packet over
+ * Ethernet and the maximum possible prepend size supported by
+ * hardware, respectively. Note that the array storage must be
+ * padded out to a multiple of four bytes so that the following
+ * LEPP command is aligned properly.
+ */
+ uint8_t header_size;
+
+ /** Byte offset of the IP header in header[]. */
+ uint8_t ip_offset;
+
+ /** Byte offset of the TCP header in header[]. */
+ uint8_t tcp_offset;
+
+ /** The number of bytes to use for the payload of each packet,
+ * except of course the last one, which may not have enough bytes.
+ * This means that each Ethernet packet except the last will have a
+ * size of header_size + payload_size.
+ */
+ uint16_t payload_size;
+
+ /** The length of the 'frags' array that follows this struct. */
+ uint16_t num_frags;
+
+ /** The actual frags. */
+ lepp_frag_t frags[0 /* Variable-sized; num_frags entries. */];
+
+ /*
+ * The packet header template logically follows frags[],
+ * but you can't declare that in C.
+ *
+ * uint32_t header[header_size_in_words_rounded_up];
+ */
+
+} lepp_tso_cmd_t;
+
+
+/** An LEPP completion ring entry. */
+typedef void* lepp_comp_t;
+
+
+/** Maximum number of frags for one TSO command. This is adapted from
+ * linux's "MAX_SKB_FRAGS", and presumably over-estimates by one, for
+ * our page size of exactly 65536. We add one for a "body" fragment.
+ */
+#define LEPP_MAX_FRAGS (65536 / HV_PAGE_SIZE_SMALL + 2 + 1)
+
+/** Total number of bytes needed for an lepp_tso_cmd_t. */
+#define LEPP_TSO_CMD_SIZE(num_frags, header_size) \
+ (sizeof(lepp_tso_cmd_t) + \
+ (num_frags) * sizeof(lepp_frag_t) + \
+ (((header_size) + 3) & -4))
+
+/** The size of the lepp "cmd" queue. */
+#define LEPP_CMD_QUEUE_BYTES \
+ (((CHIP_L2_CACHE_SIZE() - 2 * CHIP_L2_LINE_SIZE()) / \
+ (sizeof(lepp_cmd_t) + sizeof(lepp_comp_t))) * sizeof(lepp_cmd_t))
+
+/** The largest possible command that can go in lepp_queue_t::cmds[]. */
+#define LEPP_MAX_CMD_SIZE LEPP_TSO_CMD_SIZE(LEPP_MAX_FRAGS, 128)
+
+/** The largest possible value of lepp_queue_t::cmd_{head, tail} (inclusive).
+ */
+#define LEPP_CMD_LIMIT \
+ (LEPP_CMD_QUEUE_BYTES - LEPP_MAX_CMD_SIZE)
+
+/** The maximum number of completions in an LEPP queue. */
+#define LEPP_COMP_QUEUE_SIZE \
+ ((LEPP_CMD_LIMIT + sizeof(lepp_cmd_t) - 1) / sizeof(lepp_cmd_t))
+
+/** Increment an index modulo the queue size. */
+#define LEPP_QINC(var) \
+ (var = __insn_mnz(var - (LEPP_COMP_QUEUE_SIZE - 1), var + 1))
+
+/** A queue used to convey egress commands from the client to LEPP. */
+typedef struct
+{
+ /** Index of first completion not yet processed by user code.
+ * If this is equal to comp_busy, there are no such completions.
+ *
+ * NOTE: This is only read/written by the user.
+ */
+ unsigned int comp_head;
+
+ /** Index of first completion record not yet completed.
+ * If this is equal to comp_tail, there are no such completions.
+ * This index gets advanced (modulo LEPP_QUEUE_SIZE) whenever
+ * a command with the 'completion' bit set is finished.
+ *
+ * NOTE: This is only written by LEPP, only read by the user.
+ */
+ volatile unsigned int comp_busy;
+
+ /** Index of the first empty slot in the completion ring.
+ * Entries from this up to but not including comp_head (in ring order)
+ * can be filled in with completion data.
+ *
+ * NOTE: This is only read/written by the user.
+ */
+ unsigned int comp_tail;
+
+ /** Byte index of first command enqueued for LEPP but not yet processed.
+ *
+ * This is always divisible by sizeof(void*) and always <= LEPP_CMD_LIMIT.
+ *
+ * NOTE: LEPP advances this counter as soon as it no longer needs
+ * the cmds[] storage for this entry, but the transfer is not actually
+ * complete (i.e. the buffer pointed to by the command is no longer
+ * needed) until comp_busy advances.
+ *
+ * If this is equal to cmd_tail, the ring is empty.
+ *
+ * NOTE: This is only written by LEPP, only read by the user.
+ */
+ volatile unsigned int cmd_head;
+
+ /** Byte index of first empty slot in the command ring. This field can
+ * be incremented up to but not equal to cmd_head (because that would
+ * mean the ring is empty).
+ *
+ * This is always divisible by sizeof(void*) and always <= LEPP_CMD_LIMIT.
+ *
+ * NOTE: This is read/written by the user, only read by LEPP.
+ */
+ volatile unsigned int cmd_tail;
+
+ /** A ring of variable-sized egress DMA commands.
+ *
+ * NOTE: Only written by the user, only read by LEPP.
+ */
+ char cmds[LEPP_CMD_QUEUE_BYTES]
+ __attribute__((aligned(CHIP_L2_LINE_SIZE())));
+
+ /** A ring of user completion data.
+ * NOTE: Only read/written by the user.
+ */
+ lepp_comp_t comps[LEPP_COMP_QUEUE_SIZE]
+ __attribute__((aligned(CHIP_L2_LINE_SIZE())));
+} lepp_queue_t;
+
+
+/** An internal helper function for determining the number of entries
+ * available in a ring buffer, given that there is one sentinel.
+ */
+static inline unsigned int
+_lepp_num_free_slots(unsigned int head, unsigned int tail)
+{
+ /*
+ * One entry is reserved for use as a sentinel, to distinguish
+ * "empty" from "full". So we compute
+ * (head - tail - 1) % LEPP_QUEUE_SIZE, but without using a slow % operation.
+ */
+ return (head - tail - 1) + ((head <= tail) ? LEPP_COMP_QUEUE_SIZE : 0);
+}
+
+
+/** Returns how many new comp entries can be enqueued. */
+static inline unsigned int
+lepp_num_free_comp_slots(const lepp_queue_t* q)
+{
+ return _lepp_num_free_slots(q->comp_head, q->comp_tail);
+}
+
+static inline int
+lepp_qsub(int v1, int v2)
+{
+ int delta = v1 - v2;
+ return delta + ((delta >> 31) & LEPP_COMP_QUEUE_SIZE);
+}
+
+
+/** FIXME: Check this from linux, via a new "pwrite()" call. */
+#define LIPP_VERSION 1
+
+
+/** We use exactly two bytes of alignment padding. */
+#define LIPP_PACKET_PADDING 2
+
+/** The minimum size of a "small" buffer (including the padding). */
+#define LIPP_SMALL_PACKET_SIZE 128
+
+/*
+ * NOTE: The following two values should total to less than around
+ * 13582, to keep the total size used for "lipp_state_t" below 64K.
+ */
+
+/** The maximum number of "small" buffers.
+ * This is enough for 53 network cpus with 128 credits. Note that
+ * if these are exhausted, we will fall back to using large buffers.
+ */
+#define LIPP_SMALL_BUFFERS 6785
+
+/** The maximum number of "large" buffers.
+ * This is enough for 53 network cpus with 128 credits.
+ */
+#define LIPP_LARGE_BUFFERS 6785
+
+#endif /* __DRV_XGBE_INTF_H__ */
--- /dev/null
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/**
+ * Error codes returned from NetIO routines.
+ */
+
+#ifndef __NETIO_ERRORS_H__
+#define __NETIO_ERRORS_H__
+
+/**
+ * @addtogroup error
+ *
+ * @brief The error codes returned by NetIO functions.
+ *
+ * NetIO functions return 0 (defined as ::NETIO_NO_ERROR) on success, and
+ * a negative value if an error occurs.
+ *
+ * In cases where a NetIO function failed due to a error reported by
+ * system libraries, the error code will be the negation of the
+ * system errno at the time of failure. The @ref netio_strerror()
+ * function will deliver error strings for both NetIO and system error
+ * codes.
+ *
+ * @{
+ */
+
+/** The set of all NetIO errors. */
+typedef enum
+{
+ /** Operation successfully completed. */
+ NETIO_NO_ERROR = 0,
+
+ /** A packet was successfully retrieved from an input queue. */
+ NETIO_PKT = 0,
+
+ /** Largest NetIO error number. */
+ NETIO_ERR_MAX = -701,
+
+ /** The tile is not registered with the IPP. */
+ NETIO_NOT_REGISTERED = -701,
+
+ /** No packet was available to retrieve from the input queue. */
+ NETIO_NOPKT = -702,
+
+ /** The requested function is not implemented. */
+ NETIO_NOT_IMPLEMENTED = -703,
+
+ /** On a registration operation, the target queue already has the maximum
+ * number of tiles registered for it, and no more may be added. On a
+ * packet send operation, the output queue is full and nothing more can
+ * be queued until some of the queued packets are actually transmitted. */
+ NETIO_QUEUE_FULL = -704,
+
+ /** The calling process or thread is not bound to exactly one CPU. */
+ NETIO_BAD_AFFINITY = -705,
+
+ /** Cannot allocate memory on requested controllers. */
+ NETIO_CANNOT_HOME = -706,
+
+ /** On a registration operation, the IPP specified is not configured
+ * to support the options requested; for instance, the application
+ * wants a specific type of tagged headers which the configured IPP
+ * doesn't support. Or, the supplied configuration information is
+ * not self-consistent, or is out of range; for instance, specifying
+ * both NETIO_RECV and NETIO_NO_RECV, or asking for more than
+ * NETIO_MAX_SEND_BUFFERS to be preallocated. On a VLAN or bucket
+ * configure operation, the number of items, or the base item, was
+ * out of range.
+ */
+ NETIO_BAD_CONFIG = -707,
+
+ /** Too many tiles have registered to transmit packets. */
+ NETIO_TOOMANY_XMIT = -708,
+
+ /** Packet transmission was attempted on a queue which was registered
+ with transmit disabled. */
+ NETIO_UNREG_XMIT = -709,
+
+ /** This tile is already registered with the IPP. */
+ NETIO_ALREADY_REGISTERED = -710,
+
+ /** The Ethernet link is down. The application should try again later. */
+ NETIO_LINK_DOWN = -711,
+
+ /** An invalid memory buffer has been specified. This may be an unmapped
+ * virtual address, or one which does not meet alignment requirements.
+ * For netio_input_register(), this error may be returned when multiple
+ * processes specify different memory regions to be used for NetIO
+ * buffers. That can happen if these processes specify explicit memory
+ * regions with the ::NETIO_FIXED_BUFFER_VA flag, or if tmc_cmem_init()
+ * has not been called by a common ancestor of the processes.
+ */
+ NETIO_FAULT = -712,
+
+ /** Cannot combine user-managed shared memory and cache coherence. */
+ NETIO_BAD_CACHE_CONFIG = -713,
+
+ /** Smallest NetIO error number. */
+ NETIO_ERR_MIN = -713,
+
+#ifndef __DOXYGEN__
+ /** Used internally to mean that no response is needed; never returned to
+ * an application. */
+ NETIO_NO_RESPONSE = 1
+#endif
+} netio_error_t;
+
+/** @} */
+
+#endif /* __NETIO_ERRORS_H__ */
--- /dev/null
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/**
+ * NetIO interface structures and macros.
+ */
+
+#ifndef __NETIO_INTF_H__
+#define __NETIO_INTF_H__
+
+#include <hv/netio_errors.h>
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
+#if !defined(__HV__) && !defined(__BOGUX__) && !defined(__KERNEL__)
+#include <assert.h>
+#define netio_assert assert /**< Enable assertions from macros */
+#else
+#define netio_assert(...) ((void)(0)) /**< Disable assertions from macros */
+#endif
+
+/*
+ * If none of these symbols are defined, we're building libnetio in an
+ * environment where we have pthreads, so we'll enable locking.
+ */
+#if !defined(__HV__) && !defined(__BOGUX__) && !defined(__KERNEL__) && \
+ !defined(__NEWLIB__)
+#define _NETIO_PTHREAD /**< Include a mutex in netio_queue_t below */
+
+/*
+ * If NETIO_UNLOCKED is defined, we don't do use per-cpu locks on
+ * per-packet NetIO operations. We still do pthread locking on things
+ * like netio_input_register, though. This is used for building
+ * libnetio_unlocked.
+ */
+#ifndef NETIO_UNLOCKED
+
+/* Avoid PLT overhead by using our own inlined per-cpu lock. */
+#include <sched.h>
+typedef int _netio_percpu_mutex_t;
+
+static __inline int
+_netio_percpu_mutex_init(_netio_percpu_mutex_t* lock)
+{
+ *lock = 0;
+ return 0;
+}
+
+static __inline int
+_netio_percpu_mutex_lock(_netio_percpu_mutex_t* lock)
+{
+ while (__builtin_expect(__insn_tns(lock), 0))
+ sched_yield();
+ return 0;
+}
+
+static __inline int
+_netio_percpu_mutex_unlock(_netio_percpu_mutex_t* lock)
+{
+ *lock = 0;
+ return 0;
+}
+
+#else /* NETIO_UNLOCKED */
+
+/* Don't do any locking for per-packet NetIO operations. */
+typedef int _netio_percpu_mutex_t;
+#define _netio_percpu_mutex_init(L)
+#define _netio_percpu_mutex_lock(L)
+#define _netio_percpu_mutex_unlock(L)
+
+#endif /* NETIO_UNLOCKED */
+#endif /* !__HV__, !__BOGUX, !__KERNEL__, !__NEWLIB__ */
+
+/** How many tiles can register for a given queue.
+ * @ingroup setup */
+#define NETIO_MAX_TILES_PER_QUEUE 64
+
+
+/** Largest permissible queue identifier.
+ * @ingroup setup */
+#define NETIO_MAX_QUEUE_ID 255
+
+
+#ifndef __DOXYGEN__
+
+/* Metadata packet checksum/ethertype flags. */
+
+/** The L4 checksum has not been calculated. */
+#define _NETIO_PKT_NO_L4_CSUM_SHIFT 0
+#define _NETIO_PKT_NO_L4_CSUM_RMASK 1
+#define _NETIO_PKT_NO_L4_CSUM_MASK \
+ (_NETIO_PKT_NO_L4_CSUM_RMASK << _NETIO_PKT_NO_L4_CSUM_SHIFT)
+
+/** The L3 checksum has not been calculated. */
+#define _NETIO_PKT_NO_L3_CSUM_SHIFT 1
+#define _NETIO_PKT_NO_L3_CSUM_RMASK 1
+#define _NETIO_PKT_NO_L3_CSUM_MASK \
+ (_NETIO_PKT_NO_L3_CSUM_RMASK << _NETIO_PKT_NO_L3_CSUM_SHIFT)
+
+/** The L3 checksum is incorrect (or perhaps has not been calculated). */
+#define _NETIO_PKT_BAD_L3_CSUM_SHIFT 2
+#define _NETIO_PKT_BAD_L3_CSUM_RMASK 1
+#define _NETIO_PKT_BAD_L3_CSUM_MASK \
+ (_NETIO_PKT_BAD_L3_CSUM_RMASK << _NETIO_PKT_BAD_L3_CSUM_SHIFT)
+
+/** The Ethernet packet type is unrecognized. */
+#define _NETIO_PKT_TYPE_UNRECOGNIZED_SHIFT 3
+#define _NETIO_PKT_TYPE_UNRECOGNIZED_RMASK 1
+#define _NETIO_PKT_TYPE_UNRECOGNIZED_MASK \
+ (_NETIO_PKT_TYPE_UNRECOGNIZED_RMASK << \
+ _NETIO_PKT_TYPE_UNRECOGNIZED_SHIFT)
+
+/* Metadata packet type flags. */
+
+/** Where the packet type bits are; this field is the index into
+ * _netio_pkt_info. */
+#define _NETIO_PKT_TYPE_SHIFT 4
+#define _NETIO_PKT_TYPE_RMASK 0x3F
+
+/** How many VLAN tags the packet has, and, if we have two, which one we
+ * actually grouped on. A VLAN within a proprietary (Marvell or Broadcom)
+ * tag is counted here. */
+#define _NETIO_PKT_VLAN_SHIFT 4
+#define _NETIO_PKT_VLAN_RMASK 0x3
+#define _NETIO_PKT_VLAN_MASK \
+ (_NETIO_PKT_VLAN_RMASK << _NETIO_PKT_VLAN_SHIFT)
+#define _NETIO_PKT_VLAN_NONE 0 /* No VLAN tag. */
+#define _NETIO_PKT_VLAN_ONE 1 /* One VLAN tag. */
+#define _NETIO_PKT_VLAN_TWO_OUTER 2 /* Two VLAN tags, outer one used. */
+#define _NETIO_PKT_VLAN_TWO_INNER 3 /* Two VLAN tags, inner one used. */
+
+/** Which proprietary tags the packet has. */
+#define _NETIO_PKT_TAG_SHIFT 6
+#define _NETIO_PKT_TAG_RMASK 0x3
+#define _NETIO_PKT_TAG_MASK \
+ (_NETIO_PKT_TAG_RMASK << _NETIO_PKT_TAG_SHIFT)
+#define _NETIO_PKT_TAG_NONE 0 /* No proprietary tags. */
+#define _NETIO_PKT_TAG_MRVL 1 /* Marvell HyperG.Stack tags. */
+#define _NETIO_PKT_TAG_MRVL_EXT 2 /* HyperG.Stack extended tags. */
+#define _NETIO_PKT_TAG_BRCM 3 /* Broadcom HiGig tags. */
+
+/** Whether a packet has an LLC + SNAP header. */
+#define _NETIO_PKT_SNAP_SHIFT 8
+#define _NETIO_PKT_SNAP_RMASK 0x1
+#define _NETIO_PKT_SNAP_MASK \
+ (_NETIO_PKT_SNAP_RMASK << _NETIO_PKT_SNAP_SHIFT)
+
+/* NOTE: Bits 9 and 10 are unused. */
+
+/** Length of any custom data before the L2 header, in words. */
+#define _NETIO_PKT_CUSTOM_LEN_SHIFT 11
+#define _NETIO_PKT_CUSTOM_LEN_RMASK 0x1F
+#define _NETIO_PKT_CUSTOM_LEN_MASK \
+ (_NETIO_PKT_CUSTOM_LEN_RMASK << _NETIO_PKT_CUSTOM_LEN_SHIFT)
+
+/** The L4 checksum is incorrect (or perhaps has not been calculated). */
+#define _NETIO_PKT_BAD_L4_CSUM_SHIFT 16
+#define _NETIO_PKT_BAD_L4_CSUM_RMASK 0x1
+#define _NETIO_PKT_BAD_L4_CSUM_MASK \
+ (_NETIO_PKT_BAD_L4_CSUM_RMASK << _NETIO_PKT_BAD_L4_CSUM_SHIFT)
+
+/** Length of the L2 header, in words. */
+#define _NETIO_PKT_L2_LEN_SHIFT 17
+#define _NETIO_PKT_L2_LEN_RMASK 0x1F
+#define _NETIO_PKT_L2_LEN_MASK \
+ (_NETIO_PKT_L2_LEN_RMASK << _NETIO_PKT_L2_LEN_SHIFT)
+
+
+/* Flags in minimal packet metadata. */
+
+/** We need an eDMA checksum on this packet. */
+#define _NETIO_PKT_NEED_EDMA_CSUM_SHIFT 0
+#define _NETIO_PKT_NEED_EDMA_CSUM_RMASK 1
+#define _NETIO_PKT_NEED_EDMA_CSUM_MASK \
+ (_NETIO_PKT_NEED_EDMA_CSUM_RMASK << _NETIO_PKT_NEED_EDMA_CSUM_SHIFT)
+
+/* Data within the packet information table. */
+
+/* Note that, for efficiency, code which uses these fields assumes that none
+ * of the shift values below are zero. See uses below for an explanation. */
+
+/** Offset within the L2 header of the innermost ethertype (in halfwords). */
+#define _NETIO_PKT_INFO_ETYPE_SHIFT 6
+#define _NETIO_PKT_INFO_ETYPE_RMASK 0x1F
+
+/** Offset within the L2 header of the VLAN tag (in halfwords). */
+#define _NETIO_PKT_INFO_VLAN_SHIFT 11
+#define _NETIO_PKT_INFO_VLAN_RMASK 0x1F
+
+#endif
+
+
+/** The size of a memory buffer representing a small packet.
+ * @ingroup egress */
+#define SMALL_PACKET_SIZE 256
+
+/** The size of a memory buffer representing a large packet.
+ * @ingroup egress */
+#define LARGE_PACKET_SIZE 2048
+
+/** The size of a memory buffer representing a jumbo packet.
+ * @ingroup egress */
+#define JUMBO_PACKET_SIZE (12 * 1024)
+
+
+/* Common ethertypes.
+ * @ingroup ingress */
+/** @{ */
+/** The ethertype of IPv4. */
+#define ETHERTYPE_IPv4 (0x0800)
+/** The ethertype of ARP. */
+#define ETHERTYPE_ARP (0x0806)
+/** The ethertype of VLANs. */
+#define ETHERTYPE_VLAN (0x8100)
+/** The ethertype of a Q-in-Q header. */
+#define ETHERTYPE_Q_IN_Q (0x9100)
+/** The ethertype of IPv6. */
+#define ETHERTYPE_IPv6 (0x86DD)
+/** The ethertype of MPLS. */
+#define ETHERTYPE_MPLS (0x8847)
+/** @} */
+
+
+/** The possible return values of NETIO_PKT_STATUS.
+ * @ingroup ingress
+ */
+typedef enum
+{
+ /** No problems were detected with this packet. */
+ NETIO_PKT_STATUS_OK,
+ /** The packet is undersized; this is expected behavior if the packet's
+ * ethertype is unrecognized, but otherwise the packet is likely corrupt. */
+ NETIO_PKT_STATUS_UNDERSIZE,
+ /** The packet is oversized and some trailing bytes have been discarded.
+ This is expected behavior for short packets, since it's impossible to
+ precisely determine the amount of padding which may have been added to
+ them to make them meet the minimum Ethernet packet size. */
+ NETIO_PKT_STATUS_OVERSIZE,
+ /** The packet was judged to be corrupt by hardware (for instance, it had
+ a bad CRC, or part of it was discarded due to lack of buffer space in
+ the I/O shim) and should be discarded. */
+ NETIO_PKT_STATUS_BAD
+} netio_pkt_status_t;
+
+
+/** Log2 of how many buckets we have. */
+#define NETIO_LOG2_NUM_BUCKETS (10)
+
+/** How many buckets we have.
+ * @ingroup ingress */
+#define NETIO_NUM_BUCKETS (1 << NETIO_LOG2_NUM_BUCKETS)
+
+
+/**
+ * @brief A group-to-bucket identifier.
+ *
+ * @ingroup setup
+ *
+ * This tells us what to do with a given group.
+ */
+typedef union {
+ /** The header broken down into bits. */
+ struct {
+ /** Whether we should balance on L4, if available */
+ unsigned int __balance_on_l4:1;
+ /** Whether we should balance on L3, if available */
+ unsigned int __balance_on_l3:1;
+ /** Whether we should balance on L2, if available */
+ unsigned int __balance_on_l2:1;
+ /** Reserved for future use */
+ unsigned int __reserved:1;
+ /** The base bucket to use to send traffic */
+ unsigned int __bucket_base:NETIO_LOG2_NUM_BUCKETS;
+ /** The mask to apply to the balancing value. This must be one less
+ * than a power of two, e.g. 0x3 or 0xFF.
+ */
+ unsigned int __bucket_mask:NETIO_LOG2_NUM_BUCKETS;
+ /** Pad to 32 bits */
+ unsigned int __padding:(32 - 4 - 2 * NETIO_LOG2_NUM_BUCKETS);
+ } bits;
+ /** To send out the IDN. */
+ unsigned int word;
+}
+netio_group_t;
+
+
+/**
+ * @brief A VLAN-to-bucket identifier.
+ *
+ * @ingroup setup
+ *
+ * This tells us what to do with a given VLAN.
+ */
+typedef netio_group_t netio_vlan_t;
+
+
+/**
+ * A bucket-to-queue mapping.
+ * @ingroup setup
+ */
+typedef unsigned char netio_bucket_t;
+
+
+/**
+ * A packet size can always fit in a netio_size_t.
+ * @ingroup setup
+ */
+typedef unsigned int netio_size_t;
+
+
+/**
+ * @brief Ethernet standard (ingress) packet metadata.
+ *
+ * @ingroup ingress
+ *
+ * This is additional data associated with each packet.
+ * This structure is opaque and accessed through the @ref ingress.
+ *
+ * Also, the buffer population operation currently assumes that standard
+ * metadata is at least as large as minimal metadata, and will need to be
+ * modified if that is no longer the case.
+ */
+typedef struct
+{
+#ifdef __DOXYGEN__
+ /** This structure is opaque. */
+ unsigned char opaque[24];
+#else
+ /** The overall ordinal of the packet */
+ unsigned int __packet_ordinal;
+ /** The ordinal of the packet within the group */
+ unsigned int __group_ordinal;
+ /** The best flow hash IPP could compute. */
+ unsigned int __flow_hash;
+ /** Flags pertaining to checksum calculation, packet type, etc. */
+ unsigned int __flags;
+ /** The first word of "user data". */
+ unsigned int __user_data_0;
+ /** The second word of "user data". */
+ unsigned int __user_data_1;
+#endif
+}
+netio_pkt_metadata_t;
+
+
+/** To ensure that the L3 header is aligned mod 4, the L2 header should be
+ * aligned mod 4 plus 2, since every supported L2 header is 4n + 2 bytes
+ * long. The standard way to do this is to simply add 2 bytes of padding
+ * before the L2 header.
+ */
+#define NETIO_PACKET_PADDING 2
+
+
+
+/**
+ * @brief Ethernet minimal (egress) packet metadata.
+ *
+ * @ingroup egress
+ *
+ * This structure represents information about packets which have
+ * been processed by @ref netio_populate_buffer() or
+ * @ref netio_populate_prepend_buffer(). This structure is opaque
+ * and accessed through the @ref egress.
+ *
+ * @internal This structure is actually copied into the memory used by
+ * standard metadata, which is assumed to be large enough.
+ */
+typedef struct
+{
+#ifdef __DOXYGEN__
+ /** This structure is opaque. */
+ unsigned char opaque[14];
+#else
+ /** The offset of the L2 header from the start of the packet data. */
+ unsigned short l2_offset;
+ /** The offset of the L3 header from the start of the packet data. */
+ unsigned short l3_offset;
+ /** Where to write the checksum. */
+ unsigned char csum_location;
+ /** Where to start checksumming from. */
+ unsigned char csum_start;
+ /** Flags pertaining to checksum calculation etc. */
+ unsigned short flags;
+ /** The L2 length of the packet. */
+ unsigned short l2_length;
+ /** The checksum with which to seed the checksum generator. */
+ unsigned short csum_seed;
+ /** How much to checksum. */
+ unsigned short csum_length;
+#endif
+}
+netio_pkt_minimal_metadata_t;
+
+
+#ifndef __DOXYGEN__
+
+/**
+ * @brief An I/O notification header.
+ *
+ * This is the first word of data received from an I/O shim in a notification
+ * packet. It contains framing and status information.
+ */
+typedef union
+{
+ unsigned int word; /**< The whole word. */
+ /** The various fields. */
+ struct
+ {
+ unsigned int __channel:7; /**< Resource channel. */
+ unsigned int __type:4; /**< Type. */
+ unsigned int __ack:1; /**< Whether an acknowledgement is needed. */
+ unsigned int __reserved:1; /**< Reserved. */
+ unsigned int __protocol:1; /**< A protocol-specific word is added. */
+ unsigned int __status:2; /**< Status of the transfer. */
+ unsigned int __framing:2; /**< Framing of the transfer. */
+ unsigned int __transfer_size:14; /**< Transfer size in bytes (total). */
+ } bits;
+}
+__netio_pkt_notif_t;
+
+
+/**
+ * Returns the base address of the packet.
+ */
+#define _NETIO_PKT_HANDLE_BASE(p) \
+ ((unsigned char*)((p).word & 0xFFFFFFC0))
+
+/**
+ * Returns the base address of the packet.
+ */
+#define _NETIO_PKT_BASE(p) \
+ _NETIO_PKT_HANDLE_BASE(p->__packet)
+
+/**
+ * @brief An I/O notification packet (second word)
+ *
+ * This is the second word of data received from an I/O shim in a notification
+ * packet. This is the virtual address of the packet buffer, plus some flag
+ * bits. (The virtual address of the packet is always 256-byte aligned so we
+ * have room for 8 bits' worth of flags in the low 8 bits.)
+ *
+ * @internal
+ * NOTE: The low two bits must contain "__queue", so the "packet size"
+ * (SIZE_SMALL, SIZE_LARGE, or SIZE_JUMBO) can be determined quickly.
+ *
+ * If __addr or __offset are moved, _NETIO_PKT_BASE
+ * (defined right below this) must be changed.
+ */
+typedef union
+{
+ unsigned int word; /**< The whole word. */
+ /** The various fields. */
+ struct
+ {
+ /** Which queue the packet will be returned to once it is sent back to
+ the IPP. This is one of the SIZE_xxx values. */
+ unsigned int __queue:2;
+
+ /** The IPP handle of the sending IPP. */
+ unsigned int __ipp_handle:2;
+
+ /** Reserved for future use. */
+ unsigned int __reserved:1;
+
+ /** If 1, this packet has minimal (egress) metadata; otherwise, it
+ has standard (ingress) metadata. */
+ unsigned int __minimal:1;
+
+ /** Offset of the metadata within the packet. This value is multiplied
+ * by 64 and added to the base packet address to get the metadata
+ * address. Note that this field is aligned within the word such that
+ * you can easily extract the metadata address with a 26-bit mask. */
+ unsigned int __offset:2;
+
+ /** The top 24 bits of the packet's virtual address. */
+ unsigned int __addr:24;
+ } bits;
+}
+__netio_pkt_handle_t;
+
+#endif /* !__DOXYGEN__ */
+
+
+/**
+ * @brief A handle for an I/O packet's storage.
+ * @ingroup ingress
+ *
+ * netio_pkt_handle_t encodes the concept of a ::netio_pkt_t with its
+ * packet metadata removed. It is a much smaller type that exists to
+ * facilitate applications where the full ::netio_pkt_t type is too
+ * large, such as those that cache enormous numbers of packets or wish
+ * to transmit packet descriptors over the UDN.
+ *
+ * Because there is no metadata, most ::netio_pkt_t operations cannot be
+ * performed on a netio_pkt_handle_t. It supports only
+ * netio_free_handle() (to free the buffer) and
+ * NETIO_PKT_CUSTOM_DATA_H() (to access a pointer to its contents).
+ * The application must acquire any additional metadata it wants from the
+ * original ::netio_pkt_t and record it separately.
+ *
+ * A netio_pkt_handle_t can be extracted from a ::netio_pkt_t by calling
+ * NETIO_PKT_HANDLE(). An invalid handle (analogous to NULL) can be
+ * created by assigning the value ::NETIO_PKT_HANDLE_NONE. A handle can
+ * be tested for validity with NETIO_PKT_HANDLE_IS_VALID().
+ */
+typedef struct
+{
+ unsigned int word; /**< Opaque bits. */
+} netio_pkt_handle_t;
+
+/**
+ * @brief A packet descriptor.
+ *
+ * @ingroup ingress
+ * @ingroup egress
+ *
+ * This data structure represents a packet. The structure is manipulated
+ * through the @ref ingress and the @ref egress.
+ *
+ * While the contents of a netio_pkt_t are opaque, the structure itself is
+ * portable. This means that it may be shared between all tiles which have
+ * done a netio_input_register() call for the interface on which the pkt_t
+ * was initially received (via netio_get_packet()) or retrieved (via
+ * netio_get_buffer()). The contents of a netio_pkt_t can be transmitted to
+ * another tile via shared memory, or via a UDN message, or by other means.
+ * The destination tile may then use the pkt_t as if it had originally been
+ * received locally; it may read or write the packet's data, read its
+ * metadata, free the packet, send the packet, transfer the netio_pkt_t to
+ * yet another tile, and so forth.
+ *
+ * Once a netio_pkt_t has been transferred to a second tile, the first tile
+ * should not reference the original copy; in particular, if more than one
+ * tile frees or sends the same netio_pkt_t, the IPP's packet free lists will
+ * become corrupted. Note also that each tile which reads or modifies
+ * packet data must obey the memory coherency rules outlined in @ref input.
+ */
+typedef struct
+{
+#ifdef __DOXYGEN__
+ /** This structure is opaque. */
+ unsigned char opaque[32];
+#else
+ /** For an ingress packet (one with standard metadata), this is the
+ * notification header we got from the I/O shim. For an egress packet
+ * (one with minimal metadata), this word is zero if the packet has not
+ * been populated, and nonzero if it has. */
+ __netio_pkt_notif_t __notif_header;
+
+ /** Virtual address of the packet buffer, plus state flags. */
+ __netio_pkt_handle_t __packet;
+
+ /** Metadata associated with the packet. */
+ netio_pkt_metadata_t __metadata;
+#endif
+}
+netio_pkt_t;
+
+
+#ifndef __DOXYGEN__
+
+#define __NETIO_PKT_NOTIF_HEADER(pkt) ((pkt)->__notif_header)
+#define __NETIO_PKT_IPP_HANDLE(pkt) ((pkt)->__packet.bits.__ipp_handle)
+#define __NETIO_PKT_QUEUE(pkt) ((pkt)->__packet.bits.__queue)
+#define __NETIO_PKT_NOTIF_HEADER_M(mda, pkt) ((pkt)->__notif_header)
+#define __NETIO_PKT_IPP_HANDLE_M(mda, pkt) ((pkt)->__packet.bits.__ipp_handle)
+#define __NETIO_PKT_MINIMAL(pkt) ((pkt)->__packet.bits.__minimal)
+#define __NETIO_PKT_QUEUE_M(mda, pkt) ((pkt)->__packet.bits.__queue)
+#define __NETIO_PKT_FLAGS_M(mda, pkt) ((mda)->__flags)
+
+/* Packet information table, used by the attribute access functions below. */
+extern const uint16_t _netio_pkt_info[];
+
+#endif /* __DOXYGEN__ */
+
+
+#ifndef __DOXYGEN__
+/* These macros are deprecated and will disappear in a future MDE release. */
+#define NETIO_PKT_GOOD_CHECKSUM(pkt) \
+ NETIO_PKT_L4_CSUM_CORRECT(pkt)
+#define NETIO_PKT_GOOD_CHECKSUM_M(mda, pkt) \
+ NETIO_PKT_L4_CSUM_CORRECT_M(mda, pkt)
+#endif /* __DOXYGEN__ */
+
+
+/* Packet attribute access functions. */
+
+/** Return a pointer to the metadata for a packet.
+ * @ingroup ingress
+ *
+ * Calling this function once and passing the result to other retrieval
+ * functions with a "_M" suffix usually improves performance. This
+ * function must be called on an 'ingress' packet (i.e. one retrieved
+ * by @ref netio_get_packet(), on which @ref netio_populate_buffer() or
+ * @ref netio_populate_prepend_buffer have not been called). Use of this
+ * function on an 'egress' packet will cause an assertion failure.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to the packet's standard metadata.
+ */
+static __inline netio_pkt_metadata_t*
+NETIO_PKT_METADATA(netio_pkt_t* pkt)
+{
+ netio_assert(!pkt->__packet.bits.__minimal);
+ return &pkt->__metadata;
+}
+
+
+/** Return a pointer to the minimal metadata for a packet.
+ * @ingroup egress
+ *
+ * Calling this function once and passing the result to other retrieval
+ * functions with a "_MM" suffix usually improves performance. This
+ * function must be called on an 'egress' packet (i.e. one on which
+ * @ref netio_populate_buffer() or @ref netio_populate_prepend_buffer()
+ * have been called, or one retrieved by @ref netio_get_buffer()). Use of
+ * this function on an 'ingress' packet will cause an assertion failure.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to the packet's standard metadata.
+ */
+static __inline netio_pkt_minimal_metadata_t*
+NETIO_PKT_MINIMAL_METADATA(netio_pkt_t* pkt)
+{
+ netio_assert(pkt->__packet.bits.__minimal);
+ return (netio_pkt_minimal_metadata_t*) &pkt->__metadata;
+}
+
+
+/** Determine whether a packet has 'minimal' metadata.
+ * @ingroup pktfuncs
+ *
+ * This function will return nonzero if the packet is an 'egress'
+ * packet (i.e. one on which @ref netio_populate_buffer() or
+ * @ref netio_populate_prepend_buffer() have been called, or one
+ * retrieved by @ref netio_get_buffer()), and zero if the packet
+ * is an 'ingress' packet (i.e. one retrieved by @ref netio_get_packet(),
+ * which has not been converted into an 'egress' packet).
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the packet has minimal metadata.
+ */
+static __inline unsigned int
+NETIO_PKT_IS_MINIMAL(netio_pkt_t* pkt)
+{
+ return pkt->__packet.bits.__minimal;
+}
+
+
+/** Return a handle for a packet's storage.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A handle for the packet's storage.
+ */
+static __inline netio_pkt_handle_t
+NETIO_PKT_HANDLE(netio_pkt_t* pkt)
+{
+ netio_pkt_handle_t h;
+ h.word = pkt->__packet.word;
+ return h;
+}
+
+
+/** A special reserved value indicating the absence of a packet handle.
+ *
+ * @ingroup pktfuncs
+ */
+#define NETIO_PKT_HANDLE_NONE ((netio_pkt_handle_t) { 0 })
+
+
+/** Test whether a packet handle is valid.
+ *
+ * Applications may wish to use the reserved value NETIO_PKT_HANDLE_NONE
+ * to indicate no packet at all. This function tests to see if a packet
+ * handle is a real handle, not this special reserved value.
+ *
+ * @ingroup pktfuncs
+ *
+ * @param[in] handle Handle on which to operate.
+ * @return One if the packet handle is valid, else zero.
+ */
+static __inline unsigned int
+NETIO_PKT_HANDLE_IS_VALID(netio_pkt_handle_t handle)
+{
+ return handle.word != 0;
+}
+
+
+
+/** Return a pointer to the start of the packet's custom header.
+ * A custom header may or may not be present, depending upon the IPP; its
+ * contents and alignment are also IPP-dependent. Currently, none of the
+ * standard IPPs supplied by Tilera produce a custom header. If present,
+ * the custom header precedes the L2 header in the packet buffer.
+ * @ingroup ingress
+ *
+ * @param[in] handle Handle on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_CUSTOM_DATA_H(netio_pkt_handle_t handle)
+{
+ return _NETIO_PKT_HANDLE_BASE(handle) + NETIO_PACKET_PADDING;
+}
+
+
+/** Return the length of the packet's custom header.
+ * A custom header may or may not be present, depending upon the IPP; its
+ * contents and alignment are also IPP-dependent. Currently, none of the
+ * standard IPPs supplied by Tilera produce a custom header. If present,
+ * the custom header precedes the L2 header in the packet buffer.
+ *
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet's custom header, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_CUSTOM_HEADER_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ /*
+ * Note that we effectively need to extract a quantity from the flags word
+ * which is measured in words, and then turn it into bytes by shifting
+ * it left by 2. We do this all at once by just shifting right two less
+ * bits, and shifting the mask up two bits.
+ */
+ return ((mda->__flags >> (_NETIO_PKT_CUSTOM_LEN_SHIFT - 2)) &
+ (_NETIO_PKT_CUSTOM_LEN_RMASK << 2));
+}
+
+
+/** Return the length of the packet, starting with the custom header.
+ * A custom header may or may not be present, depending upon the IPP; its
+ * contents and alignment are also IPP-dependent. Currently, none of the
+ * standard IPPs supplied by Tilera produce a custom header. If present,
+ * the custom header precedes the L2 header in the packet buffer.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_CUSTOM_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return (__NETIO_PKT_NOTIF_HEADER(pkt).bits.__transfer_size -
+ NETIO_PACKET_PADDING);
+}
+
+
+/** Return a pointer to the start of the packet's custom header.
+ * A custom header may or may not be present, depending upon the IPP; its
+ * contents and alignment are also IPP-dependent. Currently, none of the
+ * standard IPPs supplied by Tilera produce a custom header. If present,
+ * the custom header precedes the L2 header in the packet buffer.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_CUSTOM_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return NETIO_PKT_CUSTOM_DATA_H(NETIO_PKT_HANDLE(pkt));
+}
+
+
+/** Return the length of the packet's L2 (Ethernet plus VLAN or SNAP) header.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet's L2 header, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_HEADER_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ /*
+ * Note that we effectively need to extract a quantity from the flags word
+ * which is measured in words, and then turn it into bytes by shifting
+ * it left by 2. We do this all at once by just shifting right two less
+ * bits, and shifting the mask up two bits. We then add two bytes.
+ */
+ return ((mda->__flags >> (_NETIO_PKT_L2_LEN_SHIFT - 2)) &
+ (_NETIO_PKT_L2_LEN_RMASK << 2)) + 2;
+}
+
+
+/** Return the length of the packet, starting with the L2 (Ethernet) header.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return (NETIO_PKT_CUSTOM_LENGTH_M(mda, pkt) -
+ NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda,pkt));
+}
+
+
+/** Return a pointer to the start of the packet's L2 (Ethernet) header.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_L2_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return (NETIO_PKT_CUSTOM_DATA_M(mda, pkt) +
+ NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt));
+}
+
+
+/** Retrieve the length of the packet, starting with the L3 (generally,
+ * the IP) header.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Length of the packet's L3 header and data, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L3_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return (NETIO_PKT_L2_LENGTH_M(mda, pkt) -
+ NETIO_PKT_L2_HEADER_LENGTH_M(mda,pkt));
+}
+
+
+/** Return a pointer to the packet's L3 (generally, the IP) header.
+ * @ingroup ingress
+ *
+ * Note that we guarantee word alignment of the L3 header.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to the packet's L3 header.
+ */
+static __inline unsigned char*
+NETIO_PKT_L3_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return (NETIO_PKT_L2_DATA_M(mda, pkt) +
+ NETIO_PKT_L2_HEADER_LENGTH_M(mda, pkt));
+}
+
+
+/** Return the ordinal of the packet.
+ * @ingroup ingress
+ *
+ * Each packet is given an ordinal number when it is delivered by the IPP.
+ * In the medium term, the ordinal is unique and monotonically increasing,
+ * being incremented by 1 for each packet; the ordinal of the first packet
+ * delivered after the IPP starts is zero. (Since the ordinal is of finite
+ * size, given enough input packets, it will eventually wrap around to zero;
+ * in the long term, therefore, ordinals are not unique.) The ordinals
+ * handed out by different IPPs are not disjoint, so two packets from
+ * different IPPs may have identical ordinals. Packets dropped by the
+ * IPP or by the I/O shim are not assigned ordinals.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's per-IPP packet ordinal.
+ */
+static __inline unsigned int
+NETIO_PKT_ORDINAL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return mda->__packet_ordinal;
+}
+
+
+/** Return the per-group ordinal of the packet.
+ * @ingroup ingress
+ *
+ * Each packet is given a per-group ordinal number when it is
+ * delivered by the IPP. By default, the group is the packet's VLAN,
+ * although IPP can be recompiled to use different values. In
+ * the medium term, the ordinal is unique and monotonically
+ * increasing, being incremented by 1 for each packet; the ordinal of
+ * the first packet distributed to a particular group is zero.
+ * (Since the ordinal is of finite size, given enough input packets,
+ * it will eventually wrap around to zero; in the long term,
+ * therefore, ordinals are not unique.) The ordinals handed out by
+ * different IPPs are not disjoint, so two packets from different IPPs
+ * may have identical ordinals; similarly, packets distributed to
+ * different groups may have identical ordinals. Packets dropped by
+ * the IPP or by the I/O shim are not assigned ordinals.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's per-IPP, per-group ordinal.
+ */
+static __inline unsigned int
+NETIO_PKT_GROUP_ORDINAL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return mda->__group_ordinal;
+}
+
+
+/** Return the VLAN ID assigned to the packet.
+ * @ingroup ingress
+ *
+ * This value is usually contained within the packet header.
+ *
+ * This value will be zero if the packet does not have a VLAN tag, or if
+ * this value was not extracted from the packet.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's VLAN ID.
+ */
+static __inline unsigned short
+NETIO_PKT_VLAN_ID_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ int vl = (mda->__flags >> _NETIO_PKT_VLAN_SHIFT) & _NETIO_PKT_VLAN_RMASK;
+ unsigned short* pkt_p;
+ int index;
+ unsigned short val;
+
+ if (vl == _NETIO_PKT_VLAN_NONE)
+ return 0;
+
+ pkt_p = (unsigned short*) NETIO_PKT_L2_DATA_M(mda, pkt);
+ index = (mda->__flags >> _NETIO_PKT_TYPE_SHIFT) & _NETIO_PKT_TYPE_RMASK;
+
+ val = pkt_p[(_netio_pkt_info[index] >> _NETIO_PKT_INFO_VLAN_SHIFT) &
+ _NETIO_PKT_INFO_VLAN_RMASK];
+
+#ifdef __TILECC__
+ return (__insn_bytex(val) >> 16) & 0xFFF;
+#else
+ return (__builtin_bswap32(val) >> 16) & 0xFFF;
+#endif
+}
+
+
+/** Return the ethertype of the packet.
+ * @ingroup ingress
+ *
+ * This value is usually contained within the packet header.
+ *
+ * This value is reliable if @ref NETIO_PKT_ETHERTYPE_RECOGNIZED_M()
+ * returns true, and otherwise, may not be well defined.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's ethertype.
+ */
+static __inline unsigned short
+NETIO_PKT_ETHERTYPE_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ unsigned short* pkt_p = (unsigned short*) NETIO_PKT_L2_DATA_M(mda, pkt);
+ int index = (mda->__flags >> _NETIO_PKT_TYPE_SHIFT) & _NETIO_PKT_TYPE_RMASK;
+
+ unsigned short val =
+ pkt_p[(_netio_pkt_info[index] >> _NETIO_PKT_INFO_ETYPE_SHIFT) &
+ _NETIO_PKT_INFO_ETYPE_RMASK];
+
+ return __builtin_bswap32(val) >> 16;
+}
+
+
+/** Return the flow hash computed on the packet.
+ * @ingroup ingress
+ *
+ * For TCP and UDP packets, this hash is calculated by hashing together
+ * the "5-tuple" values, specifically the source IP address, destination
+ * IP address, protocol type, source port and destination port.
+ * The hash value is intended to be helpful for millions of distinct
+ * flows.
+ *
+ * For IPv4 or IPv6 packets which are neither TCP nor UDP, the flow hash is
+ * derived by hashing together the source and destination IP addresses.
+ *
+ * For MPLS-encapsulated packets, the flow hash is derived by hashing
+ * the first MPLS label.
+ *
+ * For all other packets the flow hash is computed from the source
+ * and destination Ethernet addresses.
+ *
+ * The hash is symmetric, meaning it produces the same value if the
+ * source and destination are swapped. The only exceptions are
+ * tunneling protocols 0x04 (IP in IP Encapsulation), 0x29 (Simple
+ * Internet Protocol), 0x2F (General Routing Encapsulation) and 0x32
+ * (Encap Security Payload), which use only the destination address
+ * since the source address is not meaningful.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's 32-bit flow hash.
+ */
+static __inline unsigned int
+NETIO_PKT_FLOW_HASH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return mda->__flow_hash;
+}
+
+
+/** Return the first word of "user data" for the packet.
+ *
+ * The contents of the user data words depend on the IPP.
+ *
+ * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the first
+ * word of user data contains the least significant bits of the 64-bit
+ * arrival cycle count (see @c get_cycle_count_low()).
+ *
+ * See the <em>System Programmer's Guide</em> for details.
+ *
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's first word of "user data".
+ */
+static __inline unsigned int
+NETIO_PKT_USER_DATA_0_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return mda->__user_data_0;
+}
+
+
+/** Return the second word of "user data" for the packet.
+ *
+ * The contents of the user data words depend on the IPP.
+ *
+ * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the second
+ * word of user data contains the most significant bits of the 64-bit
+ * arrival cycle count (see @c get_cycle_count_high()).
+ *
+ * See the <em>System Programmer's Guide</em> for details.
+ *
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's second word of "user data".
+ */
+static __inline unsigned int
+NETIO_PKT_USER_DATA_1_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return mda->__user_data_1;
+}
+
+
+/** Determine whether the L4 (TCP/UDP) checksum was calculated.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the L4 checksum was calculated.
+ */
+static __inline unsigned int
+NETIO_PKT_L4_CSUM_CALCULATED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return !(mda->__flags & _NETIO_PKT_NO_L4_CSUM_MASK);
+}
+
+
+/** Determine whether the L4 (TCP/UDP) checksum was calculated and found to
+ * be correct.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the checksum was calculated and is correct.
+ */
+static __inline unsigned int
+NETIO_PKT_L4_CSUM_CORRECT_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return !(mda->__flags &
+ (_NETIO_PKT_BAD_L4_CSUM_MASK | _NETIO_PKT_NO_L4_CSUM_MASK));
+}
+
+
+/** Determine whether the L3 (IP) checksum was calculated.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the L3 (IP) checksum was calculated.
+*/
+static __inline unsigned int
+NETIO_PKT_L3_CSUM_CALCULATED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return !(mda->__flags & _NETIO_PKT_NO_L3_CSUM_MASK);
+}
+
+
+/** Determine whether the L3 (IP) checksum was calculated and found to be
+ * correct.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the checksum was calculated and is correct.
+ */
+static __inline unsigned int
+NETIO_PKT_L3_CSUM_CORRECT_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return !(mda->__flags &
+ (_NETIO_PKT_BAD_L3_CSUM_MASK | _NETIO_PKT_NO_L3_CSUM_MASK));
+}
+
+
+/** Determine whether the ethertype was recognized and L3 packet data was
+ * processed.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the ethertype was recognized and L3 packet data was
+ * processed.
+ */
+static __inline unsigned int
+NETIO_PKT_ETHERTYPE_RECOGNIZED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return !(mda->__flags & _NETIO_PKT_TYPE_UNRECOGNIZED_MASK);
+}
+
+
+/** Retrieve the status of a packet and any errors that may have occurred
+ * during ingress processing (length mismatches, CRC errors, etc.).
+ * @ingroup ingress
+ *
+ * Note that packets for which @ref NETIO_PKT_ETHERTYPE_RECOGNIZED()
+ * returns zero are always reported as underlength, as there is no a priori
+ * means to determine their length. Normally, applications should use
+ * @ref NETIO_PKT_BAD_M() instead of explicitly checking status with this
+ * function.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's status.
+ */
+static __inline netio_pkt_status_t
+NETIO_PKT_STATUS_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return (netio_pkt_status_t) __NETIO_PKT_NOTIF_HEADER(pkt).bits.__status;
+}
+
+
+/** Report whether a packet is bad (i.e., was shorter than expected based on
+ * its headers, or had a bad CRC).
+ * @ingroup ingress
+ *
+ * Note that this function does not verify L3 or L4 checksums.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the packet is bad and should be discarded.
+ */
+static __inline unsigned int
+NETIO_PKT_BAD_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return ((NETIO_PKT_STATUS_M(mda, pkt) & 1) &&
+ (NETIO_PKT_ETHERTYPE_RECOGNIZED_M(mda, pkt) ||
+ NETIO_PKT_STATUS_M(mda, pkt) == NETIO_PKT_STATUS_BAD));
+}
+
+
+/** Return the length of the packet, starting with the L2 (Ethernet) header.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt)
+{
+ return mmd->l2_length;
+}
+
+
+/** Return the length of the L2 (Ethernet) header.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet's L2 header, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_HEADER_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd,
+ netio_pkt_t* pkt)
+{
+ return mmd->l3_offset - mmd->l2_offset;
+}
+
+
+/** Return the length of the packet, starting with the L3 (IP) header.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Length of the packet's L3 header and data, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L3_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt)
+{
+ return (NETIO_PKT_L2_LENGTH_MM(mmd, pkt) -
+ NETIO_PKT_L2_HEADER_LENGTH_MM(mmd, pkt));
+}
+
+
+/** Return a pointer to the packet's L3 (generally, the IP) header.
+ * @ingroup egress
+ *
+ * Note that we guarantee word alignment of the L3 header.
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to the packet's L3 header.
+ */
+static __inline unsigned char*
+NETIO_PKT_L3_DATA_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt)
+{
+ return _NETIO_PKT_BASE(pkt) + mmd->l3_offset;
+}
+
+
+/** Return a pointer to the packet's L2 (Ethernet) header.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_L2_DATA_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt)
+{
+ return _NETIO_PKT_BASE(pkt) + mmd->l2_offset;
+}
+
+
+/** Retrieve the status of a packet and any errors that may have occurred
+ * during ingress processing (length mismatches, CRC errors, etc.).
+ * @ingroup ingress
+ *
+ * Note that packets for which @ref NETIO_PKT_ETHERTYPE_RECOGNIZED()
+ * returns zero are always reported as underlength, as there is no a priori
+ * means to determine their length. Normally, applications should use
+ * @ref NETIO_PKT_BAD() instead of explicitly checking status with this
+ * function.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's status.
+ */
+static __inline netio_pkt_status_t
+NETIO_PKT_STATUS(netio_pkt_t* pkt)
+{
+ netio_assert(!pkt->__packet.bits.__minimal);
+
+ return (netio_pkt_status_t) __NETIO_PKT_NOTIF_HEADER(pkt).bits.__status;
+}
+
+
+/** Report whether a packet is bad (i.e., was shorter than expected based on
+ * its headers, or had a bad CRC).
+ * @ingroup ingress
+ *
+ * Note that this function does not verify L3 or L4 checksums.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the packet is bad and should be discarded.
+ */
+static __inline unsigned int
+NETIO_PKT_BAD(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_BAD_M(mda, pkt);
+}
+
+
+/** Return the length of the packet's custom header.
+ * A custom header may or may not be present, depending upon the IPP; its
+ * contents and alignment are also IPP-dependent. Currently, none of the
+ * standard IPPs supplied by Tilera produce a custom header. If present,
+ * the custom header precedes the L2 header in the packet buffer.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet's custom header, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_CUSTOM_HEADER_LENGTH(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt);
+}
+
+
+/** Return the length of the packet, starting with the custom header.
+ * A custom header may or may not be present, depending upon the IPP; its
+ * contents and alignment are also IPP-dependent. Currently, none of the
+ * standard IPPs supplied by Tilera produce a custom header. If present,
+ * the custom header precedes the L2 header in the packet buffer.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_CUSTOM_LENGTH(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_CUSTOM_LENGTH_M(mda, pkt);
+}
+
+
+/** Return a pointer to the packet's custom header.
+ * A custom header may or may not be present, depending upon the IPP; its
+ * contents and alignment are also IPP-dependent. Currently, none of the
+ * standard IPPs supplied by Tilera produce a custom header. If present,
+ * the custom header precedes the L2 header in the packet buffer.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_CUSTOM_DATA(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_CUSTOM_DATA_M(mda, pkt);
+}
+
+
+/** Return the length of the packet's L2 (Ethernet plus VLAN or SNAP) header.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet's L2 header, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_HEADER_LENGTH(netio_pkt_t* pkt)
+{
+ if (NETIO_PKT_IS_MINIMAL(pkt))
+ {
+ netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+ return NETIO_PKT_L2_HEADER_LENGTH_MM(mmd, pkt);
+ }
+ else
+ {
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_L2_HEADER_LENGTH_M(mda, pkt);
+ }
+}
+
+
+/** Return the length of the packet, starting with the L2 (Ethernet) header.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_LENGTH(netio_pkt_t* pkt)
+{
+ if (NETIO_PKT_IS_MINIMAL(pkt))
+ {
+ netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+ return NETIO_PKT_L2_LENGTH_MM(mmd, pkt);
+ }
+ else
+ {
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_L2_LENGTH_M(mda, pkt);
+ }
+}
+
+
+/** Return a pointer to the packet's L2 (Ethernet) header.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_L2_DATA(netio_pkt_t* pkt)
+{
+ if (NETIO_PKT_IS_MINIMAL(pkt))
+ {
+ netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+ return NETIO_PKT_L2_DATA_MM(mmd, pkt);
+ }
+ else
+ {
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_L2_DATA_M(mda, pkt);
+ }
+}
+
+
+/** Retrieve the length of the packet, starting with the L3 (generally, the IP)
+ * header.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Length of the packet's L3 header and data, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L3_LENGTH(netio_pkt_t* pkt)
+{
+ if (NETIO_PKT_IS_MINIMAL(pkt))
+ {
+ netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+ return NETIO_PKT_L3_LENGTH_MM(mmd, pkt);
+ }
+ else
+ {
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_L3_LENGTH_M(mda, pkt);
+ }
+}
+
+
+/** Return a pointer to the packet's L3 (generally, the IP) header.
+ * @ingroup pktfuncs
+ *
+ * Note that we guarantee word alignment of the L3 header.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to the packet's L3 header.
+ */
+static __inline unsigned char*
+NETIO_PKT_L3_DATA(netio_pkt_t* pkt)
+{
+ if (NETIO_PKT_IS_MINIMAL(pkt))
+ {
+ netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+ return NETIO_PKT_L3_DATA_MM(mmd, pkt);
+ }
+ else
+ {
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_L3_DATA_M(mda, pkt);
+ }
+}
+
+
+/** Return the ordinal of the packet.
+ * @ingroup ingress
+ *
+ * Each packet is given an ordinal number when it is delivered by the IPP.
+ * In the medium term, the ordinal is unique and monotonically increasing,
+ * being incremented by 1 for each packet; the ordinal of the first packet
+ * delivered after the IPP starts is zero. (Since the ordinal is of finite
+ * size, given enough input packets, it will eventually wrap around to zero;
+ * in the long term, therefore, ordinals are not unique.) The ordinals
+ * handed out by different IPPs are not disjoint, so two packets from
+ * different IPPs may have identical ordinals. Packets dropped by the
+ * IPP or by the I/O shim are not assigned ordinals.
+ *
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's per-IPP packet ordinal.
+ */
+static __inline unsigned int
+NETIO_PKT_ORDINAL(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_ORDINAL_M(mda, pkt);
+}
+
+
+/** Return the per-group ordinal of the packet.
+ * @ingroup ingress
+ *
+ * Each packet is given a per-group ordinal number when it is
+ * delivered by the IPP. By default, the group is the packet's VLAN,
+ * although IPP can be recompiled to use different values. In
+ * the medium term, the ordinal is unique and monotonically
+ * increasing, being incremented by 1 for each packet; the ordinal of
+ * the first packet distributed to a particular group is zero.
+ * (Since the ordinal is of finite size, given enough input packets,
+ * it will eventually wrap around to zero; in the long term,
+ * therefore, ordinals are not unique.) The ordinals handed out by
+ * different IPPs are not disjoint, so two packets from different IPPs
+ * may have identical ordinals; similarly, packets distributed to
+ * different groups may have identical ordinals. Packets dropped by
+ * the IPP or by the I/O shim are not assigned ordinals.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's per-IPP, per-group ordinal.
+ */
+static __inline unsigned int
+NETIO_PKT_GROUP_ORDINAL(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_GROUP_ORDINAL_M(mda, pkt);
+}
+
+
+/** Return the VLAN ID assigned to the packet.
+ * @ingroup ingress
+ *
+ * This is usually also contained within the packet header. If the packet
+ * does not have a VLAN tag, the VLAN ID returned by this function is zero.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's VLAN ID.
+ */
+static __inline unsigned short
+NETIO_PKT_VLAN_ID(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_VLAN_ID_M(mda, pkt);
+}
+
+
+/** Return the ethertype of the packet.
+ * @ingroup ingress
+ *
+ * This value is reliable if @ref NETIO_PKT_ETHERTYPE_RECOGNIZED()
+ * returns true, and otherwise, may not be well defined.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's ethertype.
+ */
+static __inline unsigned short
+NETIO_PKT_ETHERTYPE(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_ETHERTYPE_M(mda, pkt);
+}
+
+
+/** Return the flow hash computed on the packet.
+ * @ingroup ingress
+ *
+ * For TCP and UDP packets, this hash is calculated by hashing together
+ * the "5-tuple" values, specifically the source IP address, destination
+ * IP address, protocol type, source port and destination port.
+ * The hash value is intended to be helpful for millions of distinct
+ * flows.
+ *
+ * For IPv4 or IPv6 packets which are neither TCP nor UDP, the flow hash is
+ * derived by hashing together the source and destination IP addresses.
+ *
+ * For MPLS-encapsulated packets, the flow hash is derived by hashing
+ * the first MPLS label.
+ *
+ * For all other packets the flow hash is computed from the source
+ * and destination Ethernet addresses.
+ *
+ * The hash is symmetric, meaning it produces the same value if the
+ * source and destination are swapped. The only exceptions are
+ * tunneling protocols 0x04 (IP in IP Encapsulation), 0x29 (Simple
+ * Internet Protocol), 0x2F (General Routing Encapsulation) and 0x32
+ * (Encap Security Payload), which use only the destination address
+ * since the source address is not meaningful.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's 32-bit flow hash.
+ */
+static __inline unsigned int
+NETIO_PKT_FLOW_HASH(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_FLOW_HASH_M(mda, pkt);
+}
+
+
+/** Return the first word of "user data" for the packet.
+ *
+ * The contents of the user data words depend on the IPP.
+ *
+ * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the first
+ * word of user data contains the least significant bits of the 64-bit
+ * arrival cycle count (see @c get_cycle_count_low()).
+ *
+ * See the <em>System Programmer's Guide</em> for details.
+ *
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's first word of "user data".
+ */
+static __inline unsigned int
+NETIO_PKT_USER_DATA_0(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_USER_DATA_0_M(mda, pkt);
+}
+
+
+/** Return the second word of "user data" for the packet.
+ *
+ * The contents of the user data words depend on the IPP.
+ *
+ * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the second
+ * word of user data contains the most significant bits of the 64-bit
+ * arrival cycle count (see @c get_cycle_count_high()).
+ *
+ * See the <em>System Programmer's Guide</em> for details.
+ *
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's second word of "user data".
+ */
+static __inline unsigned int
+NETIO_PKT_USER_DATA_1(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_USER_DATA_1_M(mda, pkt);
+}
+
+
+/** Determine whether the L4 (TCP/UDP) checksum was calculated.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the L4 checksum was calculated.
+ */
+static __inline unsigned int
+NETIO_PKT_L4_CSUM_CALCULATED(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_L4_CSUM_CALCULATED_M(mda, pkt);
+}
+
+
+/** Determine whether the L4 (TCP/UDP) checksum was calculated and found to
+ * be correct.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the checksum was calculated and is correct.
+ */
+static __inline unsigned int
+NETIO_PKT_L4_CSUM_CORRECT(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_L4_CSUM_CORRECT_M(mda, pkt);
+}
+
+
+/** Determine whether the L3 (IP) checksum was calculated.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the L3 (IP) checksum was calculated.
+*/
+static __inline unsigned int
+NETIO_PKT_L3_CSUM_CALCULATED(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_L3_CSUM_CALCULATED_M(mda, pkt);
+}
+
+
+/** Determine whether the L3 (IP) checksum was calculated and found to be
+ * correct.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the checksum was calculated and is correct.
+ */
+static __inline unsigned int
+NETIO_PKT_L3_CSUM_CORRECT(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_L3_CSUM_CORRECT_M(mda, pkt);
+}
+
+
+/** Determine whether the Ethertype was recognized and L3 packet data was
+ * processed.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the Ethertype was recognized and L3 packet data was
+ * processed.
+ */
+static __inline unsigned int
+NETIO_PKT_ETHERTYPE_RECOGNIZED(netio_pkt_t* pkt)
+{
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_ETHERTYPE_RECOGNIZED_M(mda, pkt);
+}
+
+
+/** Set an egress packet's L2 length, using a metadata pointer to speed the
+ * computation.
+ * @ingroup egress
+ *
+ * @param[in,out] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @param[in] len Packet L2 length, in bytes.
+ */
+static __inline void
+NETIO_PKT_SET_L2_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt,
+ int len)
+{
+ mmd->l2_length = len;
+}
+
+
+/** Set an egress packet's L2 length.
+ * @ingroup egress
+ *
+ * @param[in,out] pkt Packet on which to operate.
+ * @param[in] len Packet L2 length, in bytes.
+ */
+static __inline void
+NETIO_PKT_SET_L2_LENGTH(netio_pkt_t* pkt, int len)
+{
+ netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+ NETIO_PKT_SET_L2_LENGTH_MM(mmd, pkt, len);
+}
+
+
+/** Set an egress packet's L2 header length, using a metadata pointer to
+ * speed the computation.
+ * @ingroup egress
+ *
+ * It is not normally necessary to call this routine; only the L2 length,
+ * not the header length, is needed to transmit a packet. It may be useful if
+ * the egress packet will later be processed by code which expects to use
+ * functions like @ref NETIO_PKT_L3_DATA() to get a pointer to the L3 payload.
+ *
+ * @param[in,out] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @param[in] len Packet L2 header length, in bytes.
+ */
+static __inline void
+NETIO_PKT_SET_L2_HEADER_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd,
+ netio_pkt_t* pkt, int len)
+{
+ mmd->l3_offset = mmd->l2_offset + len;
+}
+
+
+/** Set an egress packet's L2 header length.
+ * @ingroup egress
+ *
+ * It is not normally necessary to call this routine; only the L2 length,
+ * not the header length, is needed to transmit a packet. It may be useful if
+ * the egress packet will later be processed by code which expects to use
+ * functions like @ref NETIO_PKT_L3_DATA() to get a pointer to the L3 payload.
+ *
+ * @param[in,out] pkt Packet on which to operate.
+ * @param[in] len Packet L2 header length, in bytes.
+ */
+static __inline void
+NETIO_PKT_SET_L2_HEADER_LENGTH(netio_pkt_t* pkt, int len)
+{
+ netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+ NETIO_PKT_SET_L2_HEADER_LENGTH_MM(mmd, pkt, len);
+}
+
+
+/** Set up an egress packet for hardware checksum computation, using a
+ * metadata pointer to speed the operation.
+ * @ingroup egress
+ *
+ * NetIO provides the ability to automatically calculate a standard
+ * 16-bit Internet checksum on transmitted packets. The application
+ * may specify the point in the packet where the checksum starts, the
+ * number of bytes to be checksummed, and the two bytes in the packet
+ * which will be replaced with the completed checksum. (If the range
+ * of bytes to be checksummed includes the bytes to be replaced, the
+ * initial values of those bytes will be included in the checksum.)
+ *
+ * For some protocols, the packet checksum covers data which is not present
+ * in the packet, or is at least not contiguous to the main data payload.
+ * For instance, the TCP checksum includes a "pseudo-header" which includes
+ * the source and destination IP addresses of the packet. To accommodate
+ * this, the checksum engine may be "seeded" with an initial value, which
+ * the application would need to compute based on the specific protocol's
+ * requirements. Note that the seed is given in host byte order (little-
+ * endian), not network byte order (big-endian); code written to compute a
+ * pseudo-header checksum in network byte order will need to byte-swap it
+ * before use as the seed.
+ *
+ * Note that the checksum is computed as part of the transmission process,
+ * so it will not be present in the packet upon completion of this routine.
+ *
+ * @param[in,out] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @param[in] start Offset within L2 packet of the first byte to include in
+ * the checksum.
+ * @param[in] length Number of bytes to include in the checksum.
+ * the checksum.
+ * @param[in] location Offset within L2 packet of the first of the two bytes
+ * to be replaced with the calculated checksum.
+ * @param[in] seed Initial value of the running checksum before any of the
+ * packet data is added.
+ */
+static __inline void
+NETIO_PKT_DO_EGRESS_CSUM_MM(netio_pkt_minimal_metadata_t* mmd,
+ netio_pkt_t* pkt, int start, int length,
+ int location, uint16_t seed)
+{
+ mmd->csum_start = start;
+ mmd->csum_length = length;
+ mmd->csum_location = location;
+ mmd->csum_seed = seed;
+ mmd->flags |= _NETIO_PKT_NEED_EDMA_CSUM_MASK;
+}
+
+
+/** Set up an egress packet for hardware checksum computation.
+ * @ingroup egress
+ *
+ * NetIO provides the ability to automatically calculate a standard
+ * 16-bit Internet checksum on transmitted packets. The application
+ * may specify the point in the packet where the checksum starts, the
+ * number of bytes to be checksummed, and the two bytes in the packet
+ * which will be replaced with the completed checksum. (If the range
+ * of bytes to be checksummed includes the bytes to be replaced, the
+ * initial values of those bytes will be included in the checksum.)
+ *
+ * For some protocols, the packet checksum covers data which is not present
+ * in the packet, or is at least not contiguous to the main data payload.
+ * For instance, the TCP checksum includes a "pseudo-header" which includes
+ * the source and destination IP addresses of the packet. To accommodate
+ * this, the checksum engine may be "seeded" with an initial value, which
+ * the application would need to compute based on the specific protocol's
+ * requirements. Note that the seed is given in host byte order (little-
+ * endian), not network byte order (big-endian); code written to compute a
+ * pseudo-header checksum in network byte order will need to byte-swap it
+ * before use as the seed.
+ *
+ * Note that the checksum is computed as part of the transmission process,
+ * so it will not be present in the packet upon completion of this routine.
+ *
+ * @param[in,out] pkt Packet on which to operate.
+ * @param[in] start Offset within L2 packet of the first byte to include in
+ * the checksum.
+ * @param[in] length Number of bytes to include in the checksum.
+ * the checksum.
+ * @param[in] location Offset within L2 packet of the first of the two bytes
+ * to be replaced with the calculated checksum.
+ * @param[in] seed Initial value of the running checksum before any of the
+ * packet data is added.
+ */
+static __inline void
+NETIO_PKT_DO_EGRESS_CSUM(netio_pkt_t* pkt, int start, int length,
+ int location, uint16_t seed)
+{
+ netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+ NETIO_PKT_DO_EGRESS_CSUM_MM(mmd, pkt, start, length, location, seed);
+}
+
+
+/** Return the number of bytes which could be prepended to a packet, using a
+ * metadata pointer to speed the operation.
+ * See @ref netio_populate_prepend_buffer() to get a full description of
+ * prepending.
+ *
+ * @param[in,out] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline int
+NETIO_PKT_PREPEND_AVAIL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+ return (pkt->__packet.bits.__offset << 6) +
+ NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt);
+}
+
+
+/** Return the number of bytes which could be prepended to a packet, using a
+ * metadata pointer to speed the operation.
+ * See @ref netio_populate_prepend_buffer() to get a full description of
+ * prepending.
+ * @ingroup egress
+ *
+ * @param[in,out] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline int
+NETIO_PKT_PREPEND_AVAIL_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt)
+{
+ return (pkt->__packet.bits.__offset << 6) + mmd->l2_offset;
+}
+
+
+/** Return the number of bytes which could be prepended to a packet.
+ * See @ref netio_populate_prepend_buffer() to get a full description of
+ * prepending.
+ * @ingroup egress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline int
+NETIO_PKT_PREPEND_AVAIL(netio_pkt_t* pkt)
+{
+ if (NETIO_PKT_IS_MINIMAL(pkt))
+ {
+ netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+ return NETIO_PKT_PREPEND_AVAIL_MM(mmd, pkt);
+ }
+ else
+ {
+ netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+ return NETIO_PKT_PREPEND_AVAIL_M(mda, pkt);
+ }
+}
+
+
+/** Flush a packet's minimal metadata from the cache, using a metadata pointer
+ * to speed the operation.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd,
+ netio_pkt_t* pkt)
+{
+}
+
+
+/** Invalidate a packet's minimal metadata from the cache, using a metadata
+ * pointer to speed the operation.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_INV_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd,
+ netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush and then invalidate a packet's minimal metadata from the cache,
+ * using a metadata pointer to speed the operation.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_INV_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd,
+ netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush a packet's metadata from the cache, using a metadata pointer
+ * to speed the operation.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+}
+
+
+/** Invalidate a packet's metadata from the cache, using a metadata
+ * pointer to speed the operation.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_INV_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush and then invalidate a packet's metadata from the cache,
+ * using a metadata pointer to speed the operation.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_INV_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush a packet's minimal metadata from the cache.
+ * @ingroup egress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_MINIMAL_METADATA(netio_pkt_t* pkt)
+{
+}
+
+
+/** Invalidate a packet's minimal metadata from the cache.
+ * @ingroup egress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_INV_MINIMAL_METADATA(netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush and then invalidate a packet's minimal metadata from the cache.
+ * @ingroup egress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_INV_MINIMAL_METADATA(netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush a packet's metadata from the cache.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_METADATA(netio_pkt_t* pkt)
+{
+}
+
+
+/** Invalidate a packet's metadata from the cache.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_INV_METADATA(netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush and then invalidate a packet's metadata from the cache.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_INV_METADATA(netio_pkt_t* pkt)
+{
+}
+
+/** Number of NUMA nodes we can distribute buffers to.
+ * @ingroup setup */
+#define NETIO_NUM_NODE_WEIGHTS 16
+
+/**
+ * @brief An object for specifying the characteristics of NetIO communication
+ * endpoint.
+ *
+ * @ingroup setup
+ *
+ * The @ref netio_input_register() function uses this structure to define
+ * how an application tile will communicate with an IPP.
+ *
+ *
+ * Future updates to NetIO may add new members to this structure,
+ * which can affect the success of the registration operation. Thus,
+ * if dynamically initializing the structure, applications are urged to
+ * zero it out first, for example:
+ *
+ * @code
+ * netio_input_config_t config;
+ * memset(&config, 0, sizeof (config));
+ * config.flags = NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE;
+ * config.num_receive_packets = NETIO_MAX_RECEIVE_PKTS;
+ * config.queue_id = 0;
+ * .
+ * .
+ * .
+ * @endcode
+ *
+ * since that guarantees that any unused structure members, including
+ * members which did not exist when the application was first developed,
+ * will not have unexpected values.
+ *
+ * If statically initializing the structure, we strongly recommend use of
+ * C99-style named initializers, for example:
+ *
+ * @code
+ * netio_input_config_t config = {
+ * .flags = NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE,
+ * .num_receive_packets = NETIO_MAX_RECEIVE_PKTS,
+ * .queue_id = 0,
+ * },
+ * @endcode
+ *
+ * instead of the old-style structure initialization:
+ *
+ * @code
+ * // Bad example! Currently equivalent to the above, but don't do this.
+ * netio_input_config_t config = {
+ * NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE, NETIO_MAX_RECEIVE_PKTS, 0
+ * },
+ * @endcode
+ *
+ * since the C99 style requires no changes to the code if elements of the
+ * config structure are rearranged. (It also makes the initialization much
+ * easier to understand.)
+ *
+ * Except for items which address a particular tile's transmit or receive
+ * characteristics, such as the ::NETIO_RECV flag, applications are advised
+ * to specify the same set of configuration data on all registrations.
+ * This prevents differing results if multiple tiles happen to do their
+ * registration operations in a different order on different invocations of
+ * the application. This is particularly important for things like link
+ * management flags, and buffer size and homing specifications.
+ *
+ * Unless the ::NETIO_FIXED_BUFFER_VA flag is specified in flags, the NetIO
+ * buffer pool is automatically created and mapped into the application's
+ * virtual address space at an address chosen by the operating system,
+ * using the common memory (cmem) facility in the Tilera Multicore
+ * Components library. The cmem facility allows multiple processes to gain
+ * access to shared memory which is mapped into each process at an
+ * identical virtual address. In order for this to work, the processes
+ * must have a common ancestor, which must create the common memory using
+ * tmc_cmem_init().
+ *
+ * In programs using the iLib process creation API, or in programs which use
+ * only one process (which include programs using the pthreads library),
+ * tmc_cmem_init() is called automatically. All other applications
+ * must call it explicitly, before any child processes which might call
+ * netio_input_register() are created.
+ */
+typedef struct
+{
+ /** Registration characteristics.
+
+ This value determines several characteristics of the registration;
+ flags for different types of behavior are ORed together to make the
+ final flag value. Generally applications should specify exactly
+ one flag from each of the following categories:
+
+ - Whether the application will be receiving packets on this queue
+ (::NETIO_RECV or ::NETIO_NO_RECV).
+
+ - Whether the application will be transmitting packets on this queue,
+ and if so, whether it will request egress checksum calculation
+ (::NETIO_XMIT, ::NETIO_XMIT_CSUM, or ::NETIO_NO_XMIT). It is
+ legal to call netio_get_buffer() without one of the XMIT flags,
+ as long as ::NETIO_RECV is specified; in this case, the retrieved
+ buffers must be passed to another tile for transmission.
+
+ - Whether the application expects any vendor-specific tags in
+ its packets' L2 headers (::NETIO_TAG_NONE, ::NETIO_TAG_BRCM,
+ or ::NETIO_TAG_MRVL). This must match the configuration of the
+ target IPP.
+
+ To accommodate applications written to previous versions of the NetIO
+ interface, none of the flags above are currently required; if omitted,
+ NetIO behaves more or less as if ::NETIO_RECV | ::NETIO_XMIT_CSUM |
+ ::NETIO_TAG_NONE were used. However, explicit specification of
+ the relevant flags allows NetIO to do a better job of resource
+ allocation, allows earlier detection of certain configuration errors,
+ and may enable advanced features or higher performance in the future,
+ so their use is strongly recommended.
+
+ Note that specifying ::NETIO_NO_RECV along with ::NETIO_NO_XMIT
+ is a special case, intended primarily for use by programs which
+ retrieve network statistics or do link management operations.
+ When these flags are both specified, the resulting queue may not
+ be used with NetIO routines other than netio_get(), netio_set(),
+ and netio_input_unregister(). See @ref link for more information
+ on link management.
+
+ Other flags are optional; their use is described below.
+ */
+ int flags;
+
+ /** Interface name. This is a string which identifies the specific
+ Ethernet controller hardware to be used. The format of the string
+ is a device type and a device index, separated by a slash; so,
+ the first 10 Gigabit Ethernet controller is named "xgbe/0", while
+ the second 10/100/1000 Megabit Ethernet controller is named "gbe/1".
+ */
+ const char* interface;
+
+ /** Receive packet queue size. This specifies the maximum number
+ of ingress packets that can be received on this queue without
+ being retrieved by @ref netio_get_packet(). If the IPP's distribution
+ algorithm calls for a packet to be sent to this queue, and this
+ number of packets are already pending there, the new packet
+ will either be discarded, or sent to another tile registered
+ for the same queue_id (see @ref drops). This value must
+ be at least ::NETIO_MIN_RECEIVE_PKTS, can always be at least
+ ::NETIO_MAX_RECEIVE_PKTS, and may be larger than that on certain
+ interfaces.
+ */
+ int num_receive_packets;
+
+ /** The queue ID being requested. Legal values for this range from 0
+ to ::NETIO_MAX_QUEUE_ID, inclusive. ::NETIO_MAX_QUEUE_ID is always
+ greater than or equal to the number of tiles; this allows one queue
+ for each tile, plus at least one additional queue. Some applications
+ may wish to use the additional queue as a destination for unwanted
+ packets, since packets delivered to queues for which no tiles have
+ registered are discarded.
+ */
+ unsigned int queue_id;
+
+ /** Maximum number of small send buffers to be held in the local empty
+ buffer cache. This specifies the size of the area which holds
+ empty small egress buffers requested from the IPP but not yet
+ retrieved via @ref netio_get_buffer(). This value must be greater
+ than zero if the application will ever use @ref netio_get_buffer()
+ to allocate empty small egress buffers; it may be no larger than
+ ::NETIO_MAX_SEND_BUFFERS. See @ref epp for more details on empty
+ buffer caching.
+ */
+ int num_send_buffers_small_total;
+
+ /** Number of small send buffers to be preallocated at registration.
+ If this value is nonzero, the specified number of empty small egress
+ buffers will be requested from the IPP during the netio_input_register
+ operation; this may speed the execution of @ref netio_get_buffer().
+ This may be no larger than @ref num_send_buffers_small_total. See @ref
+ epp for more details on empty buffer caching.
+ */
+ int num_send_buffers_small_prealloc;
+
+ /** Maximum number of large send buffers to be held in the local empty
+ buffer cache. This specifies the size of the area which holds empty
+ large egress buffers requested from the IPP but not yet retrieved via
+ @ref netio_get_buffer(). This value must be greater than zero if the
+ application will ever use @ref netio_get_buffer() to allocate empty
+ large egress buffers; it may be no larger than ::NETIO_MAX_SEND_BUFFERS.
+ See @ref epp for more details on empty buffer caching.
+ */
+ int num_send_buffers_large_total;
+
+ /** Number of large send buffers to be preallocated at registration.
+ If this value is nonzero, the specified number of empty large egress
+ buffers will be requested from the IPP during the netio_input_register
+ operation; this may speed the execution of @ref netio_get_buffer().
+ This may be no larger than @ref num_send_buffers_large_total. See @ref
+ epp for more details on empty buffer caching.
+ */
+ int num_send_buffers_large_prealloc;
+
+ /** Maximum number of jumbo send buffers to be held in the local empty
+ buffer cache. This specifies the size of the area which holds empty
+ jumbo egress buffers requested from the IPP but not yet retrieved via
+ @ref netio_get_buffer(). This value must be greater than zero if the
+ application will ever use @ref netio_get_buffer() to allocate empty
+ jumbo egress buffers; it may be no larger than ::NETIO_MAX_SEND_BUFFERS.
+ See @ref epp for more details on empty buffer caching.
+ */
+ int num_send_buffers_jumbo_total;
+
+ /** Number of jumbo send buffers to be preallocated at registration.
+ If this value is nonzero, the specified number of empty jumbo egress
+ buffers will be requested from the IPP during the netio_input_register
+ operation; this may speed the execution of @ref netio_get_buffer().
+ This may be no larger than @ref num_send_buffers_jumbo_total. See @ref
+ epp for more details on empty buffer caching.
+ */
+ int num_send_buffers_jumbo_prealloc;
+
+ /** Total packet buffer size. This determines the total size, in bytes,
+ of the NetIO buffer pool. Note that the maximum number of available
+ buffers of each size is determined during hypervisor configuration
+ (see the <em>System Programmer's Guide</em> for details); this just
+ influences how much host memory is allocated for those buffers.
+
+ The buffer pool is allocated from common memory, which will be
+ automatically initialized if needed. If your buffer pool is larger
+ than 240 MB, you might need to explicitly call @c tmc_cmem_init(),
+ as described in the Application Libraries Reference Manual (UG227).
+
+ Packet buffers are currently allocated in chunks of 16 MB; this
+ value will be rounded up to the next larger multiple of 16 MB.
+ If this value is zero, a default of 32 MB will be used; this was
+ the value used by previous versions of NetIO. Note that taking this
+ default also affects the placement of buffers on Linux NUMA nodes.
+ See @ref buffer_node_weights for an explanation of buffer placement.
+
+ In order to successfully allocate packet buffers, Linux must have
+ available huge pages on the relevant Linux NUMA nodes. See the
+ <em>System Programmer's Guide</em> for information on configuring
+ huge page support in Linux.
+ */
+ uint64_t total_buffer_size;
+
+ /** Buffer placement weighting factors.
+
+ This array specifies the relative amount of buffering to place
+ on each of the available Linux NUMA nodes. This array is
+ indexed by the NUMA node, and the values in the array are
+ proportional to the amount of buffer space to allocate on that
+ node.
+
+ If memory striping is enabled in the Hypervisor, then there is
+ only one logical NUMA node (node 0). In that case, NetIO will by
+ default ignore the suggested buffer node weights, and buffers
+ will be striped across the physical memory controllers. See
+ UG209 System Programmer's Guide for a description of the
+ hypervisor option that controls memory striping.
+
+ If memory striping is disabled, then there are up to four NUMA
+ nodes, corresponding to the four DDRAM controllers in the TILE
+ processor architecture. See UG100 Tile Processor Architecture
+ Overview for a diagram showing the location of each of the DDRAM
+ controllers relative to the tile array.
+
+ For instance, if memory striping is disabled, the following
+ configuration strucure:
+
+ @code
+ netio_input_config_t config = {
+ .
+ .
+ .
+ .total_buffer_size = 4 * 16 * 1024 * 1024;
+ .buffer_node_weights = { 1, 0, 1, 0 },
+ },
+ @endcode
+
+ would result in 32 MB of buffers being placed on controller 0, and
+ 32 MB on controller 2. (Since buffers are allocated in units of
+ 16 MB, some sets of weights will not be able to be matched exactly.)
+
+ For the weights to be effective, @ref total_buffer_size must be
+ nonzero. If @ref total_buffer_size is zero, causing the default
+ 32 MB of buffer space to be used, then any specified weights will
+ be ignored, and buffers will positioned as they were in previous
+ versions of NetIO:
+
+ - For xgbe/0 and gbe/0, 16 MB of buffers will be placed on controller 1,
+ and the other 16 MB will be placed on controller 2.
+
+ - For xgbe/1 and gbe/1, 16 MB of buffers will be placed on controller 2,
+ and the other 16 MB will be placed on controller 3.
+
+ If @ref total_buffer_size is nonzero, but all weights are zero,
+ then all buffer space will be allocated on Linux NUMA node zero.
+
+ By default, the specified buffer placement is treated as a hint;
+ if sufficient free memory is not available on the specified
+ controllers, the buffers will be allocated elsewhere. However,
+ if the ::NETIO_STRICT_HOMING flag is specified in @ref flags, then a
+ failure to allocate buffer space exactly as requested will cause the
+ registration operation to fail with an error of ::NETIO_CANNOT_HOME.
+
+ Note that maximal network performance cannot be achieved with
+ only one memory controller.
+ */
+ uint8_t buffer_node_weights[NETIO_NUM_NODE_WEIGHTS];
+
+ /** Fixed virtual address for packet buffers. Only valid when
+ ::NETIO_FIXED_BUFFER_VA is specified in @ref flags; see the
+ description of that flag for details.
+ */
+ void* fixed_buffer_va;
+
+ /**
+ Maximum number of outstanding send packet requests. This value is
+ only relevant when an EPP is in use; it determines the number of
+ slots in the EPP's outgoing packet queue which this tile is allowed
+ to consume, and thus the number of packets which may be sent before
+ the sending tile must wait for an acknowledgment from the EPP.
+ Modifying this value is generally only helpful when using @ref
+ netio_send_packet_vector(), where it can help improve performance by
+ allowing a single vector send operation to process more packets.
+ Typically it is not specified, and the default, which divides the
+ outgoing packet slots evenly between all tiles on the chip, is used.
+
+ If a registration asks for more outgoing packet queue slots than are
+ available, ::NETIO_TOOMANY_XMIT will be returned. The total number
+ of packet queue slots which are available for all tiles for each EPP
+ is subject to change, but is currently ::NETIO_TOTAL_SENDS_OUTSTANDING.
+
+
+ This value is ignored if ::NETIO_XMIT is not specified in flags.
+ If you want to specify a large value here for a specific tile, you are
+ advised to specify NETIO_NO_XMIT on other, non-transmitting tiles so
+ that they do not consume a default number of packet slots. Any tile
+ transmitting is required to have at least ::NETIO_MIN_SENDS_OUTSTANDING
+ slots allocated to it; values less than that will be silently
+ increased by the NetIO library.
+ */
+ int num_sends_outstanding;
+}
+netio_input_config_t;
+
+
+/** Registration flags; used in the @ref netio_input_config_t structure.
+ * @addtogroup setup
+ */
+/** @{ */
+
+/** Fail a registration request if we can't put packet buffers
+ on the specified memory controllers. */
+#define NETIO_STRICT_HOMING 0x00000002
+
+/** This application expects no tags on its L2 headers. */
+#define NETIO_TAG_NONE 0x00000004
+
+/** This application expects Marvell extended tags on its L2 headers. */
+#define NETIO_TAG_MRVL 0x00000008
+
+/** This application expects Broadcom tags on its L2 headers. */
+#define NETIO_TAG_BRCM 0x00000010
+
+/** This registration may call routines which receive packets. */
+#define NETIO_RECV 0x00000020
+
+/** This registration may not call routines which receive packets. */
+#define NETIO_NO_RECV 0x00000040
+
+/** This registration may call routines which transmit packets. */
+#define NETIO_XMIT 0x00000080
+
+/** This registration may call routines which transmit packets with
+ checksum acceleration. */
+#define NETIO_XMIT_CSUM 0x00000100
+
+/** This registration may not call routines which transmit packets. */
+#define NETIO_NO_XMIT 0x00000200
+
+/** This registration wants NetIO buffers mapped at an application-specified
+ virtual address.
+
+ NetIO buffers are by default created by the TMC common memory facility,
+ which must be configured by a common ancestor of all processes sharing
+ a network interface. When this flag is specified, NetIO buffers are
+ instead mapped at an address chosen by the application (and specified
+ in @ref netio_input_config_t::fixed_buffer_va). This allows multiple
+ unrelated but cooperating processes to share a NetIO interface.
+ All processes sharing the same interface must specify this flag,
+ and all must specify the same fixed virtual address.
+
+ @ref netio_input_config_t::fixed_buffer_va must be a
+ multiple of 16 MB, and the packet buffers will occupy @ref
+ netio_input_config_t::total_buffer_size bytes of virtual address
+ space, beginning at that address. If any of those virtual addresses
+ are currently occupied by other memory objects, like application or
+ shared library code or data, @ref netio_input_register() will return
+ ::NETIO_FAULT. While it is impossible to provide a fixed_buffer_va
+ which will work for all applications, a good first guess might be to
+ use 0xb0000000 minus @ref netio_input_config_t::total_buffer_size.
+ If that fails, it might be helpful to consult the running application's
+ virtual address description file (/proc/<em>pid</em>/maps) to see
+ which regions of virtual address space are available.
+ */
+#define NETIO_FIXED_BUFFER_VA 0x00000400
+
+/** This registration call will not complete unless the network link
+ is up. The process will wait several seconds for this to happen (the
+ precise interval is link-dependent), but if the link does not come up,
+ ::NETIO_LINK_DOWN will be returned. This flag is the default if
+ ::NETIO_NOREQUIRE_LINK_UP is not specified. Note that this flag by
+ itself does not request that the link be brought up; that can be done
+ with the ::NETIO_AUTO_LINK_UPDN or ::NETIO_AUTO_LINK_UP flags (the
+ latter is the default if no NETIO_AUTO_LINK_xxx flags are specified),
+ or by explicitly setting the link's desired state via netio_set().
+ If the link is not brought up by one of those methods, and this flag
+ is specified, the registration operation will return ::NETIO_LINK_DOWN.
+ This flag is ignored if it is specified along with ::NETIO_NO_XMIT and
+ ::NETIO_NO_RECV. See @ref link for more information on link
+ management.
+ */
+#define NETIO_REQUIRE_LINK_UP 0x00000800
+
+/** This registration call will complete even if the network link is not up.
+ Whenever the link is not up, packets will not be sent or received:
+ netio_get_packet() will return ::NETIO_NOPKT once all queued packets
+ have been drained, and netio_send_packet() and similar routines will
+ return NETIO_QUEUE_FULL once the outgoing packet queue in the EPP
+ or the I/O shim is full. See @ref link for more information on link
+ management.
+ */
+#define NETIO_NOREQUIRE_LINK_UP 0x00001000
+
+#ifndef __DOXYGEN__
+/*
+ * These are part of the implementation of the NETIO_AUTO_LINK_xxx flags,
+ * but should not be used directly by applications, and are thus not
+ * documented.
+ */
+#define _NETIO_AUTO_UP 0x00002000
+#define _NETIO_AUTO_DN 0x00004000
+#define _NETIO_AUTO_PRESENT 0x00008000
+#endif
+
+/** Set the desired state of the link to up, allowing any speeds which are
+ supported by the link hardware, as part of this registration operation.
+ Do not take down the link automatically. This is the default if
+ no other NETIO_AUTO_LINK_xxx flags are specified. This flag is ignored
+ if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV.
+ See @ref link for more information on link management.
+ */
+#define NETIO_AUTO_LINK_UP (_NETIO_AUTO_PRESENT | _NETIO_AUTO_UP)
+
+/** Set the desired state of the link to up, allowing any speeds which are
+ supported by the link hardware, as part of this registration operation.
+ Set the desired state of the link to down the next time no tiles are
+ registered for packet reception or transmission. This flag is ignored
+ if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV.
+ See @ref link for more information on link management.
+ */
+#define NETIO_AUTO_LINK_UPDN (_NETIO_AUTO_PRESENT | _NETIO_AUTO_UP | \
+ _NETIO_AUTO_DN)
+
+/** Set the desired state of the link to down the next time no tiles are
+ registered for packet reception or transmission. This flag is ignored
+ if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV.
+ See @ref link for more information on link management.
+ */
+#define NETIO_AUTO_LINK_DN (_NETIO_AUTO_PRESENT | _NETIO_AUTO_DN)
+
+/** Do not bring up the link automatically as part of this registration
+ operation. Do not take down the link automatically. This flag
+ is ignored if it is specified along with ::NETIO_NO_XMIT and
+ ::NETIO_NO_RECV. See @ref link for more information on link management.
+ */
+#define NETIO_AUTO_LINK_NONE _NETIO_AUTO_PRESENT
+
+
+/** Minimum number of receive packets. */
+#define NETIO_MIN_RECEIVE_PKTS 16
+
+/** Lower bound on the maximum number of receive packets; may be higher
+ than this on some interfaces. */
+#define NETIO_MAX_RECEIVE_PKTS 128
+
+/** Maximum number of send buffers, per packet size. */
+#define NETIO_MAX_SEND_BUFFERS 16
+
+/** Number of EPP queue slots, and thus outstanding sends, per EPP. */
+#define NETIO_TOTAL_SENDS_OUTSTANDING 2015
+
+/** Minimum number of EPP queue slots, and thus outstanding sends, per
+ * transmitting tile. */
+#define NETIO_MIN_SENDS_OUTSTANDING 16
+
+
+/**@}*/
+
+#ifndef __DOXYGEN__
+
+/**
+ * An object for providing Ethernet packets to a process.
+ */
+struct __netio_queue_impl_t;
+
+/**
+ * An object for managing the user end of a NetIO queue.
+ */
+struct __netio_queue_user_impl_t;
+
+#endif /* !__DOXYGEN__ */
+
+
+/** A netio_queue_t describes a NetIO communications endpoint.
+ * @ingroup setup
+ */
+typedef struct
+{
+#ifdef __DOXYGEN__
+ uint8_t opaque[8]; /**< This is an opaque structure. */
+#else
+ struct __netio_queue_impl_t* __system_part; /**< The system part. */
+ struct __netio_queue_user_impl_t* __user_part; /**< The user part. */
+#ifdef _NETIO_PTHREAD
+ _netio_percpu_mutex_t lock; /**< Queue lock. */
+#endif
+#endif
+}
+netio_queue_t;
+
+
+/**
+ * @brief Packet send context.
+ *
+ * @ingroup egress
+ *
+ * Packet send context for use with netio_send_packet_prepare and _commit.
+ */
+typedef struct
+{
+#ifdef __DOXYGEN__
+ uint8_t opaque[44]; /**< This is an opaque structure. */
+#else
+ uint8_t flags; /**< Defined below */
+ uint8_t datalen; /**< Number of valid words pointed to by data. */
+ uint32_t request[9]; /**< Request to be sent to the EPP or shim. Note
+ that this is smaller than the 11-word maximum
+ request size, since some constant values are
+ not saved in the context. */
+ uint32_t *data; /**< Data to be sent to the EPP or shim via IDN. */
+#endif
+}
+netio_send_pkt_context_t;
+
+
+#ifndef __DOXYGEN__
+#define SEND_PKT_CTX_USE_EPP 1 /**< We're sending to an EPP. */
+#define SEND_PKT_CTX_SEND_CSUM 2 /**< Request includes a checksum. */
+#endif
+
+/**
+ * @brief Packet vector entry.
+ *
+ * @ingroup egress
+ *
+ * This data structure is used with netio_send_packet_vector() to send multiple
+ * packets with one NetIO call. The structure should be initialized by
+ * calling netio_pkt_vector_set(), rather than by setting the fields
+ * directly.
+ *
+ * This structure is guaranteed to be a power of two in size, no
+ * bigger than one L2 cache line, and to be aligned modulo its size.
+ */
+typedef struct
+#ifndef __DOXYGEN__
+__attribute__((aligned(8)))
+#endif
+{
+ /** Reserved for use by the user application. When initialized with
+ * the netio_set_pkt_vector_entry() function, this field is guaranteed
+ * to be visible to readers only after all other fields are already
+ * visible. This way it can be used as a valid flag or generation
+ * counter. */
+ uint8_t user_data;
+
+ /* Structure members below this point should not be accessed directly by
+ * applications, as they may change in the future. */
+
+ /** Low 8 bits of the packet address to send. The high bits are
+ * acquired from the 'handle' field. */
+ uint8_t buffer_address_low;
+
+ /** Number of bytes to transmit. */
+ uint16_t size;
+
+ /** The raw handle from a netio_pkt_t. If this is NETIO_PKT_HANDLE_NONE,
+ * this vector entry will be skipped and no packet will be transmitted. */
+ netio_pkt_handle_t handle;
+}
+netio_pkt_vector_entry_t;
+
+
+/**
+ * @brief Initialize fields in a packet vector entry.
+ *
+ * @ingroup egress
+ *
+ * @param[out] v Pointer to the vector entry to be initialized.
+ * @param[in] pkt Packet to be transmitted when the vector entry is passed to
+ * netio_send_packet_vector(). Note that the packet's attributes
+ * (e.g., its L2 offset and length) are captured at the time this
+ * routine is called; subsequent changes in those attributes will not
+ * be reflected in the packet which is actually transmitted.
+ * Changes in the packet's contents, however, will be so reflected.
+ * If this is NULL, no packet will be transmitted.
+ * @param[in] user_data User data to be set in the vector entry.
+ * This function guarantees that the "user_data" field will become
+ * visible to a reader only after all other fields have become visible.
+ * This allows a structure in a ring buffer to be written and read
+ * by a polling reader without any locks or other synchronization.
+ */
+static __inline void
+netio_pkt_vector_set(volatile netio_pkt_vector_entry_t* v, netio_pkt_t* pkt,
+ uint8_t user_data)
+{
+ if (pkt)
+ {
+ if (NETIO_PKT_IS_MINIMAL(pkt))
+ {
+ netio_pkt_minimal_metadata_t* mmd =
+ (netio_pkt_minimal_metadata_t*) &pkt->__metadata;
+ v->buffer_address_low = (uintptr_t) NETIO_PKT_L2_DATA_MM(mmd, pkt) & 0xFF;
+ v->size = NETIO_PKT_L2_LENGTH_MM(mmd, pkt);
+ }
+ else
+ {
+ netio_pkt_metadata_t* mda = &pkt->__metadata;
+ v->buffer_address_low = (uintptr_t) NETIO_PKT_L2_DATA_M(mda, pkt) & 0xFF;
+ v->size = NETIO_PKT_L2_LENGTH_M(mda, pkt);
+ }
+ v->handle.word = pkt->__packet.word;
+ }
+ else
+ {
+ v->handle.word = 0; /* Set handle to NETIO_PKT_HANDLE_NONE. */
+ }
+
+ __asm__("" : : : "memory");
+
+ v->user_data = user_data;
+}
+
+
+/**
+ * Flags and structures for @ref netio_get() and @ref netio_set().
+ * @ingroup config
+ */
+
+/** @{ */
+/** Parameter class; addr is a NETIO_PARAM_xxx value. */
+#define NETIO_PARAM 0
+/** Interface MAC address. This address is only valid with @ref netio_get().
+ * The value is a 6-byte MAC address. Depending upon the overall system
+ * design, a MAC address may or may not be available for each interface. */
+#define NETIO_PARAM_MAC 0
+
+/** Determine whether to suspend output on the receipt of pause frames.
+ * If the value is nonzero, the I/O shim will suspend output when a pause
+ * frame is received. If the value is zero, pause frames will be ignored. */
+#define NETIO_PARAM_PAUSE_IN 1
+
+/** Determine whether to send pause frames if the I/O shim packet FIFOs are
+ * nearly full. If the value is zero, pause frames are not sent. If
+ * the value is nonzero, it is the delay value which will be sent in any
+ * pause frames which are output, in units of 512 bit times. */
+#define NETIO_PARAM_PAUSE_OUT 2
+
+/** Jumbo frame support. The value is a 4-byte integer. If the value is
+ * nonzero, the MAC will accept frames of up to 10240 bytes. If the value
+ * is zero, the MAC will only accept frames of up to 1544 bytes. */
+#define NETIO_PARAM_JUMBO 3
+
+/** I/O shim's overflow statistics register. The value is two 16-bit integers.
+ * The first 16-bit value (or the low 16 bits, if the value is treated as a
+ * 32-bit number) is the count of packets which were completely dropped and
+ * not delivered by the shim. The second 16-bit value (or the high 16 bits,
+ * if the value is treated as a 32-bit number) is the count of packets
+ * which were truncated and thus only partially delivered by the shim. This
+ * register is automatically reset to zero after it has been read.
+ */
+#define NETIO_PARAM_OVERFLOW 4
+
+/** IPP statistics. This address is only valid with @ref netio_get(). The
+ * value is a netio_stat_t structure. Unlike the I/O shim statistics, the
+ * IPP statistics are not all reset to zero on read; see the description
+ * of the netio_stat_t for details. */
+#define NETIO_PARAM_STAT 5
+
+/** Possible link state. The value is a combination of "NETIO_LINK_xxx"
+ * flags. With @ref netio_get(), this will indicate which flags are
+ * actually supported by the hardware.
+ *
+ * For historical reasons, specifying this value to netio_set() will have
+ * the same behavior as using ::NETIO_PARAM_LINK_CONFIG, but this usage is
+ * discouraged.
+ */
+#define NETIO_PARAM_LINK_POSSIBLE_STATE 6
+
+/** Link configuration. The value is a combination of "NETIO_LINK_xxx" flags.
+ * With @ref netio_set(), this will attempt to immediately bring up the
+ * link using whichever of the requested flags are supported by the
+ * hardware, or take down the link if the flags are zero; if this is
+ * not possible, an error will be returned. Many programs will want
+ * to use ::NETIO_PARAM_LINK_DESIRED_STATE instead.
+ *
+ * For historical reasons, specifying this value to netio_get() will
+ * have the same behavior as using ::NETIO_PARAM_LINK_POSSIBLE_STATE,
+ * but this usage is discouraged.
+ */
+#define NETIO_PARAM_LINK_CONFIG NETIO_PARAM_LINK_POSSIBLE_STATE
+
+/** Current link state. This address is only valid with @ref netio_get().
+ * The value is zero or more of the "NETIO_LINK_xxx" flags, ORed together.
+ * If the link is down, the value ANDed with NETIO_LINK_SPEED will be
+ * zero; if the link is up, the value ANDed with NETIO_LINK_SPEED will
+ * result in exactly one of the NETIO_LINK_xxx values, indicating the
+ * current speed. */
+#define NETIO_PARAM_LINK_CURRENT_STATE 7
+
+/** Variant symbol for current state, retained for compatibility with
+ * pre-MDE-2.1 programs. */
+#define NETIO_PARAM_LINK_STATUS NETIO_PARAM_LINK_CURRENT_STATE
+
+/** Packet Coherence protocol. This address is only valid with @ref netio_get().
+ * The value is nonzero if the interface is configured for cache-coherent DMA.
+ */
+#define NETIO_PARAM_COHERENT 8
+
+/** Desired link state. The value is a conbination of "NETIO_LINK_xxx"
+ * flags, which specify the desired state for the link. With @ref
+ * netio_set(), this will, in the background, attempt to bring up the link
+ * using whichever of the requested flags are reasonable, or take down the
+ * link if the flags are zero. The actual link up or down operation may
+ * happen after this call completes. If the link state changes in the
+ * future, the system will continue to try to get back to the desired link
+ * state; for instance, if the link is brought up successfully, and then
+ * the network cable is disconnected, the link will go down. However, the
+ * desired state of the link is still up, so if the cable is reconnected,
+ * the link will be brought up again.
+ *
+ * With @ref netio_get(), this will indicate the desired state for the
+ * link, as set with a previous netio_set() call, or implicitly by a
+ * netio_input_register() or netio_input_unregister() operation. This may
+ * not reflect the current state of the link; to get that, use
+ * ::NETIO_PARAM_LINK_CURRENT_STATE. */
+#define NETIO_PARAM_LINK_DESIRED_STATE 9
+
+/** NetIO statistics structure. Retrieved using the ::NETIO_PARAM_STAT
+ * address passed to @ref netio_get(). */
+typedef struct
+{
+ /** Number of packets which have been received by the IPP and forwarded
+ * to a tile's receive queue for processing. This value wraps at its
+ * maximum, and is not cleared upon read. */
+ uint32_t packets_received;
+
+ /** Number of packets which have been dropped by the IPP, because they could
+ * not be received, or could not be forwarded to a tile. The former happens
+ * when the IPP does not have a free packet buffer of suitable size for an
+ * incoming frame. The latter happens when all potential destination tiles
+ * for a packet, as defined by the group, bucket, and queue configuration,
+ * have full receive queues. This value wraps at its maximum, and is not
+ * cleared upon read. */
+ uint32_t packets_dropped;
+
+ /*
+ * Note: the #defines after each of the following four one-byte values
+ * denote their location within the third word of the netio_stat_t. They
+ * are intended for use only by the IPP implementation and are thus omitted
+ * from the Doxygen output.
+ */
+
+ /** Number of packets dropped because no worker was able to accept a new
+ * packet. This value saturates at its maximum, and is cleared upon
+ * read. */
+ uint8_t drops_no_worker;
+#ifndef __DOXYGEN__
+#define NETIO_STAT_DROPS_NO_WORKER 0
+#endif
+
+ /** Number of packets dropped because no small buffers were available.
+ * This value saturates at its maximum, and is cleared upon read. */
+ uint8_t drops_no_smallbuf;
+#ifndef __DOXYGEN__
+#define NETIO_STAT_DROPS_NO_SMALLBUF 1
+#endif
+
+ /** Number of packets dropped because no large buffers were available.
+ * This value saturates at its maximum, and is cleared upon read. */
+ uint8_t drops_no_largebuf;
+#ifndef __DOXYGEN__
+#define NETIO_STAT_DROPS_NO_LARGEBUF 2
+#endif
+
+ /** Number of packets dropped because no jumbo buffers were available.
+ * This value saturates at its maximum, and is cleared upon read. */
+ uint8_t drops_no_jumbobuf;
+#ifndef __DOXYGEN__
+#define NETIO_STAT_DROPS_NO_JUMBOBUF 3
+#endif
+}
+netio_stat_t;
+
+
+/** Link can run, should run, or is running at 10 Mbps. */
+#define NETIO_LINK_10M 0x01
+
+/** Link can run, should run, or is running at 100 Mbps. */
+#define NETIO_LINK_100M 0x02
+
+/** Link can run, should run, or is running at 1 Gbps. */
+#define NETIO_LINK_1G 0x04
+
+/** Link can run, should run, or is running at 10 Gbps. */
+#define NETIO_LINK_10G 0x08
+
+/** Link should run at the highest speed supported by the link and by
+ * the device connected to the link. Only usable as a value for
+ * the link's desired state; never returned as a value for the current
+ * or possible states. */
+#define NETIO_LINK_ANYSPEED 0x10
+
+/** All legal link speeds. */
+#define NETIO_LINK_SPEED (NETIO_LINK_10M | \
+ NETIO_LINK_100M | \
+ NETIO_LINK_1G | \
+ NETIO_LINK_10G | \
+ NETIO_LINK_ANYSPEED)
+
+
+/** MAC register class. Addr is a register offset within the MAC.
+ * Registers within the XGbE and GbE MACs are documented in the Tile
+ * Processor I/O Device Guide (UG104). MAC registers start at address
+ * 0x4000, and do not include the MAC_INTERFACE registers. */
+#define NETIO_MAC 1
+
+/** MDIO register class (IEEE 802.3 clause 22 format). Addr is the "addr"
+ * member of a netio_mdio_addr_t structure. */
+#define NETIO_MDIO 2
+
+/** MDIO register class (IEEE 802.3 clause 45 format). Addr is the "addr"
+ * member of a netio_mdio_addr_t structure. */
+#define NETIO_MDIO_CLAUSE45 3
+
+/** NetIO MDIO address type. Retrieved or provided using the ::NETIO_MDIO
+ * address passed to @ref netio_get() or @ref netio_set(). */
+typedef union
+{
+ struct
+ {
+ unsigned int reg:16; /**< MDIO register offset. For clause 22 access,
+ must be less than 32. */
+ unsigned int phy:5; /**< Which MDIO PHY to access. */
+ unsigned int dev:5; /**< Which MDIO device to access within that PHY.
+ Applicable for clause 45 access only; ignored
+ for clause 22 access. */
+ }
+ bits; /**< Container for bitfields. */
+ uint64_t addr; /**< Value to pass to @ref netio_get() or
+ * @ref netio_set(). */
+}
+netio_mdio_addr_t;
+
+/** @} */
+
+#endif /* __NETIO_INTF_H__ */
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_PCI) += pci.o
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
-#include <linux/smp_lock.h>
#include <linux/uaccess.h>
#include <linux/signal.h>
#include <asm/syscalls.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
--- /dev/null
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/byteorder.h>
+#include <asm/hv_driver.h>
+#include <hv/drv_pcie_rc_intf.h>
+
+
+/*
+ * Initialization flow and process
+ * -------------------------------
+ *
+ * This files containes the routines to search for PCI buses,
+ * enumerate the buses, and configure any attached devices.
+ *
+ * There are two entry points here:
+ * 1) tile_pci_init
+ * This sets up the pci_controller structs, and opens the
+ * FDs to the hypervisor. This is called from setup_arch() early
+ * in the boot process.
+ * 2) pcibios_init
+ * This probes the PCI bus(es) for any attached hardware. It's
+ * called by subsys_initcall. All of the real work is done by the
+ * generic Linux PCI layer.
+ *
+ */
+
+/*
+ * This flag tells if the platform is TILEmpower that needs
+ * special configuration for the PLX switch chip.
+ */
+int __write_once tile_plx_gen1;
+
+static struct pci_controller controllers[TILE_NUM_PCIE];
+static int num_controllers;
+
+static struct pci_ops tile_cfg_ops;
+
+
+/*
+ * We don't need to worry about the alignment of resources.
+ */
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+ resource_size_t size, resource_size_t align)
+{
+ return res->start;
+}
+EXPORT_SYMBOL(pcibios_align_resource);
+
+/*
+ * Open a FD to the hypervisor PCI device.
+ *
+ * controller_id is the controller number, config type is 0 or 1 for
+ * config0 or config1 operations.
+ */
+static int __init tile_pcie_open(int controller_id, int config_type)
+{
+ char filename[32];
+ int fd;
+
+ sprintf(filename, "pcie/%d/config%d", controller_id, config_type);
+
+ fd = hv_dev_open((HV_VirtAddr)filename, 0);
+
+ return fd;
+}
+
+
+/*
+ * Get the IRQ numbers from the HV and set up the handlers for them.
+ */
+static int __init tile_init_irqs(int controller_id,
+ struct pci_controller *controller)
+{
+ char filename[32];
+ int fd;
+ int ret;
+ int x;
+ struct pcie_rc_config rc_config;
+
+ sprintf(filename, "pcie/%d/ctl", controller_id);
+ fd = hv_dev_open((HV_VirtAddr)filename, 0);
+ if (fd < 0) {
+ pr_err("PCI: hv_dev_open(%s) failed\n", filename);
+ return -1;
+ }
+ ret = hv_dev_pread(fd, 0, (HV_VirtAddr)(&rc_config),
+ sizeof(rc_config), PCIE_RC_CONFIG_MASK_OFF);
+ hv_dev_close(fd);
+ if (ret != sizeof(rc_config)) {
+ pr_err("PCI: wanted %zd bytes, got %d\n",
+ sizeof(rc_config), ret);
+ return -1;
+ }
+ /* Record irq_base so that we can map INTx to IRQ # later. */
+ controller->irq_base = rc_config.intr;
+
+ for (x = 0; x < 4; x++)
+ tile_irq_activate(rc_config.intr + x,
+ TILE_IRQ_HW_CLEAR);
+
+ if (rc_config.plx_gen1)
+ controller->plx_gen1 = 1;
+
+ return 0;
+}
+
+/*
+ * First initialization entry point, called from setup_arch().
+ *
+ * Find valid controllers and fill in pci_controller structs for each
+ * of them.
+ *
+ * Returns the number of controllers discovered.
+ */
+int __init tile_pci_init(void)
+{
+ int i;
+
+ pr_info("PCI: Searching for controllers...\n");
+
+ /* Do any configuration we need before using the PCIe */
+
+ for (i = 0; i < TILE_NUM_PCIE; i++) {
+ int hv_cfg_fd0 = -1;
+ int hv_cfg_fd1 = -1;
+ int hv_mem_fd = -1;
+ char name[32];
+ struct pci_controller *controller;
+
+ /*
+ * Open the fd to the HV. If it fails then this
+ * device doesn't exist.
+ */
+ hv_cfg_fd0 = tile_pcie_open(i, 0);
+ if (hv_cfg_fd0 < 0)
+ continue;
+ hv_cfg_fd1 = tile_pcie_open(i, 1);
+ if (hv_cfg_fd1 < 0) {
+ pr_err("PCI: Couldn't open config fd to HV "
+ "for controller %d\n", i);
+ goto err_cont;
+ }
+
+ sprintf(name, "pcie/%d/mem", i);
+ hv_mem_fd = hv_dev_open((HV_VirtAddr)name, 0);
+ if (hv_mem_fd < 0) {
+ pr_err("PCI: Could not open mem fd to HV!\n");
+ goto err_cont;
+ }
+
+ pr_info("PCI: Found PCI controller #%d\n", i);
+
+ controller = &controllers[num_controllers];
+
+ if (tile_init_irqs(i, controller)) {
+ pr_err("PCI: Could not initialize "
+ "IRQs, aborting.\n");
+ goto err_cont;
+ }
+
+ controller->index = num_controllers;
+ controller->hv_cfg_fd[0] = hv_cfg_fd0;
+ controller->hv_cfg_fd[1] = hv_cfg_fd1;
+ controller->hv_mem_fd = hv_mem_fd;
+ controller->first_busno = 0;
+ controller->last_busno = 0xff;
+ controller->ops = &tile_cfg_ops;
+
+ num_controllers++;
+ continue;
+
+err_cont:
+ if (hv_cfg_fd0 >= 0)
+ hv_dev_close(hv_cfg_fd0);
+ if (hv_cfg_fd1 >= 0)
+ hv_dev_close(hv_cfg_fd1);
+ if (hv_mem_fd >= 0)
+ hv_dev_close(hv_mem_fd);
+ continue;
+ }
+
+ /*
+ * Before using the PCIe, see if we need to do any platform-specific
+ * configuration, such as the PLX switch Gen 1 issue on TILEmpower.
+ */
+ for (i = 0; i < num_controllers; i++) {
+ struct pci_controller *controller = &controllers[i];
+
+ if (controller->plx_gen1)
+ tile_plx_gen1 = 1;
+ }
+
+ return num_controllers;
+}
+
+/*
+ * (pin - 1) converts from the PCI standard's [1:4] convention to
+ * a normal [0:3] range.
+ */
+static int tile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct pci_controller *controller =
+ (struct pci_controller *)dev->sysdata;
+ return (pin - 1) + controller->irq_base;
+}
+
+
+static void __init fixup_read_and_payload_sizes(void)
+{
+ struct pci_dev *dev = NULL;
+ int smallest_max_payload = 0x1; /* Tile maxes out at 256 bytes. */
+ int max_read_size = 0x2; /* Limit to 512 byte reads. */
+ u16 new_values;
+
+ /* Scan for the smallest maximum payload size. */
+ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ int pcie_caps_offset;
+ u32 devcap;
+ int max_payload;
+
+ pcie_caps_offset = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (pcie_caps_offset == 0)
+ continue;
+
+ pci_read_config_dword(dev, pcie_caps_offset + PCI_EXP_DEVCAP,
+ &devcap);
+ max_payload = devcap & PCI_EXP_DEVCAP_PAYLOAD;
+ if (max_payload < smallest_max_payload)
+ smallest_max_payload = max_payload;
+ }
+
+ /* Now, set the max_payload_size for all devices to that value. */
+ new_values = (max_read_size << 12) | (smallest_max_payload << 5);
+ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ int pcie_caps_offset;
+ u16 devctl;
+
+ pcie_caps_offset = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (pcie_caps_offset == 0)
+ continue;
+
+ pci_read_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL,
+ &devctl);
+ devctl &= ~(PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ);
+ devctl |= new_values;
+ pci_write_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL,
+ devctl);
+ }
+}
+
+
+/*
+ * Second PCI initialization entry point, called by subsys_initcall.
+ *
+ * The controllers have been set up by the time we get here, by a call to
+ * tile_pci_init.
+ */
+static int __init pcibios_init(void)
+{
+ int i;
+
+ pr_info("PCI: Probing PCI hardware\n");
+
+ /*
+ * Delay a bit in case devices aren't ready. Some devices are
+ * known to require at least 20ms here, but we use a more
+ * conservative value.
+ */
+ mdelay(250);
+
+ /* Scan all of the recorded PCI controllers. */
+ for (i = 0; i < num_controllers; i++) {
+ struct pci_controller *controller = &controllers[i];
+ struct pci_bus *bus;
+
+ pr_info("PCI: initializing controller #%d\n", i);
+
+ /*
+ * This comes from the generic Linux PCI driver.
+ *
+ * It reads the PCI tree for this bus into the Linux
+ * data structures.
+ *
+ * This is inlined in linux/pci.h and calls into
+ * pci_scan_bus_parented() in probe.c.
+ */
+ bus = pci_scan_bus(0, controller->ops, controller);
+ controller->root_bus = bus;
+ controller->last_busno = bus->subordinate;
+
+ }
+
+ /* Do machine dependent PCI interrupt routing */
+ pci_fixup_irqs(pci_common_swizzle, tile_map_irq);
+
+ /*
+ * This comes from the generic Linux PCI driver.
+ *
+ * It allocates all of the resources (I/O memory, etc)
+ * associated with the devices read in above.
+ */
+
+ pci_assign_unassigned_resources();
+
+ /* Configure the max_read_size and max_payload_size values. */
+ fixup_read_and_payload_sizes();
+
+ /* Record the I/O resources in the PCI controller structure. */
+ for (i = 0; i < num_controllers; i++) {
+ struct pci_bus *root_bus = controllers[i].root_bus;
+ struct pci_bus *next_bus;
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &root_bus->devices, bus_list) {
+ /* Find the PCI host controller, ie. the 1st bridge. */
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+ (PCI_SLOT(dev->devfn) == 0)) {
+ next_bus = dev->subordinate;
+ controllers[i].mem_resources[0] =
+ *next_bus->resource[0];
+ controllers[i].mem_resources[1] =
+ *next_bus->resource[1];
+ controllers[i].mem_resources[2] =
+ *next_bus->resource[2];
+
+ break;
+ }
+ }
+
+ }
+
+ return 0;
+}
+subsys_initcall(pcibios_init);
+
+/*
+ * No bus fixups needed.
+ */
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+{
+ /* Nothing needs to be done. */
+}
+
+/*
+ * This can be called from the generic PCI layer, but doesn't need to
+ * do anything.
+ */
+char __devinit *pcibios_setup(char *str)
+{
+ /* Nothing needs to be done. */
+ return str;
+}
+
+/*
+ * This is called from the generic Linux layer.
+ */
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+/*
+ * Enable memory and/or address decoding, as appropriate, for the
+ * device described by the 'dev' struct.
+ *
+ * This is called from the generic PCI layer, and can be called
+ * for bridges or endpoints.
+ */
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+ u16 cmd, old_cmd;
+ u8 header_type;
+ int i;
+ struct resource *r;
+
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+ /*
+ * For bridges, we enable both memory and I/O decoding
+ * in call cases.
+ */
+ cmd |= PCI_COMMAND_IO;
+ cmd |= PCI_COMMAND_MEMORY;
+ } else {
+ /*
+ * For endpoints, we enable memory and/or I/O decoding
+ * only if they have a memory resource of that type.
+ */
+ for (i = 0; i < 6; i++) {
+ r = &dev->resource[i];
+ if (r->flags & IORESOURCE_UNSET) {
+ pr_err("PCI: Device %s not available "
+ "because of resource collisions\n",
+ pci_name(dev));
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ }
+
+ /*
+ * We only write the command if it changed.
+ */
+ if (cmd != old_cmd)
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ return 0;
+}
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
+{
+ unsigned long start = pci_resource_start(dev, bar);
+ unsigned long len = pci_resource_len(dev, bar);
+ unsigned long flags = pci_resource_flags(dev, bar);
+
+ if (!len)
+ return NULL;
+ if (max && len > max)
+ len = max;
+
+ if (!(flags & IORESOURCE_MEM)) {
+ pr_info("PCI: Trying to map invalid resource %#lx\n", flags);
+ start = 0;
+ }
+
+ return (void __iomem *)start;
+}
+EXPORT_SYMBOL(pci_iomap);
+
+
+/****************************************************************
+ *
+ * Tile PCI config space read/write routines
+ *
+ ****************************************************************/
+
+/*
+ * These are the normal read and write ops
+ * These are expanded with macros from pci_bus_read_config_byte() etc.
+ *
+ * devfn is the combined PCI slot & function.
+ *
+ * offset is in bytes, from the start of config space for the
+ * specified bus & slot.
+ */
+
+static int __devinit tile_cfg_read(struct pci_bus *bus,
+ unsigned int devfn,
+ int offset,
+ int size,
+ u32 *val)
+{
+ struct pci_controller *controller = bus->sysdata;
+ int busnum = bus->number & 0xff;
+ int slot = (devfn >> 3) & 0x1f;
+ int function = devfn & 0x7;
+ u32 addr;
+ int config_mode = 1;
+
+ /*
+ * There is no bridge between the Tile and bus 0, so we
+ * use config0 to talk to bus 0.
+ *
+ * If we're talking to a bus other than zero then we
+ * must have found a bridge.
+ */
+ if (busnum == 0) {
+ /*
+ * We fake an empty slot for (busnum == 0) && (slot > 0),
+ * since there is only one slot on bus 0.
+ */
+ if (slot) {
+ *val = 0xFFFFFFFF;
+ return 0;
+ }
+ config_mode = 0;
+ }
+
+ addr = busnum << 20; /* Bus in 27:20 */
+ addr |= slot << 15; /* Slot (device) in 19:15 */
+ addr |= function << 12; /* Function is in 14:12 */
+ addr |= (offset & 0xFFF); /* byte address in 0:11 */
+
+ return hv_dev_pread(controller->hv_cfg_fd[config_mode], 0,
+ (HV_VirtAddr)(val), size, addr);
+}
+
+
+/*
+ * See tile_cfg_read() for relevent comments.
+ * Note that "val" is the value to write, not a pointer to that value.
+ */
+static int __devinit tile_cfg_write(struct pci_bus *bus,
+ unsigned int devfn,
+ int offset,
+ int size,
+ u32 val)
+{
+ struct pci_controller *controller = bus->sysdata;
+ int busnum = bus->number & 0xff;
+ int slot = (devfn >> 3) & 0x1f;
+ int function = devfn & 0x7;
+ u32 addr;
+ int config_mode = 1;
+ HV_VirtAddr valp = (HV_VirtAddr)&val;
+
+ /*
+ * For bus 0 slot 0 we use config 0 accesses.
+ */
+ if (busnum == 0) {
+ /*
+ * We fake an empty slot for (busnum == 0) && (slot > 0),
+ * since there is only one slot on bus 0.
+ */
+ if (slot)
+ return 0;
+ config_mode = 0;
+ }
+
+ addr = busnum << 20; /* Bus in 27:20 */
+ addr |= slot << 15; /* Slot (device) in 19:15 */
+ addr |= function << 12; /* Function is in 14:12 */
+ addr |= (offset & 0xFFF); /* byte address in 0:11 */
+
+#ifdef __BIG_ENDIAN
+ /* Point to the correct part of the 32-bit "val". */
+ valp += 4 - size;
+#endif
+
+ return hv_dev_pwrite(controller->hv_cfg_fd[config_mode], 0,
+ valp, size, addr);
+}
+
+
+static struct pci_ops tile_cfg_ops = {
+ .read = tile_cfg_read,
+ .write = tile_cfg_write,
+};
+
+
+/*
+ * In the following, each PCI controller's mem_resources[1]
+ * represents its (non-prefetchable) PCI memory resource.
+ * mem_resources[0] and mem_resources[2] refer to its PCI I/O and
+ * prefetchable PCI memory resources, respectively.
+ * For more details, see pci_setup_bridge() in setup-bus.c.
+ * By comparing the target PCI memory address against the
+ * end address of controller 0, we can determine the controller
+ * that should accept the PCI memory access.
+ */
+#define TILE_READ(size, type) \
+type _tile_read##size(unsigned long addr) \
+{ \
+ type val; \
+ int idx = 0; \
+ if (addr > controllers[0].mem_resources[1].end && \
+ addr > controllers[0].mem_resources[2].end) \
+ idx = 1; \
+ if (hv_dev_pread(controllers[idx].hv_mem_fd, 0, \
+ (HV_VirtAddr)(&val), sizeof(type), addr)) \
+ pr_err("PCI: read %zd bytes at 0x%lX failed\n", \
+ sizeof(type), addr); \
+ return val; \
+} \
+EXPORT_SYMBOL(_tile_read##size)
+
+TILE_READ(b, u8);
+TILE_READ(w, u16);
+TILE_READ(l, u32);
+TILE_READ(q, u64);
+
+#define TILE_WRITE(size, type) \
+void _tile_write##size(type val, unsigned long addr) \
+{ \
+ int idx = 0; \
+ if (addr > controllers[0].mem_resources[1].end && \
+ addr > controllers[0].mem_resources[2].end) \
+ idx = 1; \
+ if (hv_dev_pwrite(controllers[idx].hv_mem_fd, 0, \
+ (HV_VirtAddr)(&val), sizeof(type), addr)) \
+ pr_err("PCI: write %zd bytes at 0x%lX failed\n", \
+ sizeof(type), addr); \
+} \
+EXPORT_SYMBOL(_tile_write##size)
+
+TILE_WRITE(b, u8);
+TILE_WRITE(w, u16);
+TILE_WRITE(l, u32);
+TILE_WRITE(q, u64);
for_each_online_node(i)
register_one_node(i);
- for_each_present_cpu(i)
+ for (i = 0; i < smp_height * smp_width; ++i)
register_cpu(&cpu_devices[i], i);
return 0;
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
-#include <linux/smp_lock.h>
#include <linux/bootmem.h>
#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/mman.h>
#include <linux/file.h>
void *memchr(const void *s, int c, size_t n)
{
+ const uint32_t *last_word_ptr;
+ const uint32_t *p;
+ const char *last_byte_ptr;
+ uintptr_t s_int;
+ uint32_t goal, before_mask, v, bits;
+ char *ret;
+
+ if (__builtin_expect(n == 0, 0)) {
+ /* Don't dereference any memory if the array is empty. */
+ return NULL;
+ }
+
/* Get an aligned pointer. */
- const uintptr_t s_int = (uintptr_t) s;
- const uint32_t *p = (const uint32_t *)(s_int & -4);
+ s_int = (uintptr_t) s;
+ p = (const uint32_t *)(s_int & -4);
/* Create four copies of the byte for which we are looking. */
- const uint32_t goal = 0x01010101 * (uint8_t) c;
+ goal = 0x01010101 * (uint8_t) c;
/* Read the first word, but munge it so that bytes before the array
* will not match goal.
* Note that this shift count expression works because we know
* shift counts are taken mod 32.
*/
- const uint32_t before_mask = (1 << (s_int << 3)) - 1;
- uint32_t v = (*p | before_mask) ^ (goal & before_mask);
+ before_mask = (1 << (s_int << 3)) - 1;
+ v = (*p | before_mask) ^ (goal & before_mask);
/* Compute the address of the last byte. */
- const char *const last_byte_ptr = (const char *)s + n - 1;
+ last_byte_ptr = (const char *)s + n - 1;
/* Compute the address of the word containing the last byte. */
- const uint32_t *const last_word_ptr =
- (const uint32_t *)((uintptr_t) last_byte_ptr & -4);
-
- uint32_t bits;
- char *ret;
-
- if (__builtin_expect(n == 0, 0)) {
- /* Don't dereference any memory if the array is empty. */
- return NULL;
- }
+ last_word_ptr = (const uint32_t *)((uintptr_t) last_byte_ptr & -4);
while ((bits = __insn_seqb(v, goal)) == 0) {
if (__builtin_expect(p == last_word_ptr, 0)) {
* when we compare them.
*/
u32 my_ticket_;
+ u32 iterations = 0;
- /* Take out the next ticket; this will also stop would-be readers. */
- if (val & 1)
- val = get_rwlock(rwlock);
- rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT);
+ /*
+ * Wait until there are no readers, then bump up the next
+ * field and capture the ticket value.
+ */
+ for (;;) {
+ if (!(val & 1)) {
+ if ((val >> RD_COUNT_SHIFT) == 0)
+ break;
+ rwlock->lock = val;
+ }
+ delay_backoff(iterations++);
+ val = __insn_tns((int *)&rwlock->lock);
+ }
- /* Extract my ticket value from the original word. */
+ /* Take out the next ticket and extract my ticket value. */
+ rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT);
my_ticket_ = val >> WR_NEXT_SHIFT;
- /*
- * Wait until the "current" field matches our ticket, and
- * there are no remaining readers.
- */
+ /* Wait until the "current" field matches our ticket. */
for (;;) {
u32 curr_ = val >> WR_CURR_SHIFT;
- u32 readers = val >> RD_COUNT_SHIFT;
- u32 delta = ((my_ticket_ - curr_) & WR_MASK) + !!readers;
+ u32 delta = ((my_ticket_ - curr_) & WR_MASK);
if (likely(delta == 0))
break;
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/sysctl.h>
static void free_winch(struct winch *winch, int free_irq_ok)
{
+ if (free_irq_ok)
+ free_irq(WINCH_IRQ, winch);
+
list_del(&winch->list);
if (winch->pid != -1)
os_close_file(winch->fd);
if (winch->stack != 0)
free_stack(winch->stack, 0);
- if (free_irq_ok)
- free_irq(WINCH_IRQ, winch);
kfree(winch);
}
#include "linux/stddef.h"
#include "linux/fs.h"
-#include "linux/smp_lock.h"
#include "linux/ptrace.h"
#include "linux/sched.h"
#include "linux/slab.h"
select HAVE_UNSTABLE_SCHED_CLOCK
select HAVE_IDE
select HAVE_OPROFILE
- select HAVE_PERF_EVENTS if (!M386 && !M486)
+ select HAVE_PERF_EVENTS
select HAVE_IRQ_WORK
select HAVE_IOREMAP_PROT
select HAVE_KPROBES
* by the Free Software Foundation.
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/times.h>
#include <linux/utsname.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/uio.h>
#include <linux/poll.h>
}
/* Return an pointer with offset calculated */
-static inline unsigned long __set_fixmap_offset(enum fixed_addresses idx,
- phys_addr_t phys, pgprot_t flags)
+static __always_inline unsigned long
+__set_fixmap_offset(enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
{
__set_fixmap(idx, phys, flags);
return fix_to_virt(idx) + (phys & (PAGE_SIZE - 1));
#define FAM10H_MMIO_CONF_ENABLE (1<<0)
#define FAM10H_MMIO_CONF_BUSRANGE_MASK 0xf
#define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2
-#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffff
+#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffffULL
#define FAM10H_MMIO_CONF_BASE_SHIFT 20
#define MSR_FAM10H_NODE_ID 0xc001100c
#define __PV_IS_CALLEE_SAVE(func) \
((struct paravirt_callee_save) { func })
-static inline unsigned long arch_local_save_flags(void)
+static inline notrace unsigned long arch_local_save_flags(void)
{
return PVOP_CALLEE0(unsigned long, pv_irq_ops.save_fl);
}
-static inline void arch_local_irq_restore(unsigned long f)
+static inline notrace void arch_local_irq_restore(unsigned long f)
{
PVOP_VCALLEE1(pv_irq_ops.restore_fl, f);
}
-static inline void arch_local_irq_disable(void)
+static inline notrace void arch_local_irq_disable(void)
{
PVOP_VCALLEE0(pv_irq_ops.irq_disable);
}
-static inline void arch_local_irq_enable(void)
+static inline notrace void arch_local_irq_enable(void)
{
PVOP_VCALLEE0(pv_irq_ops.irq_enable);
}
-static inline unsigned long arch_local_irq_save(void)
+static inline notrace unsigned long arch_local_irq_save(void)
{
unsigned long f;
void pvclock_read_wallclock(struct pvclock_wall_clock *wall,
struct pvclock_vcpu_time_info *vcpu,
struct timespec *ts);
+void pvclock_resume(void);
/*
* Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
#define UVH_APICID 0x002D0E00L
#define UV_APIC_PNODE_SHIFT 6
+#define UV_APICID_HIBIT_MASK 0xffff0000
+
/* Local Bus from cpu's perspective */
#define LOCAL_BUS_BASE 0x1c00000
#define LOCAL_BUS_SIZE (4 * 1024 * 1024)
}
}
+extern unsigned int uv_apicid_hibits;
static unsigned long uv_hub_ipi_value(int apicid, int vector, int mode)
{
+ apicid |= uv_apicid_hibits;
return (1UL << UVH_IPI_INT_SEND_SHFT) |
((apicid) << UVH_IPI_INT_APIC_ID_SHFT) |
(mode << UVH_IPI_INT_DELIVERY_MODE_SHFT) |
*
* SGI UV MMR definitions
*
- * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_X86_UV_UV_MMRS_H
} s;
};
+/* ========================================================================= */
+/* UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK */
+/* ========================================================================= */
+#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK 0x320130UL
+#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_32 0x009f0
+
+#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_SHFT 0
+#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_MASK 0x00000000ffffffffUL
+
+union uvh_lb_target_physical_apic_id_mask_u {
+ unsigned long v;
+ struct uvh_lb_target_physical_apic_id_mask_s {
+ unsigned long bit_enables : 32; /* RW */
+ unsigned long rsvd_32_63 : 32; /* */
+ } s;
+};
+
/* ========================================================================= */
/* UVH_NODE_ID */
/* ========================================================================= */
#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
#endif
-#ifndef machine_to_phys_mapping
-#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
-#endif
+#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START)
+#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END)
+#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>__MACH2PHYS_SHIFT)
/* Maximum number of virtual CPUs in multi-processor guests. */
#define MAX_VIRT_CPUS 32
/* And the trap vector is... */
#define TRAP_INSTR "int $0x82"
+#define __MACH2PHYS_VIRT_START 0xF5800000
+#define __MACH2PHYS_VIRT_END 0xF6800000
+
+#define __MACH2PHYS_SHIFT 2
+
/*
* Virtual addresses beyond this are not modifiable by guest OSes. The
* machine->physical mapping table starts at this address, read-only.
#define __HYPERVISOR_VIRT_END 0xFFFF880000000000
#define __MACH2PHYS_VIRT_START 0xFFFF800000000000
#define __MACH2PHYS_VIRT_END 0xFFFF804000000000
-
-#ifndef HYPERVISOR_VIRT_START
-#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
-#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END)
-#endif
-
-#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START)
-#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END)
-#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3)
-#ifndef machine_to_phys_mapping
-#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
-#endif
+#define __MACH2PHYS_SHIFT 3
/*
* int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base)
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/pfn.h>
+#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/page.h>
#define MAX_DOMAIN_PAGES \
((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
+extern unsigned long *machine_to_phys_mapping;
+extern unsigned int machine_to_phys_order;
extern unsigned long get_phys_to_machine(unsigned long pfn);
extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
if (xen_feature(XENFEAT_auto_translated_physmap))
return mfn;
-#if 0
if (unlikely((mfn >> machine_to_phys_order) != 0))
- return max_mapnr;
-#endif
+ return ~0;
pfn = 0;
/*
#include <linux/nmi.h>
#include <linux/module.h>
-/* For reliability, we're prepared to waste bits here. */
-static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
-
u64 hw_nmi_get_sample_period(void)
{
return (u64)(cpu_khz) * 1000 * 60;
}
#ifdef ARCH_HAS_NMI_WATCHDOG
+
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
void arch_trigger_all_cpu_backtrace(void)
{
int i;
static union uvh_apicid uvh_apicid;
int uv_min_hub_revision_id;
EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
+unsigned int uv_apicid_hibits;
+EXPORT_SYMBOL_GPL(uv_apicid_hibits);
static DEFINE_SPINLOCK(uv_nmi_lock);
static inline bool is_GRU_range(u64 start, u64 end)
uvh_apicid.s.pnode_shift = UV_APIC_PNODE_SHIFT;
}
+/*
+ * Add an extra bit as dictated by bios to the destination apicid of
+ * interrupts potentially passing through the UV HUB. This prevents
+ * a deadlock between interrupts and IO port operations.
+ */
+static void __init uv_set_apicid_hibit(void)
+{
+ union uvh_lb_target_physical_apic_id_mask_u apicid_mask;
+ unsigned long *mmr;
+
+ mmr = early_ioremap(UV_LOCAL_MMR_BASE |
+ UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK, sizeof(*mmr));
+ apicid_mask.v = *mmr;
+ early_iounmap(mmr, sizeof(*mmr));
+ uv_apicid_hibits = apicid_mask.s.bit_enables & UV_APICID_HIBIT_MASK;
+}
+
static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
int nodeid;
__get_cpu_var(x2apic_extra_bits) =
nodeid << (uvh_apicid.s.pnode_shift - 1);
uv_system_type = UV_NON_UNIQUE_APIC;
+ uv_set_apicid_hibit();
return 1;
}
}
int pnode;
pnode = uv_apicid_to_pnode(phys_apicid);
+ phys_apicid |= uv_apicid_hibits;
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
(phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
int cpu = cpumask_first(cpumask);
if ((unsigned)cpu < nr_cpu_ids)
- return per_cpu(x86_cpu_to_apicid, cpu);
+ return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits;
else
return BAD_APICID;
}
if (cpumask_test_cpu(cpu, cpu_online_mask))
break;
}
- return per_cpu(x86_cpu_to_apicid, cpu);
+ return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits;
}
static unsigned int x2apic_get_apic_id(unsigned long x)
#endif
+static bool check_hw_exists(void)
+{
+ u64 val, val_new = 0;
+ int ret = 0;
+
+ val = 0xabcdUL;
+ ret |= checking_wrmsrl(x86_pmu.perfctr, val);
+ ret |= rdmsrl_safe(x86_pmu.perfctr, &val_new);
+ if (ret || val != val_new)
+ return false;
+
+ return true;
+}
+
static void reserve_ds_buffers(void);
static void release_ds_buffers(void);
pmu_check_apic();
+ /* sanity check that the hardware exists or is emulated */
+ if (!check_hw_exists()) {
+ pr_cont("Broken PMU hardware detected, software events only.\n");
+ return;
+ }
+
pr_cont("%s PMU driver.\n", x86_pmu.name);
if (x86_pmu.quirks)
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/device.h>
* A tiny bit of offset fixup is necessary - 4*4 means the 4 words
* pushed above; +8 corresponds to copy_thread's esp0 setting.
*/
- pushl_cfi (TI_sysenter_return-THREAD_SIZE_asm+8+4*4)(%esp)
+ pushl_cfi ((TI_sysenter_return)-THREAD_SIZE_asm+8+4*4)(%esp)
CFI_REL_OFFSET eip, 0
pushl_cfi %eax
.endm
/* save partial stack frame */
+ .pushsection .kprobes.text, "ax"
ENTRY(save_args)
XCPT_FRAME
cld
ret
CFI_ENDPROC
END(save_args)
+ .popsection
ENTRY(save_rest)
PARTIAL_FRAME 1 REST_SKIP+8
dr6_p = (unsigned long *)ERR_PTR(args->err);
dr6 = *dr6_p;
+ /* If it's a single step, TRAP bits are random */
+ if (dr6 & DR_STEP)
+ return NOTIFY_DONE;
+
/* Do an early return if no trap bits are set in DR6 */
if ((dr6 & DR_TRAP_BITS) == 0)
return NOTIFY_DONE;
if (!breakinfo[i].enabled)
continue;
bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
- if (bp->attr.disabled == 1)
+ if (!bp->attr.disabled) {
+ arch_uninstall_hw_breakpoint(bp);
+ bp->attr.disabled = 1;
continue;
+ }
if (dbg_is_early)
early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
breakinfo[i].type);
- else
- arch_uninstall_hw_breakpoint(bp);
- bp->attr.disabled = 1;
+ else if (hw_break_release_slot(i))
+ printk(KERN_ERR "KGDB: hw bpt remove failed %lx\n",
+ breakinfo[i].addr);
+ breakinfo[i].enabled = 0;
}
}
};
static u64 __cpuinitdata fam10h_pci_mmconf_base;
-static int __cpuinitdata fam10h_pci_mmconf_base_status;
static struct pci_hostbridge_probe pci_probes[] __cpuinitdata = {
{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
return start1 - start2;
}
-/*[47:0] */
-/* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */
+#define MMCONF_UNIT (1ULL << FAM10H_MMIO_CONF_BASE_SHIFT)
+#define MMCONF_MASK (~(MMCONF_UNIT - 1))
+#define MMCONF_SIZE (MMCONF_UNIT << 8)
+/* need to avoid (0xfd<<32), (0xfe<<32), and (0xff<<32), ht used space */
#define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32)
-#define BASE_VALID(b) ((b != (0xfdULL << 32)) && (b != (0xfeULL << 32)))
+#define BASE_VALID(b) ((b) + MMCONF_SIZE <= (0xfdULL<<32) || (b) >= (1ULL<<40))
static void __cpuinit get_fam10h_pci_mmconf_base(void)
{
int i;
struct range range[8];
/* only try to get setting from BSP */
- /* -1 or 1 */
- if (fam10h_pci_mmconf_base_status)
+ if (fam10h_pci_mmconf_base)
return;
if (!early_pci_allowed())
- goto fail;
+ return;
found = 0;
for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
}
if (!found)
- goto fail;
+ return;
/* SYS_CFG */
address = MSR_K8_SYSCFG;
/* TOP_MEM2 is not enabled? */
if (!(val & (1<<21))) {
- tom2 = 0;
+ tom2 = 1ULL << 32;
} else {
/* TOP_MEM2 */
address = MSR_K8_TOP_MEM2;
rdmsrl(address, val);
- tom2 = val & (0xffffULL<<32);
+ tom2 = max(val & 0xffffff800000ULL, 1ULL << 32);
}
if (base <= tom2)
- base = tom2 + (1ULL<<32);
+ base = (tom2 + 2 * MMCONF_UNIT - 1) & MMCONF_MASK;
/*
* need to check if the range is in the high mmio range that is
if (!(reg & 3))
continue;
- start = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/
+ start = (u64)(reg & 0xffffff00) << 8; /* 39:16 on 31:8*/
reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
- end = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/
+ end = ((u64)(reg & 0xffffff00) << 8) | 0xffff; /* 39:16 on 31:8*/
- if (!end)
+ if (end < tom2)
continue;
range[hi_mmio_num].start = start;
if (range[hi_mmio_num - 1].end < base)
goto out;
- if (range[0].start > base)
+ if (range[0].start > base + MMCONF_SIZE)
goto out;
/* need to find one window */
- base = range[0].start - (1ULL << 32);
+ base = (range[0].start & MMCONF_MASK) - MMCONF_UNIT;
if ((base > tom2) && BASE_VALID(base))
goto out;
- base = range[hi_mmio_num - 1].end + (1ULL << 32);
- if ((base > tom2) && BASE_VALID(base))
+ base = (range[hi_mmio_num - 1].end + MMCONF_UNIT) & MMCONF_MASK;
+ if (BASE_VALID(base))
goto out;
/* need to find window between ranges */
- if (hi_mmio_num > 1)
- for (i = 0; i < hi_mmio_num - 1; i++) {
- if (range[i + 1].start > (range[i].end + (1ULL << 32))) {
- base = range[i].end + (1ULL << 32);
- if ((base > tom2) && BASE_VALID(base))
- goto out;
- }
+ for (i = 1; i < hi_mmio_num; i++) {
+ base = (range[i - 1].end + MMCONF_UNIT) & MMCONF_MASK;
+ val = range[i].start & MMCONF_MASK;
+ if (val >= base + MMCONF_SIZE && BASE_VALID(base))
+ goto out;
}
-
-fail:
- fam10h_pci_mmconf_base_status = -1;
return;
+
out:
fam10h_pci_mmconf_base = base;
- fam10h_pci_mmconf_base_status = 1;
}
void __cpuinit fam10h_check_enable_mmcfg(void)
/* only trust the one handle 256 buses, if acpi=off */
if (!acpi_pci_disabled || busnbits >= 8) {
- u64 base;
- base = val & (0xffffULL << 32);
- if (fam10h_pci_mmconf_base_status <= 0) {
+ u64 base = val & MMCONF_MASK;
+
+ if (!fam10h_pci_mmconf_base) {
fam10h_pci_mmconf_base = base;
- fam10h_pci_mmconf_base_status = 1;
return;
} else if (fam10h_pci_mmconf_base == base)
return;
* with 256 buses
*/
get_fam10h_pci_mmconf_base();
- if (fam10h_pci_mmconf_base_status <= 0)
+ if (!fam10h_pci_mmconf_base) {
+ pci_probe &= ~PCI_CHECK_ENABLE_AMD_MMCONF;
return;
+ }
printk(KERN_INFO "Enable MMCONFIG on AMD Family 10h\n");
val &= ~((FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT) |
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/device.h>
static atomic64_t last_value = ATOMIC64_INIT(0);
+void pvclock_resume(void)
+{
+ atomic64_set(&last_value, 0);
+}
+
cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
{
struct pvclock_shadow_time shadow;
vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
load_host_msrs(vcpu);
+ kvm_load_ldt(ldt_selector);
loadsegment(fs, fs_selector);
#ifdef CONFIG_X86_64
load_gs_index(gs_selector);
#else
loadsegment(gs, gs_selector);
#endif
- kvm_load_ldt(ldt_selector);
reload_tss(vcpu);
#endif
#ifdef CONFIG_X86_64
- if (is_long_mode(&vmx->vcpu)) {
- rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
+ rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
+ if (is_long_mode(&vmx->vcpu))
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
- }
#endif
for (i = 0; i < vmx->save_nmsrs; ++i)
kvm_set_shared_msr(vmx->guest_msrs[i].index,
++vmx->vcpu.stat.host_state_reload;
vmx->host_state.loaded = 0;
- if (vmx->host_state.fs_reload_needed)
- loadsegment(fs, vmx->host_state.fs_sel);
+#ifdef CONFIG_X86_64
+ if (is_long_mode(&vmx->vcpu))
+ rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
+#endif
if (vmx->host_state.gs_ldt_reload_needed) {
kvm_load_ldt(vmx->host_state.ldt_sel);
#ifdef CONFIG_X86_64
load_gs_index(vmx->host_state.gs_sel);
- wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
#else
loadsegment(gs, vmx->host_state.gs_sel);
#endif
}
+ if (vmx->host_state.fs_reload_needed)
+ loadsegment(fs, vmx->host_state.fs_sel);
reload_tss();
#ifdef CONFIG_X86_64
- if (is_long_mode(&vmx->vcpu)) {
- rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
- wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
- }
+ wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
#endif
if (current_thread_info()->status & TS_USEDFPU)
clts();
static void __cpuinit calculate_tlb_offset(void)
{
- int cpu, node, nr_node_vecs;
+ int cpu, node, nr_node_vecs, idx = 0;
/*
* we are changing tlb_vector_offset for each CPU in runtime, but this
* will not cause inconsistency, as the write is atomic under X86. we
nr_node_vecs = NUM_INVALIDATE_TLB_VECTORS/nr_online_nodes;
for_each_online_node(node) {
- int node_offset = (node % NUM_INVALIDATE_TLB_VECTORS) *
+ int node_offset = (idx % NUM_INVALIDATE_TLB_VECTORS) *
nr_node_vecs;
int cpu_offset = 0;
for_each_cpu(cpu, cpumask_of_node(node)) {
cpu_offset++;
cpu_offset = cpu_offset % nr_node_vecs;
}
+ idx++;
}
}
struct xen_pci_frontend_ops *xen_pci_frontend;
EXPORT_SYMBOL_GPL(xen_pci_frontend);
+#define XEN_PIRQ_MSI_DATA (MSI_DATA_TRIGGER_EDGE | \
+ MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0))
+
static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
struct msi_msg *msg)
{
MSI_ADDR_REDIRECTION_CPU |
MSI_ADDR_DEST_ID(pirq);
- msg->data =
- MSI_DATA_TRIGGER_EDGE |
- MSI_DATA_LEVEL_ASSERT |
- /* delivery mode reserved */
- (3 << 8) |
- MSI_DATA_VECTOR(0);
+ msg->data = XEN_PIRQ_MSI_DATA;
}
static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
struct msi_msg msg;
list_for_each_entry(msidesc, &dev->msi_list, list) {
+ __read_msi_msg(msidesc, &msg);
+ pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
+ ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
+ if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) {
+ xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
+ "msi-x" : "msi", &irq, &pirq, XEN_ALLOC_IRQ);
+ if (irq < 0)
+ goto error;
+ ret = set_irq_msi(irq, msidesc);
+ if (ret < 0)
+ goto error_while;
+ printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d"
+ " pirq=%d\n", irq, pirq);
+ return 0;
+ }
xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
- "msi-x" : "msi", &irq, &pirq);
+ "msi-x" : "msi", &irq, &pirq, (XEN_ALLOC_IRQ | XEN_ALLOC_PIRQ));
if (irq < 0 || pirq < 0)
goto error;
printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
* the below initialization can't be in firmware because the
* messaging IRQ will be determined by the OS
*/
- apicid = uvhub_to_first_apicid(uvhub);
+ apicid = uvhub_to_first_apicid(uvhub) | uv_apicid_hibits;
uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG,
((apicid << 32) | vector));
}
apicid = cpu_physical_id(cpu);
pnode = uv_apicid_to_pnode(apicid);
+ apicid |= uv_apicid_hibits;
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
(apicid << UVH_IPI_INT_APIC_ID_SHFT) |
(X86_PLATFORM_IPI_VECTOR << UVH_IPI_INT_VECTOR_SHFT);
static int uv_setup_intr(int cpu, u64 expires)
{
u64 val;
+ unsigned long apicid = cpu_physical_id(cpu) | uv_apicid_hibits;
int pnode = uv_cpu_to_pnode(cpu);
uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG,
UVH_EVENT_OCCURRED0_RTC1_MASK);
val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
- ((u64)cpu_physical_id(cpu) << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
+ ((u64)apicid << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
/* Set configuration */
uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, val);
enum xen_domain_type xen_domain_type = XEN_NATIVE;
EXPORT_SYMBOL_GPL(xen_domain_type);
+unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START;
+EXPORT_SYMBOL(machine_to_phys_mapping);
+unsigned int machine_to_phys_order;
+EXPORT_SYMBOL(machine_to_phys_order);
+
struct start_info *xen_start_info;
EXPORT_SYMBOL_GPL(xen_start_info);
{
struct sched_shutdown r = { .reason = reason };
-#ifdef CONFIG_SMP
- stop_other_cpus();
-#endif
-
if (HYPERVISOR_sched_op(SCHEDOP_shutdown, &r))
BUG();
}
/* First C function to be called on Xen boot */
asmlinkage void __init xen_start_kernel(void)
{
+ struct physdev_set_iopl set_iopl;
+ int rc;
pgd_t *pgd;
if (!xen_start_info)
xen_domain_type = XEN_PV_DOMAIN;
+ xen_setup_machphys_mapping();
+
/* Install Xen paravirt ops */
pv_info = xen_info;
pv_init_ops = xen_init_ops;
/* Allocate and initialize top and mid mfn levels for p2m structure */
xen_build_mfn_list_list();
- init_mm.pgd = pgd;
-
/* keep using Xen gdt for now; no urgent need to change it */
#ifdef CONFIG_X86_32
#else
pv_info.kernel_rpl = 0;
#endif
-
/* set the limit of our address space */
xen_reserve_top();
+ /* We used to do this in xen_arch_setup, but that is too late on AMD
+ * were early_cpu_init (run before ->arch_setup()) calls early_amd_init
+ * which pokes 0xcf8 port.
+ */
+ set_iopl.iopl = 1;
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+ if (rc != 0)
+ xen_raw_printk("physdev_op failed %d\n", rc);
+
#ifdef CONFIG_X86_32
/* set up basic CPUID stuff */
cpu_detect(&new_cpu_data);
set_page_prot(pmd, PAGE_KERNEL_RO);
}
+void __init xen_setup_machphys_mapping(void)
+{
+ struct xen_machphys_mapping mapping;
+ unsigned long machine_to_phys_nr_ents;
+
+ if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
+ machine_to_phys_mapping = (unsigned long *)mapping.v_start;
+ machine_to_phys_nr_ents = mapping.max_mfn + 1;
+ } else {
+ machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
+ }
+ machine_to_phys_order = fls(machine_to_phys_nr_ents - 1);
+}
+
#ifdef CONFIG_X86_64
static void convert_pfn_mfn(void *v)
{
return pgd;
}
#else /* !CONFIG_X86_64 */
-static RESERVE_BRK_ARRAY(pmd_t, level2_kernel_pgt, PTRS_PER_PMD);
+static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD);
+static RESERVE_BRK_ARRAY(pmd_t, swapper_kernel_pmd, PTRS_PER_PMD);
+
+static __init void xen_write_cr3_init(unsigned long cr3)
+{
+ unsigned long pfn = PFN_DOWN(__pa(swapper_pg_dir));
+
+ BUG_ON(read_cr3() != __pa(initial_page_table));
+ BUG_ON(cr3 != __pa(swapper_pg_dir));
+
+ /*
+ * We are switching to swapper_pg_dir for the first time (from
+ * initial_page_table) and therefore need to mark that page
+ * read-only and then pin it.
+ *
+ * Xen disallows sharing of kernel PMDs for PAE
+ * guests. Therefore we must copy the kernel PMD from
+ * initial_page_table into a new kernel PMD to be used in
+ * swapper_pg_dir.
+ */
+ swapper_kernel_pmd =
+ extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
+ memcpy(swapper_kernel_pmd, initial_kernel_pmd,
+ sizeof(pmd_t) * PTRS_PER_PMD);
+ swapper_pg_dir[KERNEL_PGD_BOUNDARY] =
+ __pgd(__pa(swapper_kernel_pmd) | _PAGE_PRESENT);
+ set_page_prot(swapper_kernel_pmd, PAGE_KERNEL_RO);
+
+ set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO);
+ xen_write_cr3(cr3);
+ pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, pfn);
+
+ pin_pagetable_pfn(MMUEXT_UNPIN_TABLE,
+ PFN_DOWN(__pa(initial_page_table)));
+ set_page_prot(initial_page_table, PAGE_KERNEL);
+ set_page_prot(initial_kernel_pmd, PAGE_KERNEL);
+
+ pv_mmu_ops.write_cr3 = &xen_write_cr3;
+}
__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
unsigned long max_pfn)
{
pmd_t *kernel_pmd;
- level2_kernel_pgt = extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
+ initial_kernel_pmd =
+ extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
xen_start_info->nr_pt_frames * PAGE_SIZE +
512*1024);
kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd);
- memcpy(level2_kernel_pgt, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
+ memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
- xen_map_identity_early(level2_kernel_pgt, max_pfn);
+ xen_map_identity_early(initial_kernel_pmd, max_pfn);
- memcpy(swapper_pg_dir, pgd, sizeof(pgd_t) * PTRS_PER_PGD);
- set_pgd(&swapper_pg_dir[KERNEL_PGD_BOUNDARY],
- __pgd(__pa(level2_kernel_pgt) | _PAGE_PRESENT));
+ memcpy(initial_page_table, pgd, sizeof(pgd_t) * PTRS_PER_PGD);
+ initial_page_table[KERNEL_PGD_BOUNDARY] =
+ __pgd(__pa(initial_kernel_pmd) | _PAGE_PRESENT);
- set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO);
- set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO);
+ set_page_prot(initial_kernel_pmd, PAGE_KERNEL_RO);
+ set_page_prot(initial_page_table, PAGE_KERNEL_RO);
set_page_prot(empty_zero_page, PAGE_KERNEL_RO);
pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
- xen_write_cr3(__pa(swapper_pg_dir));
-
- pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(swapper_pg_dir)));
+ pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE,
+ PFN_DOWN(__pa(initial_page_table)));
+ xen_write_cr3(__pa(initial_page_table));
memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
__pa(xen_start_info->pt_base +
xen_start_info->nr_pt_frames * PAGE_SIZE),
"XEN PAGETABLES");
- return swapper_pg_dir;
+ return initial_page_table;
}
#endif /* CONFIG_X86_64 */
.write_cr2 = xen_write_cr2,
.read_cr3 = xen_read_cr3,
+#ifdef CONFIG_X86_32
+ .write_cr3 = xen_write_cr3_init,
+#else
.write_cr3 = xen_write_cr3,
+#endif
.flush_tlb_user = xen_flush_tlb,
.flush_tlb_kernel = xen_flush_tlb,
x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done;
pv_mmu_ops = xen_mmu_ops;
- vmap_lazy_unmap = false;
-
memset(dummy_mapping, 0xff, PAGE_SIZE);
}
prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP);
- vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
+ BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_RESERVED | VM_IO)) ==
+ (VM_PFNMAP | VM_RESERVED | VM_IO)));
rmd.mfn = mfn;
rmd.prot = prot;
return 0;
}
-void __init xen_unplug_emulated_devices(void)
+void xen_unplug_emulated_devices(void)
{
int r;
#include <xen/interface/callback.h>
#include <xen/interface/memory.h>
#include <xen/interface/physdev.h>
-#include <xen/interface/memory.h>
#include <xen/features.h>
#include "xen-ops.h"
for (i = 0; i < memmap.nr_entries; i++) {
unsigned long long end = map[i].addr + map[i].size;
- if (map[i].type == E820_RAM) {
- if (map[i].addr < mem_end && end > mem_end) {
- /* Truncate region to max_mem. */
- u64 delta = end - mem_end;
+ if (map[i].type == E820_RAM && end > mem_end) {
+ /* RAM off the end - may be partially included */
+ u64 delta = min(map[i].size, end - mem_end);
- map[i].size -= delta;
- extra_pages += PFN_DOWN(delta);
+ map[i].size -= delta;
+ end -= delta;
- end = mem_end;
- }
+ extra_pages += PFN_DOWN(delta);
}
- if (end > xen_extra_mem_start)
+ if (map[i].size > 0 && end > xen_extra_mem_start)
xen_extra_mem_start = end;
- /* If region is non-RAM or below mem_end, add what remains */
- if ((map[i].type != E820_RAM || map[i].addr < mem_end) &&
- map[i].size > 0)
+ /* Add region if any remains */
+ if (map[i].size > 0)
e820_add_region(map[i].addr, map[i].size, map[i].type);
}
else
extra_pages = 0;
- if (!xen_initial_domain())
- xen_add_extra_mem(extra_pages);
+ xen_add_extra_mem(extra_pages);
return "Xen";
}
-static void xen_idle(void)
-{
- local_irq_disable();
-
- if (need_resched())
- local_irq_enable();
- else {
- current_thread_info()->status &= ~TS_POLLING;
- smp_mb__after_clear_bit();
- safe_halt();
- current_thread_info()->status |= TS_POLLING;
- }
-}
-
/*
* Set the bit indicating "nosegneg" library variants should be used.
* We only need to bother in pure 32-bit mode; compat 32-bit processes
void __init xen_arch_setup(void)
{
- struct physdev_set_iopl set_iopl;
- int rc;
-
xen_panic_handler_init();
HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
xen_enable_sysenter();
xen_enable_syscall();
- set_iopl.iopl = 1;
- rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
- if (rc != 0)
- printk(KERN_INFO "physdev_op failed %d\n", rc);
-
#ifdef CONFIG_ACPI
if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ?
COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE);
- pm_idle = xen_idle;
+ /* Set up idle, making sure it calls safe_halt() pvop */
+#ifdef CONFIG_X86_32
+ boot_cpu_data.hlt_works_ok = 1;
+#endif
+ pm_idle = default_idle;
fiddle_vdso();
}
int cpu;
xen_hvm_init_shared_info();
xen_callback_vector();
+ xen_unplug_emulated_devices();
if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
for_each_online_cpu(cpu) {
xen_setup_runstate_info(cpu);
{
int cpu;
+ pvclock_resume();
+
if (xen_clockevent != &xen_vcpuop_clockevent)
return;
void xen_callback_vector(void);
void xen_hvm_init_shared_info(void);
-void __init xen_unplug_emulated_devices(void);
+void xen_unplug_emulated_devices(void);
void __init xen_build_dynamic_phys_to_machine(void);
{
unsigned int nr_reads = 0, nr_writes = 0;
unsigned int max_nr_reads = throtl_grp_quantum*3/4;
- unsigned int max_nr_writes = throtl_grp_quantum - nr_reads;
+ unsigned int max_nr_writes = throtl_grp_quantum - max_nr_reads;
struct bio *bio;
/* Try to dispatch 75% READS and 25% WRITES */
int ret, rw;
unsigned int dxfer_len;
void *dxferp = NULL;
+ struct bsg_class_device *bcd = &q->bsg_dev;
+
+ /* if the LLD has been removed then the bsg_unregister_queue will
+ * eventually be called and the class_dev was freed, so we can no
+ * longer use this request_queue. Return no such address.
+ */
+ if (!bcd->class_dev)
+ return ERR_PTR(-ENXIO);
dprintk("map hdr %llx/%u %llx/%u\n", (unsigned long long) hdr->dout_xferp,
hdr->dout_xfer_len, (unsigned long long) hdr->din_xferp,
#include <linux/hdreg.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/hdreg.h>
#include <linux/backing-dev.h>
#include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
#include <linux/blktrace_api.h>
#include <asm/uaccess.h>
.release = single_release,
};
#endif
-static int get_ac_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct acpi_ac *ac = to_acpi_ac(psy);
- switch (psp) {
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = ac->state;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-static enum power_supply_property ac_props[] = {
- POWER_SUPPLY_PROP_ONLINE,
-};
/* --------------------------------------------------------------------------
AC Adapter Management
-------------------------------------------------------------------------- */
return 0;
}
+/* --------------------------------------------------------------------------
+ sysfs I/F
+ -------------------------------------------------------------------------- */
+static int get_ac_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct acpi_ac *ac = to_acpi_ac(psy);
+
+ if (!ac)
+ return -ENODEV;
+
+ if (acpi_ac_get_state(ac))
+ return -ENODEV;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = ac->state;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static enum power_supply_property ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
#ifdef CONFIG_ACPI_PROCFS_POWER
/* --------------------------------------------------------------------------
FS Interface (/proc)
* It is used to provide exclusive accessing for ERST Error Log
* Address Range too.
*/
-static DEFINE_SPINLOCK(erst_lock);
+static DEFINE_RAW_SPINLOCK(erst_lock);
static inline int erst_errno(int command_status)
{
if (erst_disable)
return -ENODEV;
- spin_lock_irqsave(&erst_lock, flags);
+ raw_spin_lock_irqsave(&erst_lock, flags);
count = __erst_get_record_count();
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return count;
}
if (erst_disable)
return -ENODEV;
- spin_lock_irqsave(&erst_lock, flags);
+ raw_spin_lock_irqsave(&erst_lock, flags);
rc = __erst_get_next_record_id(record_id);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return rc;
}
return -EINVAL;
if (erst_erange.attr & ERST_RANGE_NVRAM) {
- if (!spin_trylock_irqsave(&erst_lock, flags))
+ if (!raw_spin_trylock_irqsave(&erst_lock, flags))
return -EBUSY;
rc = __erst_write_to_nvram(record);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return rc;
}
if (record->record_length > erst_erange.size)
return -EINVAL;
- if (!spin_trylock_irqsave(&erst_lock, flags))
+ if (!raw_spin_trylock_irqsave(&erst_lock, flags))
return -EBUSY;
memcpy(erst_erange.vaddr, record, record->record_length);
rcd_erange = erst_erange.vaddr;
memcpy(&rcd_erange->persistence_information, "ER", 2);
rc = __erst_write_to_storage(0);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return rc;
}
if (erst_disable)
return -ENODEV;
- spin_lock_irqsave(&erst_lock, flags);
+ raw_spin_lock_irqsave(&erst_lock, flags);
len = __erst_read(record_id, record, buflen);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return len;
}
EXPORT_SYMBOL_GPL(erst_read);
if (erst_disable)
return -ENODEV;
- spin_lock_irqsave(&erst_lock, flags);
+ raw_spin_lock_irqsave(&erst_lock, flags);
rc = __erst_get_next_record_id(&record_id);
if (rc) {
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return rc;
}
/* no more record */
if (record_id == APEI_ERST_INVALID_RECORD_ID) {
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return 0;
}
len = __erst_read(record_id, record, buflen);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return len;
}
if (erst_disable)
return -ENODEV;
- spin_lock_irqsave(&erst_lock, flags);
+ raw_spin_lock_irqsave(&erst_lock, flags);
if (erst_erange.attr & ERST_RANGE_NVRAM)
rc = __erst_clear_from_nvram(record_id);
else
rc = __erst_clear_from_storage(record_id);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return rc;
}
/* HEST table parsing */
-static struct acpi_table_hest *hest_tab;
+static struct acpi_table_hest *__read_mostly hest_tab;
-static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
+static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
[ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */
[ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1,
[ACPI_HEST_TYPE_IA32_NMI] = sizeof(struct acpi_hest_ia_nmi),
unsigned int count;
};
-static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
+static int __init hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
{
int *count = data;
return 0;
}
-static int hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
+static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
{
struct platform_device *ghes_dev;
struct ghes_arr *ghes_arr = data;
return rc;
}
-static int hest_ghes_dev_register(unsigned int ghes_count)
+static int __init hest_ghes_dev_register(unsigned int ghes_count)
{
int rc, i;
struct ghes_arr ghes_arr;
unsigned long flags;
};
+static int acpi_battery_update(struct acpi_battery *battery);
+
#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
inline int acpi_battery_present(struct acpi_battery *battery)
int ret = 0;
struct acpi_battery *battery = to_acpi_battery(psy);
+ if (acpi_battery_update(battery))
+ return -ENODEV;
+
if (acpi_battery_present(battery)) {
/* run battery update only if it is present */
acpi_battery_get_state(battery);
ec_flag_msi, "MSI hardware", {
DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL},
{
+ ec_flag_msi, "MSI hardware", {
+ DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR")}, NULL},
+ {
ec_validate_ecdt, "ASUS hardware", {
DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
{},
static LIST_HEAD(acpi_ioremaps);
static DEFINE_SPINLOCK(acpi_ioremap_lock);
-#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
-static char osi_setup_string[OSI_STRING_LENGTH_MAX];
-
static void __init acpi_osi_setup_late(void);
/*
unsigned int enable:1;
unsigned int dmi:1;
unsigned int cmdline:1;
- unsigned int known:1;
-} osi_linux = { 0, 0, 0, 0};
+} osi_linux = {0, 0, 0};
static u32 acpi_osi_handler(acpi_string interface, u32 supported)
{
__setup("acpi_os_name=", acpi_os_name_setup);
+#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
+#define OSI_STRING_ENTRIES_MAX 16 /* arbitrary */
+
+struct osi_setup_entry {
+ char string[OSI_STRING_LENGTH_MAX];
+ bool enable;
+};
+
+static struct osi_setup_entry __initdata osi_setup_entries[OSI_STRING_ENTRIES_MAX];
+
+void __init acpi_osi_setup(char *str)
+{
+ struct osi_setup_entry *osi;
+ bool enable = true;
+ int i;
+
+ if (!acpi_gbl_create_osi_method)
+ return;
+
+ if (str == NULL || *str == '\0') {
+ printk(KERN_INFO PREFIX "_OSI method disabled\n");
+ acpi_gbl_create_osi_method = FALSE;
+ return;
+ }
+
+ if (*str == '!') {
+ str++;
+ enable = false;
+ }
+
+ for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+ osi = &osi_setup_entries[i];
+ if (!strcmp(osi->string, str)) {
+ osi->enable = enable;
+ break;
+ } else if (osi->string[0] == '\0') {
+ osi->enable = enable;
+ strncpy(osi->string, str, OSI_STRING_LENGTH_MAX);
+ break;
+ }
+ }
+}
+
static void __init set_osi_linux(unsigned int enable)
{
- if (osi_linux.enable != enable) {
+ if (osi_linux.enable != enable)
osi_linux.enable = enable;
- printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
- enable ? "Add": "Delet");
- }
if (osi_linux.enable)
acpi_osi_setup("Linux");
static void __init acpi_cmdline_osi_linux(unsigned int enable)
{
- osi_linux.cmdline = 1; /* cmdline set the default */
+ osi_linux.cmdline = 1; /* cmdline set the default and override DMI */
+ osi_linux.dmi = 0;
set_osi_linux(enable);
return;
void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
{
- osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */
-
printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
if (enable == -1)
return;
- osi_linux.known = 1; /* DMI knows which OSI(Linux) default needed */
-
+ osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */
set_osi_linux(enable);
return;
*/
static void __init acpi_osi_setup_late(void)
{
- char *str = osi_setup_string;
+ struct osi_setup_entry *osi;
+ char *str;
+ int i;
+ acpi_status status;
- if (*str == '\0')
- return;
+ for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+ osi = &osi_setup_entries[i];
+ str = osi->string;
- if (!strcmp("!Linux", str)) {
- acpi_cmdline_osi_linux(0); /* !enable */
- } else if (*str == '!') {
- if (acpi_remove_interface(++str) == AE_OK)
- printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
- } else if (!strcmp("Linux", str)) {
- acpi_cmdline_osi_linux(1); /* enable */
- } else {
- if (acpi_install_interface(str) == AE_OK)
- printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+ if (*str == '\0')
+ break;
+ if (osi->enable) {
+ status = acpi_install_interface(str);
+
+ if (ACPI_SUCCESS(status))
+ printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+ } else {
+ status = acpi_remove_interface(str);
+
+ if (ACPI_SUCCESS(status))
+ printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
+ }
}
}
-int __init acpi_osi_setup(char *str)
+static int __init osi_setup(char *str)
{
- if (str == NULL || *str == '\0') {
- printk(KERN_INFO PREFIX "_OSI method disabled\n");
- acpi_gbl_create_osi_method = FALSE;
- } else {
- strncpy(osi_setup_string, str, OSI_STRING_LENGTH_MAX);
- }
+ if (str && !strcmp("Linux", str))
+ acpi_cmdline_osi_linux(1);
+ else if (str && !strcmp("!Linux", str))
+ acpi_cmdline_osi_linux(0);
+ else
+ acpi_osi_setup(str);
return 1;
}
-__setup("acpi_osi=", acpi_osi_setup);
+__setup("acpi_osi=", osi_setup);
/* enable serialization to combat AE_ALREADY_EXISTS errors */
static int __init acpi_serialize_setup(char *str)
return AE_OK;
}
-acpi_status acpi_os_initialize1(void)
+acpi_status __init acpi_os_initialize1(void)
{
kacpid_wq = create_workqueue("kacpid");
kacpi_notify_wq = create_workqueue("kacpi_notify");
resource->name));
} else {
result = __acpi_power_on(resource);
+ if (result)
+ resource->ref_count--;
}
mutex_unlock(&resource->resource_lock);
- return 0;
+ return result;
}
static int acpi_power_off_device(acpi_handle handle)
struct acpi_handle_list *tl = NULL; /* Target Resources */
int i = 0;
-
if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
return -EINVAL;
+ if (device->power.state == state)
+ return 0;
+
if ((device->power.state < ACPI_STATE_D0)
|| (device->power.state > ACPI_STATE_D3))
return -ENODEV;
goto end;
}
- if (device->power.state == state) {
- goto end;
- }
-
/*
* Then we dereference all power resources used in the current list.
*/
return 0;
}
-static int acpi_thermal_cpufreq_increase(unsigned int cpu)
-{
- return -ENODEV;
-}
-static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
-{
- return -ENODEV;
-}
-
#endif
int acpi_processor_get_limit_info(struct acpi_processor *pr)
static u8 sleep_states[ACPI_S_STATE_COUNT];
-static u32 acpi_target_sleep_state = ACPI_STATE_S0;
-
static void acpi_sleep_tts_switch(u32 acpi_state)
{
union acpi_object in_arg = { ACPI_TYPE_INTEGER };
}
#ifdef CONFIG_ACPI_SLEEP
+static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+
/*
* The ACPI specification wants us to save NVS memory regions during hibernation
* and to restore them during the subsequent resume. Windows does that also for
DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"),
},
},
+ {
+ .callback = init_nvs_nosave,
+ .ident = "Sony Vaio VGN-NW130D",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"),
+ },
+ },
{},
};
#endif /* CONFIG_SUSPEND */
/**
* ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
+ * @shost: SCSI host of command to be sent
* @cmd: SCSI command to be sent
- * @done: Completion function, called when command is complete
*
* In some cases, this function translates SCSI commands into
* ATA taskfiles, and queues the taskfiles to be sent to
* ATA and ATAPI devices appearing as SCSI devices.
*
* LOCKING:
- * Releases scsi-layer-held lock, and obtains host lock.
+ * ATA host lock
*
* RETURNS:
* Return value from __ata_scsi_queuecmd() if @cmd can be queued,
* 0 otherwise.
*/
-int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
struct ata_port *ap;
struct ata_device *dev;
struct scsi_device *scsidev = cmd->device;
- struct Scsi_Host *shost = scsidev->host;
int rc = 0;
+ unsigned long irq_flags;
ap = ata_shost_to_port(shost);
- spin_unlock(shost->host_lock);
- spin_lock(ap->lock);
+ spin_lock_irqsave(ap->lock, irq_flags);
ata_scsi_dump_cdb(ap, cmd);
dev = ata_scsi_find_dev(ap, scsidev);
if (likely(dev))
- rc = __ata_scsi_queuecmd(cmd, done, dev);
+ rc = __ata_scsi_queuecmd(cmd, cmd->scsi_done, dev);
else {
cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
+ cmd->scsi_done(cmd);
}
- spin_unlock(ap->lock);
- spin_lock(shost->host_lock);
+ spin_unlock_irqrestore(ap->lock, irq_flags);
+
return rc;
}
return 0;
}
-static void svia_configure(struct pci_dev *pdev)
+static void svia_configure(struct pci_dev *pdev, int board_id)
{
u8 tmp8;
}
/*
- * vt6421 has problems talking to some drives. The following
+ * vt6420/1 has problems talking to some drives. The following
* is the fix from Joseph Chan <JosephChan@via.com.tw>.
*
* When host issues HOLD, device may send up to 20DW of data
*
* https://bugzilla.kernel.org/show_bug.cgi?id=15173
* http://article.gmane.org/gmane.linux.ide/46352
+ * http://thread.gmane.org/gmane.linux.kernel/1062139
*/
- if (pdev->device == 0x3249) {
+ if (board_id == vt6420 || board_id == vt6421) {
pci_read_config_byte(pdev, 0x52, &tmp8);
tmp8 |= 1 << 2;
pci_write_config_byte(pdev, 0x52, tmp8);
if (rc)
return rc;
- svia_configure(pdev);
+ svia_configure(pdev, board_id);
pci_set_master(pdev);
return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
err = -ENOMEM;
goto out;
}
- atm_dev = atm_dev_register(DEV_LABEL, &adummy_ops, -1, NULL);
+ atm_dev = atm_dev_register(DEV_LABEL, NULL, &adummy_ops, -1, NULL);
if (!atm_dev) {
printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n");
err = -ENODEV;
goto out_reset;
}
- dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL);
+ dev->atm_dev = atm_dev_register (DEV_LABEL, &pci_dev->dev, &amb_ops, -1,
+ NULL);
if (!dev->atm_dev) {
PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
err = -EINVAL;
if (!dev_data)
return -ENOMEM;
- dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
+ dev = atm_dev_register(DEV_LABEL,NULL,&atmtcp_v_dev_ops,itf,NULL);
if (!dev) {
kfree(dev_data);
return itf == -1 ? -ENOMEM : -EBUSY;
&zeroes);
if (!cpu_zeroes) goto out1;
}
- dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
+ dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &ops, -1, NULL);
if (!dev) goto out2;
pci_set_drvdata(pci_dev, dev);
eni_dev->pci_dev = pci_dev;
fs_dev, sizeof (struct fs_dev));
if (!fs_dev)
goto err_out;
- atm_dev = atm_dev_register("fs", &ops, -1, NULL);
+ atm_dev = atm_dev_register("fs", &pci_dev->dev, &ops, -1, NULL);
if (!atm_dev)
goto err_out_free_fs_dev;
static int __devinit
-fore200e_register(struct fore200e* fore200e)
+fore200e_register(struct fore200e* fore200e, struct device *parent)
{
struct atm_dev* atm_dev;
DPRINTK(2, "device %s being registered\n", fore200e->name);
- atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1,
- NULL);
+ atm_dev = atm_dev_register(fore200e->bus->proc_name, parent, &fore200e_ops,
+ -1, NULL);
if (atm_dev == NULL) {
printk(FORE200E "unable to register device %s\n", fore200e->name);
return -ENODEV;
static int __devinit
-fore200e_init(struct fore200e* fore200e)
+fore200e_init(struct fore200e* fore200e, struct device *parent)
{
- if (fore200e_register(fore200e) < 0)
+ if (fore200e_register(fore200e, parent) < 0)
return -ENODEV;
if (fore200e->bus->configure(fore200e) < 0)
sprintf(fore200e->name, "%s-%d", bus->model_name, index);
- err = fore200e_init(fore200e);
+ err = fore200e_init(fore200e, &op->dev);
if (err < 0) {
fore200e_shutdown(fore200e);
kfree(fore200e);
sprintf(fore200e->name, "%s-%d", bus->model_name, index);
- err = fore200e_init(fore200e);
+ err = fore200e_init(fore200e, &pci_dev->dev);
if (err < 0) {
fore200e_shutdown(fore200e);
goto out_free;
goto init_one_failure;
}
- atm_dev = atm_dev_register(DEV_LABEL, &he_ops, -1, NULL);
+ atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &he_ops, -1, NULL);
if (!atm_dev) {
err = -ENODEV;
goto init_one_failure;
PRINTD(DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p",
iobase, irq, membase);
- dev->atm_dev = atm_dev_register(DEV_LABEL, &hrz_ops, -1, NULL);
+ dev->atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &hrz_ops, -1,
+ NULL);
if (!(dev->atm_dev)) {
PRINTD(DBG_ERR, "failed to register Madge ATM adapter");
err = -EINVAL;
goto err_out_iounmap;
}
- dev = atm_dev_register("idt77252", &idt77252_ops, -1, NULL);
+ dev = atm_dev_register("idt77252", &pcidev->dev, &idt77252_ops, -1,
+ NULL);
if (!dev) {
printk("%s: can't register atm device\n", card->name);
err = -EIO;
ret = -ENODEV;
goto err_out_free_iadev;
}
- dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+ dev = atm_dev_register(DEV_LABEL, &pdev->dev, &ops, -1, NULL);
if (!dev) {
ret = -ENOMEM;
goto err_out_disable_dev;
return -ENOMEM;
}
- atmdev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+ atmdev = atm_dev_register(DEV_LABEL, &pci->dev, &ops, -1, NULL);
if (atmdev == NULL) {
printk(KERN_ERR DEV_LABEL
": couldn't register atm device!\n");
}
/* Register device */
- card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
+ card->atmdev = atm_dev_register("nicstar", &card->pcidev->dev, &atm_ops,
+ -1, NULL);
if (card->atmdev == NULL) {
printk("nicstar%d: can't register device.\n", i);
error = 17;
static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci);
static int list_vccs(int vci);
static void release_vccs(struct atm_dev *dev);
-static int atm_init(struct solos_card *);
+static int atm_init(struct solos_card *, struct device *);
static void atm_remove(struct solos_card *);
static int send_command(struct solos_card *card, int dev, const char *buf, size_t size);
static void solos_bh(unsigned long);
if (db_firmware_upgrade)
flash_upgrade(card, 3);
- err = atm_init(card);
+ err = atm_init(card, &dev->dev);
if (err)
goto out_free_irq;
return err;
}
-static int atm_init(struct solos_card *card)
+static int atm_init(struct solos_card *card, struct device *parent)
{
int i;
skb_queue_head_init(&card->tx_queue[i]);
skb_queue_head_init(&card->cli_queue[i]);
- card->atmdev[i] = atm_dev_register("solos-pci", &fpga_ops, -1, NULL);
+ card->atmdev[i] = atm_dev_register("solos-pci", parent, &fpga_ops, -1, NULL);
if (!card->atmdev[i]) {
dev_err(&card->dev->dev, "Could not register ATM device %d\n", i);
atm_remove(card);
goto out;
}
- dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+ dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &ops, -1, NULL);
if (!dev)
goto out_free;
*/
void dpm_resume_noirq(pm_message_t state)
{
- struct device *dev;
+ struct list_head list;
ktime_t starttime = ktime_get();
+ INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
transition_started = false;
- list_for_each_entry(dev, &dpm_list, power.entry)
+ while (!list_empty(&dpm_list)) {
+ struct device *dev = to_device(dpm_list.next);
+
+ get_device(dev);
if (dev->power.status > DPM_OFF) {
int error;
dev->power.status = DPM_OFF;
+ mutex_unlock(&dpm_list_mtx);
+
error = device_resume_noirq(dev, state);
+
+ mutex_lock(&dpm_list_mtx);
if (error)
pm_dev_err(dev, state, " early", error);
}
+ if (!list_empty(&dev->power.entry))
+ list_move_tail(&dev->power.entry, &list);
+ put_device(dev);
+ }
+ list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
dpm_show_time(starttime, state, "early");
resume_device_irqs();
*/
int dpm_suspend_noirq(pm_message_t state)
{
- struct device *dev;
+ struct list_head list;
ktime_t starttime = ktime_get();
int error = 0;
+ INIT_LIST_HEAD(&list);
suspend_device_irqs();
mutex_lock(&dpm_list_mtx);
- list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
+ while (!list_empty(&dpm_list)) {
+ struct device *dev = to_device(dpm_list.prev);
+
+ get_device(dev);
+ mutex_unlock(&dpm_list_mtx);
+
error = device_suspend_noirq(dev, state);
+
+ mutex_lock(&dpm_list_mtx);
if (error) {
pm_dev_err(dev, state, " late", error);
+ put_device(dev);
break;
}
dev->power.status = DPM_OFF_IRQ;
+ if (!list_empty(&dev->power.entry))
+ list_move(&dev->power.entry, &list);
+ put_device(dev);
}
+ list_splice_tail(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
if (error)
dpm_resume_noirq(resume_event(state));
{
struct request_queue *q;
int cnt = FD_MAX_UNITS;
- struct request *rq;
+ struct request *rq = NULL;
/* Find next queue we can dispatch from */
fdc_queue = fdc_queue + 1;
{
struct request_queue *q;
int old_pos = fdc_queue;
- struct request *rq;
+ struct request *rq = NULL;
do {
q = unit[fdc_queue].disk->queue;
MODULE_LICENSE("GPL");
static DEFINE_MUTEX(cciss_mutex);
+static struct proc_dir_entry *proc_cciss;
#include "cciss_cmd.h"
#include "cciss.h"
#define ENG_GIG_FACTOR (ENG_GIG/512)
#define ENGAGE_SCSI "engage scsi"
-static struct proc_dir_entry *proc_cciss;
-
static void cciss_seq_show_header(struct seq_file *seq)
{
ctlr_info_t *h = seq->private;
int length, /* length of data in buffer */
int func); /* 0 == read, 1 == write */
-static int cciss_scsi_queue_command (struct scsi_cmnd *cmd,
- void (* done)(struct scsi_cmnd *));
+static int cciss_scsi_queue_command (struct Scsi_Host *h,
+ struct scsi_cmnd *cmd);
static int cciss_eh_device_reset_handler(struct scsi_cmnd *);
static int cciss_eh_abort_handler(struct scsi_cmnd *);
static int
-cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+cciss_scsi_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
ctlr_info_t *h;
int rc;
return 0;
}
+static DEF_SCSI_QCMD(cciss_scsi_queue_command)
+
static void cciss_unregister_scsi(ctlr_info_t *h)
{
struct cciss_scsi_adapter_data_t *sa;
#include <linux/memcontrol.h>
#include <linux/mm_inline.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/pkt_sched.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/drbd.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/memcontrol.h>
- Instructions for use
- --------------------
+ For usage instructions, please refer to:
- 1) Map a Linux block device to an existing rbd image.
-
- Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name]
-
- $ echo "192.168.0.1 name=admin rbd foo" > /sys/class/rbd/add
-
- The snapshot name can be "-" or omitted to map the image read/write.
-
- 2) List all active blkdev<->object mappings.
-
- In this example, we have performed step #1 twice, creating two blkdevs,
- mapped to two separate rados objects in the rados rbd pool
-
- $ cat /sys/class/rbd/list
- #id major client_name pool name snap KB
- 0 254 client4143 rbd foo - 1024000
-
- The columns, in order, are:
- - blkdev unique id
- - blkdev assigned major
- - rados client id
- - rados pool name
- - rados block device name
- - mapped snapshot ("-" if none)
- - device size in KB
-
-
- 3) Create a snapshot.
-
- Usage: <blkdev id> <snapname>
-
- $ echo "0 mysnap" > /sys/class/rbd/snap_create
-
-
- 4) Listing a snapshot.
-
- $ cat /sys/class/rbd/snaps_list
- #id snap KB
- 0 - 1024000 (*)
- 0 foo 1024000
-
- The columns, in order, are:
- - blkdev unique id
- - snapshot name, '-' means none (active read/write version)
- - size of device at time of snapshot
- - the (*) indicates this is the active version
-
- 5) Rollback to snapshot.
-
- Usage: <blkdev id> <snapname>
-
- $ echo "0 mysnap" > /sys/class/rbd/snap_rollback
-
-
- 6) Mapping an image using snapshot.
-
- A snapshot mapping is read-only. This is being done by passing
- snap=<snapname> to the options when adding a device.
-
- $ echo "192.168.0.1 name=admin,snap=mysnap rbd foo" > /sys/class/rbd/add
-
-
- 7) Remove an active blkdev<->rbd image mapping.
-
- In this example, we remove the mapping with blkdev unique id 1.
-
- $ echo 1 > /sys/class/rbd/remove
-
-
- NOTE: The actual creation and deletion of rados objects is outside the scope
- of this driver.
+ Documentation/ABI/testing/sysfs-bus-rbd
*/
u64 len;
};
+struct rbd_snap {
+ struct device dev;
+ const char *name;
+ size_t size;
+ struct list_head node;
+ u64 id;
+};
+
/*
* a single device
*/
int read_only;
struct list_head node;
+
+ /* list of snapshots */
+ struct list_head snaps;
+
+ /* sysfs related */
+ struct device dev;
+};
+
+static struct bus_type rbd_bus_type = {
+ .name = "rbd",
};
static spinlock_t node_lock; /* protects client get/put */
-static struct class *class_rbd; /* /sys/class/rbd */
static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */
static LIST_HEAD(rbd_dev_list); /* devices */
static LIST_HEAD(rbd_client_list); /* clients */
+static int __rbd_init_snaps_header(struct rbd_device *rbd_dev);
+static void rbd_dev_release(struct device *dev);
+static ssize_t rbd_snap_rollback(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size);
+static ssize_t rbd_snap_add(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count);
+static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
+ struct rbd_snap *snap);;
+
+
+static struct rbd_device *dev_to_rbd(struct device *dev)
+{
+ return container_of(dev, struct rbd_device, dev);
+}
+
+static struct device *rbd_get_dev(struct rbd_device *rbd_dev)
+{
+ return get_device(&rbd_dev->dev);
+}
+
+static void rbd_put_dev(struct rbd_device *rbd_dev)
+{
+ put_device(&rbd_dev->dev);
+}
static int rbd_open(struct block_device *bdev, fmode_t mode)
{
struct gendisk *disk = bdev->bd_disk;
struct rbd_device *rbd_dev = disk->private_data;
+ rbd_get_dev(rbd_dev);
+
set_device_ro(bdev, rbd_dev->read_only);
if ((mode & FMODE_WRITE) && rbd_dev->read_only)
return 0;
}
+static int rbd_release(struct gendisk *disk, fmode_t mode)
+{
+ struct rbd_device *rbd_dev = disk->private_data;
+
+ rbd_put_dev(rbd_dev);
+
+ return 0;
+}
+
static const struct block_device_operations rbd_bd_ops = {
.owner = THIS_MODULE,
.open = rbd_open,
+ .release = rbd_release,
};
/*
int ret = -ENOMEM;
init_rwsem(&header->snap_rwsem);
-
header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
snap_count *
return -ERANGE;
}
+static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev)
+{
+ struct rbd_snap *snap;
+
+ while (!list_empty(&rbd_dev->snaps)) {
+ snap = list_first_entry(&rbd_dev->snaps, struct rbd_snap, node);
+ __rbd_remove_snap_dev(rbd_dev, snap);
+ }
+}
+
/*
* only read the first part of the ondisk header, without the snaps info
*/
-static int rbd_update_snaps(struct rbd_device *rbd_dev)
+static int __rbd_update_snaps(struct rbd_device *rbd_dev)
{
int ret;
struct rbd_image_header h;
rbd_dev->header.total_snaps = h.total_snaps;
rbd_dev->header.snapc = h.snapc;
rbd_dev->header.snap_names = h.snap_names;
+ rbd_dev->header.snap_names_len = h.snap_names_len;
rbd_dev->header.snap_sizes = h.snap_sizes;
rbd_dev->header.snapc->seq = snap_seq;
+ ret = __rbd_init_snaps_header(rbd_dev);
+
up_write(&rbd_dev->header.snap_rwsem);
- return 0;
+ return ret;
}
static int rbd_init_disk(struct rbd_device *rbd_dev)
if (rc)
return rc;
+ /* no need to lock here, as rbd_dev is not registered yet */
+ rc = __rbd_init_snaps_header(rbd_dev);
+ if (rc)
+ return rc;
+
rc = rbd_header_set_snap(rbd_dev, rbd_dev->snap_name, &total_size);
if (rc)
return rc;
return rc;
}
-/********************************************************************
- * /sys/class/rbd/
- * add map rados objects to blkdev
- * remove unmap rados objects
- * list show mappings
- *******************************************************************/
+/*
+ sysfs
+*/
+
+static ssize_t rbd_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "%llu\n", (unsigned long long)rbd_dev->header.image_size);
+}
+
+static ssize_t rbd_major_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
-static void class_rbd_release(struct class *cls)
+ return sprintf(buf, "%d\n", rbd_dev->major);
+}
+
+static ssize_t rbd_client_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- kfree(cls);
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "client%lld\n", ceph_client_id(rbd_dev->client));
}
-static ssize_t class_rbd_list(struct class *c,
- struct class_attribute *attr,
- char *data)
+static ssize_t rbd_pool_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- int n = 0;
- struct list_head *tmp;
- int max = PAGE_SIZE;
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "%s\n", rbd_dev->pool_name);
+}
+
+static ssize_t rbd_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "%s\n", rbd_dev->obj);
+}
+
+static ssize_t rbd_snap_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "%s\n", rbd_dev->snap_name);
+}
+
+static ssize_t rbd_image_refresh(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ int rc;
+ int ret = size;
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- n += snprintf(data, max,
- "#id\tmajor\tclient_name\tpool\tname\tsnap\tKB\n");
+ rc = __rbd_update_snaps(rbd_dev);
+ if (rc < 0)
+ ret = rc;
- list_for_each(tmp, &rbd_dev_list) {
- struct rbd_device *rbd_dev;
+ mutex_unlock(&ctl_mutex);
+ return ret;
+}
- rbd_dev = list_entry(tmp, struct rbd_device, node);
- n += snprintf(data+n, max-n,
- "%d\t%d\tclient%lld\t%s\t%s\t%s\t%lld\n",
- rbd_dev->id,
- rbd_dev->major,
- ceph_client_id(rbd_dev->client),
- rbd_dev->pool_name,
- rbd_dev->obj, rbd_dev->snap_name,
- rbd_dev->header.image_size >> 10);
- if (n == max)
+static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL);
+static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL);
+static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL);
+static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL);
+static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL);
+static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh);
+static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL);
+static DEVICE_ATTR(create_snap, S_IWUSR, NULL, rbd_snap_add);
+static DEVICE_ATTR(rollback_snap, S_IWUSR, NULL, rbd_snap_rollback);
+
+static struct attribute *rbd_attrs[] = {
+ &dev_attr_size.attr,
+ &dev_attr_major.attr,
+ &dev_attr_client_id.attr,
+ &dev_attr_pool.attr,
+ &dev_attr_name.attr,
+ &dev_attr_current_snap.attr,
+ &dev_attr_refresh.attr,
+ &dev_attr_create_snap.attr,
+ &dev_attr_rollback_snap.attr,
+ NULL
+};
+
+static struct attribute_group rbd_attr_group = {
+ .attrs = rbd_attrs,
+};
+
+static const struct attribute_group *rbd_attr_groups[] = {
+ &rbd_attr_group,
+ NULL
+};
+
+static void rbd_sysfs_dev_release(struct device *dev)
+{
+}
+
+static struct device_type rbd_device_type = {
+ .name = "rbd",
+ .groups = rbd_attr_groups,
+ .release = rbd_sysfs_dev_release,
+};
+
+
+/*
+ sysfs - snapshots
+*/
+
+static ssize_t rbd_snap_size_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
+
+ return sprintf(buf, "%lld\n", (long long)snap->size);
+}
+
+static ssize_t rbd_snap_id_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
+
+ return sprintf(buf, "%lld\n", (long long)snap->id);
+}
+
+static DEVICE_ATTR(snap_size, S_IRUGO, rbd_snap_size_show, NULL);
+static DEVICE_ATTR(snap_id, S_IRUGO, rbd_snap_id_show, NULL);
+
+static struct attribute *rbd_snap_attrs[] = {
+ &dev_attr_snap_size.attr,
+ &dev_attr_snap_id.attr,
+ NULL,
+};
+
+static struct attribute_group rbd_snap_attr_group = {
+ .attrs = rbd_snap_attrs,
+};
+
+static void rbd_snap_dev_release(struct device *dev)
+{
+ struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
+ kfree(snap->name);
+ kfree(snap);
+}
+
+static const struct attribute_group *rbd_snap_attr_groups[] = {
+ &rbd_snap_attr_group,
+ NULL
+};
+
+static struct device_type rbd_snap_device_type = {
+ .groups = rbd_snap_attr_groups,
+ .release = rbd_snap_dev_release,
+};
+
+static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
+ struct rbd_snap *snap)
+{
+ list_del(&snap->node);
+ device_unregister(&snap->dev);
+}
+
+static int rbd_register_snap_dev(struct rbd_device *rbd_dev,
+ struct rbd_snap *snap,
+ struct device *parent)
+{
+ struct device *dev = &snap->dev;
+ int ret;
+
+ dev->type = &rbd_snap_device_type;
+ dev->parent = parent;
+ dev->release = rbd_snap_dev_release;
+ dev_set_name(dev, "snap_%s", snap->name);
+ ret = device_register(dev);
+
+ return ret;
+}
+
+static int __rbd_add_snap_dev(struct rbd_device *rbd_dev,
+ int i, const char *name,
+ struct rbd_snap **snapp)
+{
+ int ret;
+ struct rbd_snap *snap = kzalloc(sizeof(*snap), GFP_KERNEL);
+ if (!snap)
+ return -ENOMEM;
+ snap->name = kstrdup(name, GFP_KERNEL);
+ snap->size = rbd_dev->header.snap_sizes[i];
+ snap->id = rbd_dev->header.snapc->snaps[i];
+ if (device_is_registered(&rbd_dev->dev)) {
+ ret = rbd_register_snap_dev(rbd_dev, snap,
+ &rbd_dev->dev);
+ if (ret < 0)
+ goto err;
+ }
+ *snapp = snap;
+ return 0;
+err:
+ kfree(snap->name);
+ kfree(snap);
+ return ret;
+}
+
+/*
+ * search for the previous snap in a null delimited string list
+ */
+const char *rbd_prev_snap_name(const char *name, const char *start)
+{
+ if (name < start + 2)
+ return NULL;
+
+ name -= 2;
+ while (*name) {
+ if (name == start)
+ return start;
+ name--;
+ }
+ return name + 1;
+}
+
+/*
+ * compare the old list of snapshots that we have to what's in the header
+ * and update it accordingly. Note that the header holds the snapshots
+ * in a reverse order (from newest to oldest) and we need to go from
+ * older to new so that we don't get a duplicate snap name when
+ * doing the process (e.g., removed snapshot and recreated a new
+ * one with the same name.
+ */
+static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
+{
+ const char *name, *first_name;
+ int i = rbd_dev->header.total_snaps;
+ struct rbd_snap *snap, *old_snap = NULL;
+ int ret;
+ struct list_head *p, *n;
+
+ first_name = rbd_dev->header.snap_names;
+ name = first_name + rbd_dev->header.snap_names_len;
+
+ list_for_each_prev_safe(p, n, &rbd_dev->snaps) {
+ u64 cur_id;
+
+ old_snap = list_entry(p, struct rbd_snap, node);
+
+ if (i)
+ cur_id = rbd_dev->header.snapc->snaps[i - 1];
+
+ if (!i || old_snap->id < cur_id) {
+ /* old_snap->id was skipped, thus was removed */
+ __rbd_remove_snap_dev(rbd_dev, old_snap);
+ continue;
+ }
+ if (old_snap->id == cur_id) {
+ /* we have this snapshot already */
+ i--;
+ name = rbd_prev_snap_name(name, first_name);
+ continue;
+ }
+ for (; i > 0;
+ i--, name = rbd_prev_snap_name(name, first_name)) {
+ if (!name) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ cur_id = rbd_dev->header.snapc->snaps[i];
+ /* snapshot removal? handle it above */
+ if (cur_id >= old_snap->id)
+ break;
+ /* a new snapshot */
+ ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap);
+ if (ret < 0)
+ return ret;
+
+ /* note that we add it backward so using n and not p */
+ list_add(&snap->node, n);
+ p = &snap->node;
+ }
+ }
+ /* we're done going over the old snap list, just add what's left */
+ for (; i > 0; i--) {
+ name = rbd_prev_snap_name(name, first_name);
+ if (!name) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap);
+ if (ret < 0)
+ return ret;
+ list_add(&snap->node, &rbd_dev->snaps);
+ }
+
+ return 0;
+}
+
+
+static void rbd_root_dev_release(struct device *dev)
+{
+}
+
+static struct device rbd_root_dev = {
+ .init_name = "rbd",
+ .release = rbd_root_dev_release,
+};
+
+static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
+{
+ int ret = -ENOMEM;
+ struct device *dev;
+ struct rbd_snap *snap;
+
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+ dev = &rbd_dev->dev;
+
+ dev->bus = &rbd_bus_type;
+ dev->type = &rbd_device_type;
+ dev->parent = &rbd_root_dev;
+ dev->release = rbd_dev_release;
+ dev_set_name(dev, "%d", rbd_dev->id);
+ ret = device_register(dev);
+ if (ret < 0)
+ goto done_free;
+
+ list_for_each_entry(snap, &rbd_dev->snaps, node) {
+ ret = rbd_register_snap_dev(rbd_dev, snap,
+ &rbd_dev->dev);
+ if (ret < 0)
break;
}
mutex_unlock(&ctl_mutex);
- return n;
+ return 0;
+done_free:
+ mutex_unlock(&ctl_mutex);
+ return ret;
}
-static ssize_t class_rbd_add(struct class *c,
- struct class_attribute *attr,
- const char *buf, size_t count)
+static void rbd_bus_del_dev(struct rbd_device *rbd_dev)
+{
+ device_unregister(&rbd_dev->dev);
+}
+
+static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count)
{
struct ceph_osd_client *osdc;
struct rbd_device *rbd_dev;
/* static rbd_device initialization */
spin_lock_init(&rbd_dev->lock);
INIT_LIST_HEAD(&rbd_dev->node);
+ INIT_LIST_HEAD(&rbd_dev->snaps);
/* generate unique id: find highest unique id, add one */
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
}
rbd_dev->major = irc;
+ rc = rbd_bus_add_dev(rbd_dev);
+ if (rc)
+ goto err_out_disk;
/* set up and announce blkdev mapping */
rc = rbd_init_disk(rbd_dev);
if (rc)
err_out_blkdev:
unregister_blkdev(rbd_dev->major, rbd_dev->name);
+err_out_disk:
+ rbd_free_disk(rbd_dev);
err_out_client:
rbd_put_client(rbd_dev);
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
return NULL;
}
-static ssize_t class_rbd_remove(struct class *c,
- struct class_attribute *attr,
- const char *buf,
- size_t count)
+static void rbd_dev_release(struct device *dev)
{
- struct rbd_device *rbd_dev = NULL;
- int target_id, rc;
- unsigned long ul;
-
- rc = strict_strtoul(buf, 10, &ul);
- if (rc)
- return rc;
-
- /* convert to int; abort if we lost anything in the conversion */
- target_id = (int) ul;
- if (target_id != ul)
- return -EINVAL;
-
- /* remove object from list immediately */
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
- rbd_dev = __rbd_get_dev(target_id);
- if (rbd_dev)
- list_del_init(&rbd_dev->node);
-
- mutex_unlock(&ctl_mutex);
-
- if (!rbd_dev)
- return -ENOENT;
+ struct rbd_device *rbd_dev =
+ container_of(dev, struct rbd_device, dev);
rbd_put_client(rbd_dev);
/* release module ref */
module_put(THIS_MODULE);
-
- return count;
}
-static ssize_t class_rbd_snaps_list(struct class *c,
- struct class_attribute *attr,
- char *data)
-{
- struct rbd_device *rbd_dev = NULL;
- struct list_head *tmp;
- struct rbd_image_header *header;
- int i, n = 0, max = PAGE_SIZE;
- int ret;
-
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
- n += snprintf(data, max, "#id\tsnap\tKB\n");
-
- list_for_each(tmp, &rbd_dev_list) {
- char *names, *p;
- struct ceph_snap_context *snapc;
-
- rbd_dev = list_entry(tmp, struct rbd_device, node);
- header = &rbd_dev->header;
-
- down_read(&header->snap_rwsem);
-
- names = header->snap_names;
- snapc = header->snapc;
-
- n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n",
- rbd_dev->id, RBD_SNAP_HEAD_NAME,
- header->image_size >> 10,
- (!rbd_dev->cur_snap ? " (*)" : ""));
- if (n == max)
- break;
-
- p = names;
- for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) {
- n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n",
- rbd_dev->id, p, header->snap_sizes[i] >> 10,
- (rbd_dev->cur_snap &&
- (snap_index(header, i) == rbd_dev->cur_snap) ?
- " (*)" : ""));
- if (n == max)
- break;
- }
-
- up_read(&header->snap_rwsem);
- }
-
-
- ret = n;
- mutex_unlock(&ctl_mutex);
- return ret;
-}
-
-static ssize_t class_rbd_snaps_refresh(struct class *c,
- struct class_attribute *attr,
- const char *buf,
- size_t count)
+static ssize_t rbd_remove(struct bus_type *bus,
+ const char *buf,
+ size_t count)
{
struct rbd_device *rbd_dev = NULL;
int target_id, rc;
goto done;
}
- rc = rbd_update_snaps(rbd_dev);
- if (rc < 0)
- ret = rc;
+ list_del_init(&rbd_dev->node);
+
+ __rbd_remove_all_snaps(rbd_dev);
+ rbd_bus_del_dev(rbd_dev);
done:
mutex_unlock(&ctl_mutex);
return ret;
}
-static ssize_t class_rbd_snap_create(struct class *c,
- struct class_attribute *attr,
- const char *buf,
- size_t count)
+static ssize_t rbd_snap_add(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
{
- struct rbd_device *rbd_dev = NULL;
- int target_id, ret;
- char *name;
-
- name = kmalloc(RBD_MAX_SNAP_NAME_LEN + 1, GFP_KERNEL);
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ int ret;
+ char *name = kmalloc(count + 1, GFP_KERNEL);
if (!name)
return -ENOMEM;
- /* parse snaps add command */
- if (sscanf(buf, "%d "
- "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
- &target_id,
- name) != 2) {
- ret = -EINVAL;
- goto done;
- }
+ snprintf(name, count, "%s", buf);
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- rbd_dev = __rbd_get_dev(target_id);
- if (!rbd_dev) {
- ret = -ENOENT;
- goto done_unlock;
- }
-
ret = rbd_header_add_snap(rbd_dev,
name, GFP_KERNEL);
if (ret < 0)
goto done_unlock;
- ret = rbd_update_snaps(rbd_dev);
+ ret = __rbd_update_snaps(rbd_dev);
if (ret < 0)
goto done_unlock;
ret = count;
done_unlock:
mutex_unlock(&ctl_mutex);
-done:
kfree(name);
return ret;
}
-static ssize_t class_rbd_rollback(struct class *c,
- struct class_attribute *attr,
- const char *buf,
- size_t count)
+static ssize_t rbd_snap_rollback(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
{
- struct rbd_device *rbd_dev = NULL;
- int target_id, ret;
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ int ret;
u64 snapid;
- char snap_name[RBD_MAX_SNAP_NAME_LEN];
u64 cur_ofs;
- char *seg_name;
+ char *seg_name = NULL;
+ char *snap_name = kmalloc(count + 1, GFP_KERNEL);
+ ret = -ENOMEM;
+ if (!snap_name)
+ return ret;
/* parse snaps add command */
- if (sscanf(buf, "%d "
- "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
- &target_id,
- snap_name) != 2) {
- return -EINVAL;
- }
-
- ret = -ENOMEM;
+ snprintf(snap_name, count, "%s", buf);
seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO);
if (!seg_name)
- return ret;
+ goto done;
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- rbd_dev = __rbd_get_dev(target_id);
- if (!rbd_dev) {
- ret = -ENOENT;
- goto done_unlock;
- }
-
ret = snap_by_name(&rbd_dev->header, snap_name, &snapid, NULL);
if (ret < 0)
goto done_unlock;
seg_name, ret);
}
- ret = rbd_update_snaps(rbd_dev);
+ ret = __rbd_update_snaps(rbd_dev);
if (ret < 0)
goto done_unlock;
done_unlock:
mutex_unlock(&ctl_mutex);
+done:
kfree(seg_name);
+ kfree(snap_name);
return ret;
}
-static struct class_attribute class_rbd_attrs[] = {
- __ATTR(add, 0200, NULL, class_rbd_add),
- __ATTR(remove, 0200, NULL, class_rbd_remove),
- __ATTR(list, 0444, class_rbd_list, NULL),
- __ATTR(snaps_refresh, 0200, NULL, class_rbd_snaps_refresh),
- __ATTR(snap_create, 0200, NULL, class_rbd_snap_create),
- __ATTR(snaps_list, 0444, class_rbd_snaps_list, NULL),
- __ATTR(snap_rollback, 0200, NULL, class_rbd_rollback),
+static struct bus_attribute rbd_bus_attrs[] = {
+ __ATTR(add, S_IWUSR, NULL, rbd_add),
+ __ATTR(remove, S_IWUSR, NULL, rbd_remove),
__ATTR_NULL
};
/*
* create control files in sysfs
- * /sys/class/rbd/...
+ * /sys/bus/rbd/...
*/
static int rbd_sysfs_init(void)
{
- int ret = -ENOMEM;
+ int ret;
- class_rbd = kzalloc(sizeof(*class_rbd), GFP_KERNEL);
- if (!class_rbd)
- goto out;
+ rbd_bus_type.bus_attrs = rbd_bus_attrs;
- class_rbd->name = DRV_NAME;
- class_rbd->owner = THIS_MODULE;
- class_rbd->class_release = class_rbd_release;
- class_rbd->class_attrs = class_rbd_attrs;
+ ret = bus_register(&rbd_bus_type);
+ if (ret < 0)
+ return ret;
- ret = class_register(class_rbd);
- if (ret)
- goto out_class;
- return 0;
+ ret = device_register(&rbd_root_dev);
-out_class:
- kfree(class_rbd);
- class_rbd = NULL;
- pr_err(DRV_NAME ": failed to create class rbd\n");
-out:
return ret;
}
static void rbd_sysfs_cleanup(void)
{
- if (class_rbd)
- class_destroy(class_rbd);
- class_rbd = NULL;
+ device_unregister(&rbd_root_dev);
+ bus_unregister(&rbd_bus_type);
}
int __init rbd_init(void)
static DEFINE_MUTEX(blkfront_mutex);
static const struct block_device_operations xlvbd_block_fops;
-#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
+#define BLK_RING_SIZE __CONST_RING_SIZE(blkif, PAGE_SIZE)
/*
* We have one of these per vbd, whether ide, scsi or 'other'. They
static struct usb_device_id ath3k_table[] = {
/* Atheros AR3011 */
{ USB_DEVICE(0x0CF3, 0x3000) },
+
+ /* Atheros AR3011 with sflash firmware*/
+ { USB_DEVICE(0x0CF3, 0x3002) },
+
{ } /* Terminating entry */
};
/* Broadcom BCM2033 without firmware */
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
+ /* Atheros 3011 with sflash firmware */
+ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- BT_ERR("%s urb %p failed to resubmit (%d)",
+ if (err != -EPERM)
+ BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- BT_ERR("%s urb %p failed to resubmit (%d)",
+ if (err != -EPERM)
+ BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- BT_ERR("%s urb %p failed to resubmit (%d)",
+ if (err != -EPERM)
+ BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include "agp.h"
static void i830_cleanup(void)
{
- kunmap(intel_private.i8xx_page);
- intel_private.i8xx_flush_page = NULL;
+ if (intel_private.i8xx_flush_page) {
+ kunmap(intel_private.i8xx_flush_page);
+ intel_private.i8xx_flush_page = NULL;
+ }
__free_page(intel_private.i8xx_page);
intel_private.i8xx_page = NULL;
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/major.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/interrupt.h>
#include <linux/serial.h>
#include <linux/serialP.h>
-#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/tty_flip.h>
#include <linux/mm.h>
#include <linux/serial.h>
-#include <linux/smp_lock.h>
#include <linux/fcntl.h>
#include <linux/major.h>
#include <linux/delay.h>
#include <linux/stallion.h>
#include <linux/ioport.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/eisa.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
+#include <linux/acpi.h>
#include "tpm.h"
#define TPM_HEADER_SIZE 10
static LIST_HEAD(tis_chips);
static DEFINE_SPINLOCK(tis_lock);
+#ifdef CONFIG_ACPI
+static int is_itpm(struct pnp_dev *dev)
+{
+ struct acpi_device *acpi = pnp_acpi_device(dev);
+ struct acpi_hardware_id *id;
+
+ list_for_each_entry(id, &acpi->pnp.ids, list) {
+ if (!strcmp("INTC0102", id->id))
+ return 1;
+ }
+
+ return 0;
+}
+#else
+static int is_itpm(struct pnp_dev *dev)
+{
+ return 0;
+}
+#endif
+
static int check_locality(struct tpm_chip *chip, int l)
{
if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
+ if (is_itpm(to_pnp_dev(dev)))
+ itpm = 1;
+
if (itpm)
dev_info(dev, "Intel iTPM workaround enabled\n");
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/math64.h>
-#include <linux/smp_lock.h>
#include <asm/genapic.h>
#include <asm/uv/uv_hub.h>
nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
- if (!vqs) {
- err = -ENOMEM;
- goto fail;
- }
io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
- if (!io_callbacks) {
- err = -ENOMEM;
- goto free_vqs;
- }
io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
- if (!io_names) {
- err = -ENOMEM;
- goto free_callbacks;
- }
portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
GFP_KERNEL);
- if (!portdev->in_vqs) {
- err = -ENOMEM;
- goto free_names;
- }
portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
GFP_KERNEL);
- if (!portdev->out_vqs) {
+ if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
+ !portdev->out_vqs) {
err = -ENOMEM;
- goto free_invqs;
+ goto free;
}
/*
io_callbacks,
(const char **)io_names);
if (err)
- goto free_outvqs;
+ goto free;
j = 0;
portdev->in_vqs[0] = vqs[0];
portdev->out_vqs[i] = vqs[j + 1];
}
}
- kfree(io_callbacks);
kfree(io_names);
+ kfree(io_callbacks);
kfree(vqs);
return 0;
-free_names:
- kfree(io_names);
-free_callbacks:
- kfree(io_callbacks);
-free_outvqs:
+free:
kfree(portdev->out_vqs);
-free_invqs:
kfree(portdev->in_vqs);
-free_vqs:
+ kfree(io_names);
+ kfree(io_callbacks);
kfree(vqs);
-fail:
+
return err;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector.");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_CONNECTOR);
static struct cn_dev cdev;
ifeq ($(CONFIG_DMADEVICES_DEBUG),y)
- EXTRA_CFLAGS += -DDEBUG
+ ccflags-y += -DDEBUG
endif
ifeq ($(CONFIG_DMADEVICES_VDEBUG),y)
- EXTRA_CFLAGS += -DVERBOSE_DEBUG
+ ccflags-y += -DVERBOSE_DEBUG
endif
obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
desc->lli.daddr = mem;
desc->lli.ctrla = ctrla
| ATC_DST_WIDTH(mem_width)
- | len >> mem_width;
+ | len >> reg_width;
desc->lli.ctrlb = ctrlb;
if (!first) {
* EIE - Error interrupt enable
* EOSIE - End of segments interrupt enable (basic mode)
* EOLNIE - End of links interrupt enable
+ * BWC - Bandwidth sharing among channels
*/
- DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EIE
- | FSL_DMA_MR_EOLNIE | FSL_DMA_MR_EOSIE, 32);
+ DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
+ | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE
+ | FSL_DMA_MR_EOSIE, 32);
break;
case FSL_DMA_IP_83XX:
/* Set the channel to below modes:
/*
- * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved.
*
* Author:
* Zhang Wei <wei.zhang@freescale.com>, Jul 2007
#define FSL_DMA_MR_DAHE 0x00002000
#define FSL_DMA_MR_SAHE 0x00001000
+/*
+ * Bandwidth/pause control determines how many bytes a given
+ * channel is allowed to transfer before the DMA engine pauses
+ * the current channel and switches to the next channel
+ */
+#define FSL_DMA_MR_BWC 0x08000000
+
/* Special MR definition for MPC8349 */
#define FSL_DMA_MR_EOTIE 0x00000080
#define FSL_DMA_MR_PRC_RM 0x00000800
return 0;
err_init:
- while (i-- >= 0) {
+ while (--i >= 0) {
struct imxdma_channel *imxdmac = &imxdma->channel[i];
imx_dma_free(imxdmac->imxdma_channel);
}
struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
int param;
- bd->buffer_addr = sgl->dma_address;
+ bd->buffer_addr = sg->dma_address;
count = sg->length;
{
return platform_driver_probe(&sdma_driver, sdma_probe);
}
-subsys_initcall(sdma_module_init);
+module_init(sdma_module_init);
MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
MODULE_DESCRIPTION("i.MX SDMA driver");
if (NULL == dma->dma_pool) {
pr_err("ERR_MDMA:pci_pool_create failed\n");
err = -ENOMEM;
- kfree(dma);
goto err_dma_pool;
}
free_irq(pdev->irq, dma);
err_irq:
pci_pool_destroy(dma->dma_pool);
- kfree(dma);
err_dma_pool:
pr_err("ERR_MDMA:setup_dma failed: %d\n", err);
return err;
.runtime_idle = dma_runtime_idle,
};
-static struct pci_driver intel_mid_dma_pci = {
+static struct pci_driver intel_mid_dma_pci_driver = {
.name = "Intel MID DMA",
.id_table = intel_mid_dma_ids,
.probe = intel_mid_dma_probe,
{
pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n",
INTEL_MID_DMA_DRIVER_VERSION);
- return pci_register_driver(&intel_mid_dma_pci);
+ return pci_register_driver(&intel_mid_dma_pci_driver);
}
fs_initcall(intel_mid_dma_init);
static void __exit intel_mid_dma_exit(void)
{
- pci_unregister_driver(&intel_mid_dma_pci);
+ pci_unregister_driver(&intel_mid_dma_pci_driver);
}
module_exit(intel_mid_dma_exit);
obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
-ioatdma-objs := pci.o dma.o dma_v2.o dma_v3.o dca.o
+ioatdma-y := pci.o dma.o dma_v2.o dma_v3.o dca.o
return;
}
- channel_writel(pd_chan, DEV_ADDR, desc->regs.dev_addr);
- channel_writel(pd_chan, MEM_ADDR, desc->regs.mem_addr);
- channel_writel(pd_chan, SIZE, desc->regs.size);
- channel_writel(pd_chan, NEXT, desc->regs.next);
-
dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> dev_addr: %x\n",
pd_chan->chan.chan_id, desc->regs.dev_addr);
dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> mem_addr: %x\n",
dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> next: %x\n",
pd_chan->chan.chan_id, desc->regs.next);
- if (list_empty(&desc->tx_list))
+ if (list_empty(&desc->tx_list)) {
+ channel_writel(pd_chan, DEV_ADDR, desc->regs.dev_addr);
+ channel_writel(pd_chan, MEM_ADDR, desc->regs.mem_addr);
+ channel_writel(pd_chan, SIZE, desc->regs.size);
+ channel_writel(pd_chan, NEXT, desc->regs.next);
pdc_set_mode(&pd_chan->chan, DMA_CTL0_ONESHOT);
- else
+ } else {
+ channel_writel(pd_chan, NEXT, desc->txd.phys);
pdc_set_mode(&pd_chan->chan, DMA_CTL0_SG);
+ }
val = dma_readl(pd, CTL2);
val |= 1 << (DMA_CTL2_START_SHIFT_BITS + pd_chan->chan.chan_id);
if (!request_mem_region(res.start, resource_size(&res),
dev_driver_string(&ofdev->dev))) {
- dev_err(&ofdev->dev, "failed to request memory region "
- "(0x%016llx-0x%016llx)\n",
- (u64)res.start, (u64)res.end);
+ dev_err(&ofdev->dev, "failed to request memory region %pR\n",
+ &res);
initcode = PPC_ADMA_INIT_MEMREG;
ret = -EBUSY;
goto out;
MODULE_AUTHOR("Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>");
MODULE_DESCRIPTION("Renesas SH DMA Engine driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh-dma-engine");
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
obj-$(CONFIG_EDAC_MCE) += edac_mce.o
-edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
-edac_core-objs += edac_module.o edac_device_sysfs.o
+edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
+edac_core-y += edac_module.o edac_device_sysfs.o
ifdef CONFIG_PCI
-edac_core-objs += edac_pci.o edac_pci_sysfs.o
+edac_core-y += edac_pci.o edac_pci_sysfs.o
endif
obj-$(CONFIG_EDAC_MCE_INJ) += mce_amd_inj.o
-edac_mce_amd-objs := mce_amd.o
+edac_mce_amd-y := mce_amd.o
obj-$(CONFIG_EDAC_DECODE_MCE) += edac_mce_amd.o
obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o
debugf1(" HoleOffset=0x%x HoleValid=0x%x IntlvSel=0x%x\n",
hole_off, hole_valid, intlv_sel);
- if (intlv_en ||
+ if (intlv_en &&
(intlv_sel != ((sys_addr >> 12) & intlv_en)))
return -EINVAL;
#define MC_PROC_NAME_MAX_LEN 7
#if PAGE_SHIFT < 20
-#define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) )
-#define MiB_TO_PAGES(mb) ((mb) >> (20 - PAGE_SHIFT))
+#define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT))
+#define MiB_TO_PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
#else /* PAGE_SHIFT > 20 */
-#define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) )
+#define PAGES_TO_MiB(pages) ((pages) << (PAGE_SHIFT - 20))
#define MiB_TO_PAGES(mb) ((mb) >> (PAGE_SHIFT - 20))
#endif
return NULL;
}
- /* marking MCI offline */
- mci->op_state = OP_OFFLINE;
-
del_mc_from_global_list(mci);
mutex_unlock(&mem_ctls_mutex);
- /* flush workq processes and remove sysfs */
+ /* flush workq processes */
edac_mc_workq_teardown(mci);
+
+ /* marking MCI offline */
+ mci->op_state = OP_OFFLINE;
+
+ /* remove from sysfs */
edac_remove_sysfs_mci_device(mci);
edac_printk(KERN_INFO, EDAC_MC,
return 0;
err_sysfs_create:
- while (i-- >= 0)
+ while (--i >= 0)
sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr);
kobject_del(mce_kobj);
*/
#include <linux/bug.h>
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
#include <asm/unaligned.h>
#include <net/arp.h>
-#define FWNET_MAX_FRAGMENTS 25 /* arbitrary limit */
-#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16 * 1024 ? 4 : 2)
+/* rx limits */
+#define FWNET_MAX_FRAGMENTS 30 /* arbitrary, > TX queue depth */
+#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16*1024 ? 4 : 2)
+
+/* tx limits */
+#define FWNET_MAX_QUEUED_DATAGRAMS 20 /* < 64 = number of tlabels */
+#define FWNET_MIN_QUEUED_DATAGRAMS 10 /* should keep AT DMA busy enough */
+#define FWNET_TX_QUEUE_LEN FWNET_MAX_QUEUED_DATAGRAMS /* ? */
#define IEEE1394_BROADCAST_CHANNEL 31
#define IEEE1394_ALL_NODES (0xffc0 | 0x003f)
struct fw_address_handler handler;
u64 local_fifo;
- /* List of packets to be sent */
- struct list_head packet_list;
- /*
- * List of packets that were broadcasted. When we get an ISO interrupt
- * one of them has been sent
- */
- struct list_head broadcasted_list;
- /* List of packets that have been sent but not yet acked */
- struct list_head sent_list;
+ /* Number of tx datagrams that have been queued but not yet acked */
+ int queued_datagrams;
struct list_head peer_list;
struct fw_card *card;
unsigned pdg_size; /* pd_list size */
u16 datagram_label; /* outgoing datagram label */
- unsigned max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */
+ u16 max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */
int node_id;
int generation;
unsigned speed;
/* This is our task struct. It's used for the packet complete callback. */
struct fwnet_packet_task {
- /*
- * ptask can actually be on dev->packet_list, dev->broadcasted_list,
- * or dev->sent_list depending on its current state.
- */
- struct list_head pt_link;
struct fw_transaction transaction;
struct rfc2734_header hdr;
struct sk_buff *skb;
struct fwnet_device *dev;
int outstanding_pkts;
- unsigned max_payload;
u64 fifo_addr;
u16 dest_node;
+ u16 max_payload;
u8 generation;
u8 speed;
+ u8 enqueued;
};
/*
net->stats.rx_packets++;
net->stats.rx_bytes += skb->len;
}
- if (netif_queue_stopped(net))
- netif_wake_queue(net);
return 0;
net->stats.rx_dropped++;
dev_kfree_skb_any(skb);
- if (netif_queue_stopped(net))
- netif_wake_queue(net);
return -ENOENT;
}
* Datagram is not complete, we're done for the
* moment.
*/
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return 0;
+ retval = 0;
fail:
spin_unlock_irqrestore(&dev->lock, flags);
- if (netif_queue_stopped(net))
- netif_wake_queue(net);
-
return retval;
}
kmem_cache_free(fwnet_packet_task_cache, ptask);
}
+/* Caller must hold dev->lock. */
+static void dec_queued_datagrams(struct fwnet_device *dev)
+{
+ if (--dev->queued_datagrams == FWNET_MIN_QUEUED_DATAGRAMS)
+ netif_wake_queue(dev->netdev);
+}
+
static int fwnet_send_packet(struct fwnet_packet_task *ptask);
static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
{
struct fwnet_device *dev = ptask->dev;
+ struct sk_buff *skb = ptask->skb;
unsigned long flags;
bool free;
ptask->outstanding_pkts--;
/* Check whether we or the networking TX soft-IRQ is last user. */
- free = (ptask->outstanding_pkts == 0 && !list_empty(&ptask->pt_link));
+ free = (ptask->outstanding_pkts == 0 && ptask->enqueued);
+ if (free)
+ dec_queued_datagrams(dev);
- if (ptask->outstanding_pkts == 0)
- list_del(&ptask->pt_link);
+ if (ptask->outstanding_pkts == 0) {
+ dev->netdev->stats.tx_packets++;
+ dev->netdev->stats.tx_bytes += skb->len;
+ }
spin_unlock_irqrestore(&dev->lock, flags);
u16 fg_off;
u16 datagram_label;
u16 lf;
- struct sk_buff *skb;
/* Update the ptask to point to the next fragment and send it */
lf = fwnet_get_hdr_lf(&ptask->hdr);
datagram_label = fwnet_get_hdr_dgl(&ptask->hdr);
break;
}
- skb = ptask->skb;
+
skb_pull(skb, ptask->max_payload);
if (ptask->outstanding_pkts > 1) {
fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG,
fwnet_free_ptask(ptask);
}
+static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask)
+{
+ struct fwnet_device *dev = ptask->dev;
+ unsigned long flags;
+ bool free;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* One fragment failed; don't try to send remaining fragments. */
+ ptask->outstanding_pkts = 0;
+
+ /* Check whether we or the networking TX soft-IRQ is last user. */
+ free = ptask->enqueued;
+ if (free)
+ dec_queued_datagrams(dev);
+
+ dev->netdev->stats.tx_dropped++;
+ dev->netdev->stats.tx_errors++;
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ if (free)
+ fwnet_free_ptask(ptask);
+}
+
static void fwnet_write_complete(struct fw_card *card, int rcode,
void *payload, size_t length, void *data)
{
ptask = data;
- if (rcode == RCODE_COMPLETE)
+ if (rcode == RCODE_COMPLETE) {
fwnet_transmit_packet_done(ptask);
- else
+ } else {
fw_error("fwnet_write_complete: failed: %x\n", rcode);
- /* ??? error recovery */
+ fwnet_transmit_packet_failed(ptask);
+ }
}
static int fwnet_send_packet(struct fwnet_packet_task *ptask)
spin_lock_irqsave(&dev->lock, flags);
/* If the AT tasklet already ran, we may be last user. */
- free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link));
+ free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
if (!free)
- list_add_tail(&ptask->pt_link, &dev->broadcasted_list);
+ ptask->enqueued = true;
+ else
+ dec_queued_datagrams(dev);
spin_unlock_irqrestore(&dev->lock, flags);
spin_lock_irqsave(&dev->lock, flags);
/* If the AT tasklet already ran, we may be last user. */
- free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link));
+ free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
if (!free)
- list_add_tail(&ptask->pt_link, &dev->sent_list);
+ ptask->enqueued = true;
+ else
+ dec_queued_datagrams(dev);
spin_unlock_irqrestore(&dev->lock, flags);
struct fwnet_peer *peer;
unsigned long flags;
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* Can this happen? */
+ if (netif_queue_stopped(dev->netdev)) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return NETDEV_TX_BUSY;
+ }
+
ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC);
if (ptask == NULL)
goto fail;
proto = hdr_buf.h_proto;
dg_size = skb->len;
- /* serialize access to peer, including peer->datagram_label */
- spin_lock_irqsave(&dev->lock, flags);
-
/*
* Set the transmission type for the packet. ARP packets and IP
* broadcast packets are sent via GASP.
peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR)
- goto fail_unlock;
+ goto fail;
generation = peer->generation;
dest_node = peer->node_id;
max_payload += RFC2374_FRAG_HDR_SIZE;
}
+ if (++dev->queued_datagrams == FWNET_MAX_QUEUED_DATAGRAMS)
+ netif_stop_queue(dev->netdev);
+
spin_unlock_irqrestore(&dev->lock, flags);
ptask->max_payload = max_payload;
- INIT_LIST_HEAD(&ptask->pt_link);
+ ptask->enqueued = 0;
fwnet_send_packet(ptask);
return NETDEV_TX_OK;
- fail_unlock:
- spin_unlock_irqrestore(&dev->lock, flags);
fail:
+ spin_unlock_irqrestore(&dev->lock, flags);
+
if (ptask)
kmem_cache_free(fwnet_packet_task_cache, ptask);
net->addr_len = FWNET_ALEN;
net->hard_header_len = FWNET_HLEN;
net->type = ARPHRD_IEEE1394;
- net->tx_queue_len = 10;
+ net->tx_queue_len = FWNET_TX_QUEUE_LEN;
}
/* caller must hold fwnet_device_mutex */
dev->broadcast_rcv_context = NULL;
dev->broadcast_xmt_max_payload = 0;
dev->broadcast_xmt_datagramlabel = 0;
-
dev->local_fifo = FWNET_NO_FIFO_ADDR;
-
- INIT_LIST_HEAD(&dev->packet_list);
- INIT_LIST_HEAD(&dev->broadcasted_list);
- INIT_LIST_HEAD(&dev->sent_list);
+ dev->queued_datagrams = 0;
INIT_LIST_HEAD(&dev->peer_list);
-
dev->card = card;
dev->netdev = net;
struct fwnet_peer *peer = dev_get_drvdata(_dev);
struct fwnet_device *dev = peer->dev;
struct net_device *net;
- struct fwnet_packet_task *ptask, *pt_next;
+ int i;
mutex_lock(&fwnet_device_mutex);
dev->card);
fw_iso_context_destroy(dev->broadcast_rcv_context);
}
- list_for_each_entry_safe(ptask, pt_next,
- &dev->packet_list, pt_link) {
- dev_kfree_skb_any(ptask->skb);
- kmem_cache_free(fwnet_packet_task_cache, ptask);
- }
- list_for_each_entry_safe(ptask, pt_next,
- &dev->broadcasted_list, pt_link) {
- dev_kfree_skb_any(ptask->skb);
- kmem_cache_free(fwnet_packet_task_cache, ptask);
- }
- list_for_each_entry_safe(ptask, pt_next,
- &dev->sent_list, pt_link) {
- dev_kfree_skb_any(ptask->skb);
- kmem_cache_free(fwnet_packet_task_cache, ptask);
- }
+ for (i = 0; dev->queued_datagrams && i < 5; i++)
+ ssleep(1);
+ WARN_ON(dev->queued_datagrams);
list_del(&dev->dev_link);
free_netdev(net);
static char ohci_driver_name[] = KBUILD_MODNAME;
+#define PCI_DEVICE_ID_AGERE_FW643 0x5901
#define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380
#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009
/* In case of multiple matches in ohci_quirks[], only the first one is used. */
static const struct {
- unsigned short vendor, device, flags;
+ unsigned short vendor, device, revision, flags;
} ohci_quirks[] = {
- {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, QUIRK_CYCLE_TIMER |
- QUIRK_RESET_PACKET |
- QUIRK_NO_1394A},
- {PCI_VENDOR_ID_TI, PCI_ANY_ID, QUIRK_RESET_PACKET},
- {PCI_VENDOR_ID_AL, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
- {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, QUIRK_NO_MSI},
- {PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
- {PCI_VENDOR_ID_VIA, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
- {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
- {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS},
+ {PCI_VENDOR_ID_AL, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_CYCLE_TIMER},
+
+ {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, PCI_ANY_ID,
+ QUIRK_BE_HEADERS},
+
+ {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6,
+ QUIRK_NO_MSI},
+
+ {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, PCI_ANY_ID,
+ QUIRK_NO_MSI},
+
+ {PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_CYCLE_TIMER},
+
+ {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_CYCLE_TIMER},
+
+ {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID,
+ QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A},
+
+ {PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_RESET_PACKET},
+
+ {PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_CYCLE_TIMER | QUIRK_NO_MSI},
};
/* This overrides anything that was found in ohci_quirks[]. */
}
for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++)
- if (ohci_quirks[i].vendor == dev->vendor &&
- (ohci_quirks[i].device == dev->device ||
- ohci_quirks[i].device == (unsigned short)PCI_ANY_ID)) {
+ if ((ohci_quirks[i].vendor == dev->vendor) &&
+ (ohci_quirks[i].device == (unsigned short)PCI_ANY_ID ||
+ ohci_quirks[i].device == dev->device) &&
+ (ohci_quirks[i].revision == (unsigned short)PCI_ANY_ID ||
+ ohci_quirks[i].revision >= dev->revision)) {
ohci->quirks = ohci_quirks[i].flags;
break;
}
/* SCSI stack integration */
-static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
+static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done)
{
struct sbp2_logical_unit *lu = cmd->device->hostdata;
struct fw_device *device = target_device(lu->tgt);
return retval;
}
+static DEF_SCSI_QCMD(sbp2_scsi_queuecommand)
+
static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
{
struct sbp2_logical_unit *lu = sdev->hostdata;
* registers, see include/linux/cs5535.h.
*/
+static void errata_outl(u32 val, unsigned long addr)
+{
+ /*
+ * According to the CS5536 errata (#36), after suspend
+ * a write to the high bank GPIO register will clear all
+ * non-selected bits; the recommended workaround is a
+ * read-modify-write operation.
+ */
+ val |= inl(addr);
+ outl(val, addr);
+}
+
static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset,
unsigned int reg)
{
outl(1 << offset, chip->base + reg);
else
/* high bank register */
- outl(1 << (offset - 16), chip->base + 0x80 + reg);
+ errata_outl(1 << (offset - 16), chip->base + 0x80 + reg);
}
void cs5535_gpio_set(unsigned offset, unsigned int reg)
outl(1 << (offset + 16), chip->base + reg);
else
/* high bank register */
- outl(1 << offset, chip->base + 0x80 + reg);
+ errata_outl(1 << offset, chip->base + 0x80 + reg);
}
void cs5535_gpio_clear(unsigned offset, unsigned int reg)
{ DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 },
{ DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 },
{ DRM_MODE_CONNECTOR_Component, "Component", 0 },
- { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN", 0 },
- { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort", 0 },
- { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A", 0 },
- { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B", 0 },
+ { DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 },
+ { DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 },
+ { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 },
+ { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 },
{ DRM_MODE_CONNECTOR_TV, "TV", 0 },
- { DRM_MODE_CONNECTOR_eDP, "Embedded DisplayPort", 0 },
+ { DRM_MODE_CONNECTOR_eDP, "eDP", 0 },
};
static struct drm_prop_enum_list drm_encoder_enum_list[] =
}
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- if (!drm_helper_encoder_in_use(encoder)) {
+ if (encoder->crtc && !drm_helper_encoder_in_use(encoder)) {
drm_encoder_disable(encoder);
/* disconnector encoder from any connector */
encoder->crtc = NULL;
int count = 0, ro, fail = 0;
struct drm_crtc_helper_funcs *crtc_funcs;
int ret = 0;
+ int i;
DRM_DEBUG_KMS("\n");
if (ret != 0)
goto fail;
}
+ DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+ for (i = 0; i < set->num_connectors; i++) {
+ DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+ drm_get_connector_name(set->connectors[i]));
+ set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
+ }
kfree(save_connectors);
kfree(save_encoders);
struct delayed_work *delayed_work = to_delayed_work(work);
struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
struct drm_connector *connector;
- enum drm_connector_status old_status, status;
+ enum drm_connector_status old_status;
bool repoll = false, changed = false;
if (!drm_kms_helper_poll)
!(connector->polled & DRM_CONNECTOR_POLL_HPD))
continue;
- status = connector->funcs->detect(connector, false);
- if (old_status != status)
+ connector->status = connector->funcs->detect(connector, false);
+ DRM_DEBUG_KMS("connector status updated to %d\n", connector->status);
+ if (old_status != connector->status)
changed = true;
}
#include "drmP.h"
#include <linux/poll.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
/* from BKL pushdown: note that nothing else serializes idr_find() */
DEFINE_MUTEX(drm_global_mutex);
struct timeval now;
unsigned long flags;
unsigned int seq;
+ int ret;
e = kzalloc(sizeof *e, GFP_KERNEL);
- if (e == NULL)
- return -ENOMEM;
+ if (e == NULL) {
+ ret = -ENOMEM;
+ goto err_put;
+ }
e->pipe = pipe;
e->base.pid = current->pid;
spin_lock_irqsave(&dev->event_lock, flags);
if (file_priv->event_space < sizeof e->event) {
- spin_unlock_irqrestore(&dev->event_lock, flags);
- kfree(e);
- return -ENOMEM;
+ ret = -EBUSY;
+ goto err_unlock;
}
file_priv->event_space -= sizeof e->event;
if ((seq - vblwait->request.sequence) <= (1 << 23)) {
e->event.tv_sec = now.tv_sec;
e->event.tv_usec = now.tv_usec;
- drm_vblank_put(dev, e->pipe);
+ drm_vblank_put(dev, pipe);
list_add_tail(&e->base.link, &e->base.file_priv->event_list);
wake_up_interruptible(&e->base.file_priv->event_wait);
trace_drm_vblank_event_delivered(current->pid, pipe,
spin_unlock_irqrestore(&dev->event_lock, flags);
return 0;
+
+err_unlock:
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ kfree(e);
+err_put:
+ drm_vblank_put(dev, pipe);
+ return ret;
}
/**
case I915_PARAM_HAS_BLT:
value = HAS_BLT(dev);
break;
+ case I915_PARAM_HAS_COHERENT_RINGS:
+ value = 1;
+ break;
default:
DRM_DEBUG_DRIVER("Unknown parameter %d\n",
param->param);
static const struct intel_device_info intel_ironlake_m_info = {
.gen = 5, .is_mobile = 1,
- .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+ .need_gfx_hws = 1, .has_rc6 = 1, .has_hotplug = 1,
+ .has_fbc = 0, /* disabled due to buggy hardware */
.has_bsd_ring = 1,
};
int i915_gem_object_set_domain(struct drm_gem_object *obj,
uint32_t read_domains,
uint32_t write_domain);
+int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
+ bool interruptible);
int i915_gem_init_ringbuffer(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
int i915_gem_do_init(struct drm_device *dev, unsigned long start,
static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj);
-static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
- bool pipelined);
+static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj,
struct drm_i915_gem_object *obj_priv;
int ret = 0;
+ if (args->size == 0)
+ return 0;
+
+ if (!access_ok(VERIFY_WRITE,
+ (char __user *)(uintptr_t)args->data_ptr,
+ args->size))
+ return -EFAULT;
+
+ ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
+ args->size);
+ if (ret)
+ return -EFAULT;
+
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
goto out;
}
- if (args->size == 0)
- goto out;
-
- if (!access_ok(VERIFY_WRITE,
- (char __user *)(uintptr_t)args->data_ptr,
- args->size)) {
- ret = -EFAULT;
- goto out;
- }
-
- ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
- args->size);
- if (ret) {
- ret = -EFAULT;
- goto out;
- }
-
ret = i915_gem_object_get_pages_or_evict(obj);
if (ret)
goto out;
struct drm_i915_gem_pwrite *args = data;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
- int ret = 0;
+ int ret;
+
+ if (args->size == 0)
+ return 0;
+
+ if (!access_ok(VERIFY_READ,
+ (char __user *)(uintptr_t)args->data_ptr,
+ args->size))
+ return -EFAULT;
+
+ ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
+ args->size);
+ if (ret)
+ return -EFAULT;
ret = i915_mutex_lock_interruptible(dev);
if (ret)
}
obj_priv = to_intel_bo(obj);
-
/* Bounds check destination. */
if (args->offset > obj->size || args->size > obj->size - args->offset) {
ret = -EINVAL;
goto out;
}
- if (args->size == 0)
- goto out;
-
- if (!access_ok(VERIFY_READ,
- (char __user *)(uintptr_t)args->data_ptr,
- args->size)) {
- ret = -EFAULT;
- goto out;
- }
-
- ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
- args->size);
- if (ret) {
- ret = -EFAULT;
- goto out;
- }
-
/* We can only do the GTT pwrite on untiled buffers, as otherwise
* it would end up going through the fenced access, and we'll get
* different detiling behavior between reading and writing.
if (reg->gpu) {
int ret;
- ret = i915_gem_object_flush_gpu_write_domain(obj, true);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret)
return ret;
/** Flushes any GPU write domain for the object if it's dirty. */
static int
-i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
- bool pipelined)
+i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
uint32_t old_write_domain;
obj->read_domains,
old_write_domain);
- if (pipelined)
- return 0;
-
- return i915_gem_object_wait_rendering(obj, true);
+ return 0;
}
/** Flushes the GTT write domain for the object if it's dirty. */
if (obj_priv->gtt_space == NULL)
return -EINVAL;
- ret = i915_gem_object_flush_gpu_write_domain(obj, false);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret != 0)
return ret;
+ ret = i915_gem_object_wait_rendering(obj, true);
+ if (ret)
+ return ret;
i915_gem_object_flush_cpu_write_domain(obj);
- if (write) {
- ret = i915_gem_object_wait_rendering(obj, true);
- if (ret)
- return ret;
- }
-
old_write_domain = obj->write_domain;
old_read_domains = obj->read_domains;
if (obj_priv->gtt_space == NULL)
return -EINVAL;
- ret = i915_gem_object_flush_gpu_write_domain(obj, true);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret)
return ret;
return 0;
}
+int
+i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
+ bool interruptible)
+{
+ if (!obj->active)
+ return 0;
+
+ if (obj->base.write_domain & I915_GEM_GPU_DOMAINS)
+ i915_gem_flush_ring(obj->base.dev, NULL, obj->ring,
+ 0, obj->base.write_domain);
+
+ return i915_gem_object_wait_rendering(&obj->base, interruptible);
+}
+
/**
* Moves a single object to the CPU read, and possibly write domain.
*
uint32_t old_write_domain, old_read_domains;
int ret;
- ret = i915_gem_object_flush_gpu_write_domain(obj, false);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret != 0)
return ret;
+ ret = i915_gem_object_wait_rendering(obj, true);
+ if (ret)
+ return ret;
i915_gem_object_flush_gtt_write_domain(obj);
*/
i915_gem_object_set_to_full_cpu_read_domain(obj);
- if (write) {
- ret = i915_gem_object_wait_rendering(obj, true);
- if (ret)
- return ret;
- }
-
old_write_domain = obj->write_domain;
old_read_domains = obj->read_domains;
if (offset == 0 && size == obj->size)
return i915_gem_object_set_to_cpu_domain(obj, 0);
- ret = i915_gem_object_flush_gpu_write_domain(obj, false);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret != 0)
return ret;
+ ret = i915_gem_object_wait_rendering(obj, true);
+ if (ret)
+ return ret;
+
i915_gem_object_flush_gtt_write_domain(obj);
/* If we're already fully in the CPU read domain, we're done. */
return 0;
}
-/**
- * Pin an object to the GTT and evaluate the relocations landing in it.
- */
static int
-i915_gem_execbuffer_relocate(struct drm_i915_gem_object *obj,
- struct drm_file *file_priv,
- struct drm_i915_gem_exec_object2 *entry)
+i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
+ struct drm_file *file_priv,
+ struct drm_i915_gem_exec_object2 *entry,
+ struct drm_i915_gem_relocation_entry *reloc)
{
struct drm_device *dev = obj->base.dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_relocation_entry __user *user_relocs;
- struct drm_gem_object *target_obj = NULL;
- uint32_t target_handle = 0;
- int i, ret = 0;
+ struct drm_gem_object *target_obj;
+ uint32_t target_offset;
+ int ret = -EINVAL;
- user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
- for (i = 0; i < entry->relocation_count; i++) {
- struct drm_i915_gem_relocation_entry reloc;
- uint32_t target_offset;
+ target_obj = drm_gem_object_lookup(dev, file_priv,
+ reloc->target_handle);
+ if (target_obj == NULL)
+ return -ENOENT;
- if (__copy_from_user_inatomic(&reloc,
- user_relocs+i,
- sizeof(reloc))) {
- ret = -EFAULT;
- break;
- }
+ target_offset = to_intel_bo(target_obj)->gtt_offset;
- if (reloc.target_handle != target_handle) {
- drm_gem_object_unreference(target_obj);
+#if WATCH_RELOC
+ DRM_INFO("%s: obj %p offset %08x target %d "
+ "read %08x write %08x gtt %08x "
+ "presumed %08x delta %08x\n",
+ __func__,
+ obj,
+ (int) reloc->offset,
+ (int) reloc->target_handle,
+ (int) reloc->read_domains,
+ (int) reloc->write_domain,
+ (int) target_offset,
+ (int) reloc->presumed_offset,
+ reloc->delta);
+#endif
- target_obj = drm_gem_object_lookup(dev, file_priv,
- reloc.target_handle);
- if (target_obj == NULL) {
- ret = -ENOENT;
- break;
- }
+ /* The target buffer should have appeared before us in the
+ * exec_object list, so it should have a GTT space bound by now.
+ */
+ if (target_offset == 0) {
+ DRM_ERROR("No GTT space found for object %d\n",
+ reloc->target_handle);
+ goto err;
+ }
- target_handle = reloc.target_handle;
- }
- target_offset = to_intel_bo(target_obj)->gtt_offset;
+ /* Validate that the target is in a valid r/w GPU domain */
+ if (reloc->write_domain & (reloc->write_domain - 1)) {
+ DRM_ERROR("reloc with multiple write domains: "
+ "obj %p target %d offset %d "
+ "read %08x write %08x",
+ obj, reloc->target_handle,
+ (int) reloc->offset,
+ reloc->read_domains,
+ reloc->write_domain);
+ goto err;
+ }
+ if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
+ reloc->read_domains & I915_GEM_DOMAIN_CPU) {
+ DRM_ERROR("reloc with read/write CPU domains: "
+ "obj %p target %d offset %d "
+ "read %08x write %08x",
+ obj, reloc->target_handle,
+ (int) reloc->offset,
+ reloc->read_domains,
+ reloc->write_domain);
+ goto err;
+ }
+ if (reloc->write_domain && target_obj->pending_write_domain &&
+ reloc->write_domain != target_obj->pending_write_domain) {
+ DRM_ERROR("Write domain conflict: "
+ "obj %p target %d offset %d "
+ "new %08x old %08x\n",
+ obj, reloc->target_handle,
+ (int) reloc->offset,
+ reloc->write_domain,
+ target_obj->pending_write_domain);
+ goto err;
+ }
-#if WATCH_RELOC
- DRM_INFO("%s: obj %p offset %08x target %d "
- "read %08x write %08x gtt %08x "
- "presumed %08x delta %08x\n",
- __func__,
- obj,
- (int) reloc.offset,
- (int) reloc.target_handle,
- (int) reloc.read_domains,
- (int) reloc.write_domain,
- (int) target_offset,
- (int) reloc.presumed_offset,
- reloc.delta);
-#endif
+ target_obj->pending_read_domains |= reloc->read_domains;
+ target_obj->pending_write_domain |= reloc->write_domain;
- /* The target buffer should have appeared before us in the
- * exec_object list, so it should have a GTT space bound by now.
- */
- if (target_offset == 0) {
- DRM_ERROR("No GTT space found for object %d\n",
- reloc.target_handle);
- ret = -EINVAL;
- break;
- }
+ /* If the relocation already has the right value in it, no
+ * more work needs to be done.
+ */
+ if (target_offset == reloc->presumed_offset)
+ goto out;
- /* Validate that the target is in a valid r/w GPU domain */
- if (reloc.write_domain & (reloc.write_domain - 1)) {
- DRM_ERROR("reloc with multiple write domains: "
- "obj %p target %d offset %d "
- "read %08x write %08x",
- obj, reloc.target_handle,
- (int) reloc.offset,
- reloc.read_domains,
- reloc.write_domain);
- ret = -EINVAL;
- break;
- }
- if (reloc.write_domain & I915_GEM_DOMAIN_CPU ||
- reloc.read_domains & I915_GEM_DOMAIN_CPU) {
- DRM_ERROR("reloc with read/write CPU domains: "
- "obj %p target %d offset %d "
- "read %08x write %08x",
- obj, reloc.target_handle,
- (int) reloc.offset,
- reloc.read_domains,
- reloc.write_domain);
- ret = -EINVAL;
- break;
- }
- if (reloc.write_domain && target_obj->pending_write_domain &&
- reloc.write_domain != target_obj->pending_write_domain) {
- DRM_ERROR("Write domain conflict: "
- "obj %p target %d offset %d "
- "new %08x old %08x\n",
- obj, reloc.target_handle,
- (int) reloc.offset,
- reloc.write_domain,
- target_obj->pending_write_domain);
- ret = -EINVAL;
- break;
- }
+ /* Check that the relocation address is valid... */
+ if (reloc->offset > obj->base.size - 4) {
+ DRM_ERROR("Relocation beyond object bounds: "
+ "obj %p target %d offset %d size %d.\n",
+ obj, reloc->target_handle,
+ (int) reloc->offset,
+ (int) obj->base.size);
+ goto err;
+ }
+ if (reloc->offset & 3) {
+ DRM_ERROR("Relocation not 4-byte aligned: "
+ "obj %p target %d offset %d.\n",
+ obj, reloc->target_handle,
+ (int) reloc->offset);
+ goto err;
+ }
- target_obj->pending_read_domains |= reloc.read_domains;
- target_obj->pending_write_domain |= reloc.write_domain;
+ /* and points to somewhere within the target object. */
+ if (reloc->delta >= target_obj->size) {
+ DRM_ERROR("Relocation beyond target object bounds: "
+ "obj %p target %d delta %d size %d.\n",
+ obj, reloc->target_handle,
+ (int) reloc->delta,
+ (int) target_obj->size);
+ goto err;
+ }
- /* If the relocation already has the right value in it, no
- * more work needs to be done.
- */
- if (target_offset == reloc.presumed_offset)
- continue;
+ reloc->delta += target_offset;
+ if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) {
+ uint32_t page_offset = reloc->offset & ~PAGE_MASK;
+ char *vaddr;
- /* Check that the relocation address is valid... */
- if (reloc.offset > obj->base.size - 4) {
- DRM_ERROR("Relocation beyond object bounds: "
- "obj %p target %d offset %d size %d.\n",
- obj, reloc.target_handle,
- (int) reloc.offset, (int) obj->base.size);
- ret = -EINVAL;
- break;
- }
- if (reloc.offset & 3) {
- DRM_ERROR("Relocation not 4-byte aligned: "
- "obj %p target %d offset %d.\n",
- obj, reloc.target_handle,
- (int) reloc.offset);
- ret = -EINVAL;
- break;
- }
+ vaddr = kmap_atomic(obj->pages[reloc->offset >> PAGE_SHIFT]);
+ *(uint32_t *)(vaddr + page_offset) = reloc->delta;
+ kunmap_atomic(vaddr);
+ } else {
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t __iomem *reloc_entry;
+ void __iomem *reloc_page;
- /* and points to somewhere within the target object. */
- if (reloc.delta >= target_obj->size) {
- DRM_ERROR("Relocation beyond target object bounds: "
- "obj %p target %d delta %d size %d.\n",
- obj, reloc.target_handle,
- (int) reloc.delta, (int) target_obj->size);
- ret = -EINVAL;
- break;
- }
+ ret = i915_gem_object_set_to_gtt_domain(&obj->base, 1);
+ if (ret)
+ goto err;
- reloc.delta += target_offset;
- if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) {
- uint32_t page_offset = reloc.offset & ~PAGE_MASK;
- char *vaddr;
+ /* Map the page containing the relocation we're going to perform. */
+ reloc->offset += obj->gtt_offset;
+ reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+ reloc->offset & PAGE_MASK);
+ reloc_entry = (uint32_t __iomem *)
+ (reloc_page + (reloc->offset & ~PAGE_MASK));
+ iowrite32(reloc->delta, reloc_entry);
+ io_mapping_unmap_atomic(reloc_page);
+ }
- vaddr = kmap_atomic(obj->pages[reloc.offset >> PAGE_SHIFT]);
- *(uint32_t *)(vaddr + page_offset) = reloc.delta;
- kunmap_atomic(vaddr);
- } else {
- uint32_t __iomem *reloc_entry;
- void __iomem *reloc_page;
+ /* and update the user's relocation entry */
+ reloc->presumed_offset = target_offset;
- ret = i915_gem_object_set_to_gtt_domain(&obj->base, 1);
- if (ret)
- break;
+out:
+ ret = 0;
+err:
+ drm_gem_object_unreference(target_obj);
+ return ret;
+}
- /* Map the page containing the relocation we're going to perform. */
- reloc.offset += obj->gtt_offset;
- reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
- reloc.offset & PAGE_MASK);
- reloc_entry = (uint32_t __iomem *)
- (reloc_page + (reloc.offset & ~PAGE_MASK));
- iowrite32(reloc.delta, reloc_entry);
- io_mapping_unmap_atomic(reloc_page);
- }
+static int
+i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
+ struct drm_file *file_priv,
+ struct drm_i915_gem_exec_object2 *entry)
+{
+ struct drm_i915_gem_relocation_entry __user *user_relocs;
+ int i, ret;
+
+ user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
+ for (i = 0; i < entry->relocation_count; i++) {
+ struct drm_i915_gem_relocation_entry reloc;
+
+ if (__copy_from_user_inatomic(&reloc,
+ user_relocs+i,
+ sizeof(reloc)))
+ return -EFAULT;
+
+ ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &reloc);
+ if (ret)
+ return ret;
- /* and update the user's relocation entry */
- reloc.presumed_offset = target_offset;
if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset,
- &reloc.presumed_offset,
- sizeof(reloc.presumed_offset))) {
- ret = -EFAULT;
- break;
- }
+ &reloc.presumed_offset,
+ sizeof(reloc.presumed_offset)))
+ return -EFAULT;
}
- drm_gem_object_unreference(target_obj);
- return ret;
+ return 0;
}
static int
-i915_gem_execbuffer_pin(struct drm_device *dev,
- struct drm_file *file,
- struct drm_gem_object **object_list,
- struct drm_i915_gem_exec_object2 *exec_list,
- int count)
+i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
+ struct drm_file *file_priv,
+ struct drm_i915_gem_exec_object2 *entry,
+ struct drm_i915_gem_relocation_entry *relocs)
+{
+ int i, ret;
+
+ for (i = 0; i < entry->relocation_count; i++) {
+ ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &relocs[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+i915_gem_execbuffer_relocate(struct drm_device *dev,
+ struct drm_file *file,
+ struct drm_gem_object **object_list,
+ struct drm_i915_gem_exec_object2 *exec_list,
+ int count)
+{
+ int i, ret;
+
+ for (i = 0; i < count; i++) {
+ struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
+ obj->base.pending_read_domains = 0;
+ obj->base.pending_write_domain = 0;
+ ret = i915_gem_execbuffer_relocate_object(obj, file,
+ &exec_list[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+i915_gem_execbuffer_reserve(struct drm_device *dev,
+ struct drm_file *file,
+ struct drm_gem_object **object_list,
+ struct drm_i915_gem_exec_object2 *exec_list,
+ int count)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int ret, i, retry;
return 0;
}
+static int
+i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
+ struct drm_file *file,
+ struct drm_gem_object **object_list,
+ struct drm_i915_gem_exec_object2 *exec_list,
+ int count)
+{
+ struct drm_i915_gem_relocation_entry *reloc;
+ int i, total, ret;
+
+ for (i = 0; i < count; i++) {
+ struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
+ obj->in_execbuffer = false;
+ }
+
+ mutex_unlock(&dev->struct_mutex);
+
+ total = 0;
+ for (i = 0; i < count; i++)
+ total += exec_list[i].relocation_count;
+
+ reloc = drm_malloc_ab(total, sizeof(*reloc));
+ if (reloc == NULL) {
+ mutex_lock(&dev->struct_mutex);
+ return -ENOMEM;
+ }
+
+ total = 0;
+ for (i = 0; i < count; i++) {
+ struct drm_i915_gem_relocation_entry __user *user_relocs;
+
+ user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr;
+
+ if (copy_from_user(reloc+total, user_relocs,
+ exec_list[i].relocation_count *
+ sizeof(*reloc))) {
+ ret = -EFAULT;
+ mutex_lock(&dev->struct_mutex);
+ goto err;
+ }
+
+ total += exec_list[i].relocation_count;
+ }
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret) {
+ mutex_lock(&dev->struct_mutex);
+ goto err;
+ }
+
+ ret = i915_gem_execbuffer_reserve(dev, file,
+ object_list, exec_list,
+ count);
+ if (ret)
+ goto err;
+
+ total = 0;
+ for (i = 0; i < count; i++) {
+ struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
+ obj->base.pending_read_domains = 0;
+ obj->base.pending_write_domain = 0;
+ ret = i915_gem_execbuffer_relocate_object_slow(obj, file,
+ &exec_list[i],
+ reloc + total);
+ if (ret)
+ goto err;
+
+ total += exec_list[i].relocation_count;
+ }
+
+ /* Leave the user relocations as are, this is the painfully slow path,
+ * and we want to avoid the complication of dropping the lock whilst
+ * having buffers reserved in the aperture and so causing spurious
+ * ENOSPC for random operations.
+ */
+
+err:
+ drm_free_large(reloc);
+ return ret;
+}
+
static int
i915_gem_execbuffer_move_to_gpu(struct drm_device *dev,
struct drm_file *file,
for (i = 0; i < count; i++) {
char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
- size_t length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry);
+ int length; /* limited by fault_in_pages_readable() */
+
+ /* First check for malicious input causing overflow */
+ if (exec[i].relocation_count >
+ INT_MAX / sizeof(struct drm_i915_gem_relocation_entry))
+ return -EINVAL;
+ length = exec[i].relocation_count *
+ sizeof(struct drm_i915_gem_relocation_entry);
if (!access_ok(VERIFY_READ, ptr, length))
return -EFAULT;
}
/* Move the objects en-masse into the GTT, evicting if necessary. */
- ret = i915_gem_execbuffer_pin(dev, file,
- object_list, exec_list,
- args->buffer_count);
+ ret = i915_gem_execbuffer_reserve(dev, file,
+ object_list, exec_list,
+ args->buffer_count);
if (ret)
goto err;
/* The objects are in their final locations, apply the relocations. */
- for (i = 0; i < args->buffer_count; i++) {
- struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
- obj->base.pending_read_domains = 0;
- obj->base.pending_write_domain = 0;
- ret = i915_gem_execbuffer_relocate(obj, file, &exec_list[i]);
+ ret = i915_gem_execbuffer_relocate(dev, file,
+ object_list, exec_list,
+ args->buffer_count);
+ if (ret) {
+ if (ret == -EFAULT) {
+ ret = i915_gem_execbuffer_relocate_slow(dev, file,
+ object_list,
+ exec_list,
+ args->buffer_count);
+ BUG_ON(!mutex_is_locked(&dev->struct_mutex));
+ }
if (ret)
goto err;
}
* use this buffer rather sooner than later, so issuing the required
* flush earlier is beneficial.
*/
- if (obj->write_domain & I915_GEM_GPU_DOMAINS)
+ if (obj->write_domain & I915_GEM_GPU_DOMAINS) {
i915_gem_flush_ring(dev, file_priv,
obj_priv->ring,
0, obj->write_domain);
+ } else if (obj_priv->ring->outstanding_lazy_request) {
+ /* This ring is not being cleared by active usage,
+ * so emit a request to do so.
+ */
+ u32 seqno = i915_add_request(dev,
+ NULL, NULL,
+ obj_priv->ring);
+ if (seqno == 0)
+ ret = -ENOMEM;
+ }
/* Update the active list for the hardware's current position.
* Otherwise this only updates on a delayed timer or when irqs
#define TRANS_DP_10BPC (1<<9)
#define TRANS_DP_6BPC (2<<9)
#define TRANS_DP_12BPC (3<<9)
+#define TRANS_DP_BPC_MASK (3<<9)
#define TRANS_DP_VSYNC_ACTIVE_HIGH (1<<4)
#define TRANS_DP_VSYNC_ACTIVE_LOW 0
#define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3)
if (drm_core_check_feature(dev, DRIVER_MODESET))
return;
+ /* Cursor state */
+ dev_priv->saveCURACNTR = I915_READ(CURACNTR);
+ dev_priv->saveCURAPOS = I915_READ(CURAPOS);
+ dev_priv->saveCURABASE = I915_READ(CURABASE);
+ dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
+ dev_priv->saveCURBPOS = I915_READ(CURBPOS);
+ dev_priv->saveCURBBASE = I915_READ(CURBBASE);
+ if (IS_GEN2(dev))
+ dev_priv->saveCURSIZE = I915_READ(CURSIZE);
+
if (HAS_PCH_SPLIT(dev)) {
dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL);
dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL);
I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
+ /* Cursor state */
+ I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
+ I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
+ I915_WRITE(CURABASE, dev_priv->saveCURABASE);
+ I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
+ I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
+ I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
+ if (IS_GEN2(dev))
+ I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
+
return;
}
/* Don't save them in KMS mode */
i915_save_modeset_reg(dev);
- /* Cursor state */
- dev_priv->saveCURACNTR = I915_READ(CURACNTR);
- dev_priv->saveCURAPOS = I915_READ(CURAPOS);
- dev_priv->saveCURABASE = I915_READ(CURABASE);
- dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
- dev_priv->saveCURBPOS = I915_READ(CURBPOS);
- dev_priv->saveCURBBASE = I915_READ(CURBBASE);
- if (IS_GEN2(dev))
- dev_priv->saveCURSIZE = I915_READ(CURSIZE);
-
/* CRT state */
if (HAS_PCH_SPLIT(dev)) {
dev_priv->saveADPA = I915_READ(PCH_ADPA);
/* Don't restore them in KMS mode */
i915_restore_modeset_reg(dev);
- /* Cursor state */
- I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
- I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
- I915_WRITE(CURABASE, dev_priv->saveCURABASE);
- I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
- I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
- I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
- if (IS_GEN2(dev))
- I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
-
/* CRT state */
if (HAS_PCH_SPLIT(dev))
I915_WRITE(PCH_ADPA, dev_priv->saveADPA);
kfree(output.pointer);
}
-static int intel_dsm_switchto(enum vga_switcheroo_client_id id)
-{
- return 0;
-}
-
-static int intel_dsm_power_state(enum vga_switcheroo_client_id id,
- enum vga_switcheroo_state state)
-{
- return 0;
-}
-
-static int intel_dsm_init(void)
-{
- return 0;
-}
-
-static int intel_dsm_get_client_id(struct pci_dev *pdev)
-{
- if (intel_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
- return VGA_SWITCHEROO_IGD;
- else
- return VGA_SWITCHEROO_DIS;
-}
-
-static struct vga_switcheroo_handler intel_dsm_handler = {
- .switchto = intel_dsm_switchto,
- .power_state = intel_dsm_power_state,
- .init = intel_dsm_init,
- .get_client_id = intel_dsm_get_client_id,
-};
-
static bool intel_dsm_pci_probe(struct pci_dev *pdev)
{
acpi_handle dhandle, intel_handle;
{
if (!intel_dsm_detect())
return;
-
- vga_switcheroo_register_handler(&intel_dsm_handler);
}
void intel_unregister_dsm_handler(void)
{
- vga_switcheroo_unregister_handler();
}
#include "i915_drm.h"
#include "i915_drv.h"
+/* Here's the desired hotplug mode */
+#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \
+ ADPA_CRT_HOTPLUG_WARMUP_10MS | \
+ ADPA_CRT_HOTPLUG_SAMPLE_4S | \
+ ADPA_CRT_HOTPLUG_VOLTAGE_50 | \
+ ADPA_CRT_HOTPLUG_VOLREF_325MV | \
+ ADPA_CRT_HOTPLUG_ENABLE)
+
+struct intel_crt {
+ struct intel_encoder base;
+ bool force_hotplug_required;
+};
+
+static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
+{
+ return container_of(intel_attached_encoder(connector),
+ struct intel_crt, base);
+}
+
static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
}
- adpa = 0;
+ adpa = ADPA_HOTPLUG_BITS;
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
+ struct intel_crt *crt = intel_attached_crt(connector);
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 adpa, temp;
+ u32 adpa;
bool ret;
- bool turn_off_dac = false;
- temp = adpa = I915_READ(PCH_ADPA);
+ /* The first time through, trigger an explicit detection cycle */
+ if (crt->force_hotplug_required) {
+ bool turn_off_dac = HAS_PCH_SPLIT(dev);
+ u32 save_adpa;
- if (HAS_PCH_SPLIT(dev))
- turn_off_dac = true;
-
- adpa &= ~ADPA_CRT_HOTPLUG_MASK;
- if (turn_off_dac)
- adpa &= ~ADPA_DAC_ENABLE;
-
- /* disable HPD first */
- I915_WRITE(PCH_ADPA, adpa);
- (void)I915_READ(PCH_ADPA);
-
- adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
- ADPA_CRT_HOTPLUG_WARMUP_10MS |
- ADPA_CRT_HOTPLUG_SAMPLE_4S |
- ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
- ADPA_CRT_HOTPLUG_VOLREF_325MV |
- ADPA_CRT_HOTPLUG_ENABLE |
- ADPA_CRT_HOTPLUG_FORCE_TRIGGER);
-
- DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa);
- I915_WRITE(PCH_ADPA, adpa);
-
- if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
- 1000))
- DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
-
- if (turn_off_dac) {
- /* Make sure hotplug is enabled */
- I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE);
- (void)I915_READ(PCH_ADPA);
+ crt->force_hotplug_required = 0;
+
+ save_adpa = adpa = I915_READ(PCH_ADPA);
+ DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
+
+ adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
+ if (turn_off_dac)
+ adpa &= ~ADPA_DAC_ENABLE;
+
+ I915_WRITE(PCH_ADPA, adpa);
+
+ if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
+ 1000))
+ DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
+
+ if (turn_off_dac) {
+ I915_WRITE(PCH_ADPA, save_adpa);
+ POSTING_READ(PCH_ADPA);
+ }
}
/* Check the status to see if both blue and green are on now */
adpa = I915_READ(PCH_ADPA);
- adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK;
- if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) ||
- (adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO))
+ if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
ret = true;
else
ret = false;
+ DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
return ret;
}
return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
}
-static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
+static bool intel_crt_detect_ddc(struct intel_crt *crt)
{
- struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
- struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+ struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
/* CRT should always be at 0, but check anyway */
- if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
+ if (crt->base.type != INTEL_OUTPUT_ANALOG)
return false;
if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
return true;
}
- if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) {
+ if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
return true;
}
}
static enum drm_connector_status
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
+intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
{
- struct drm_encoder *encoder = &intel_encoder->base;
+ struct drm_encoder *encoder = &crt->base.base;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
intel_crt_detect(struct drm_connector *connector, bool force)
{
struct drm_device *dev = connector->dev;
- struct intel_encoder *encoder = intel_attached_encoder(connector);
+ struct intel_crt *crt = intel_attached_crt(connector);
struct drm_crtc *crtc;
int dpms_mode;
enum drm_connector_status status;
if (intel_crt_detect_hotplug(connector)) {
DRM_DEBUG_KMS("CRT detected via hotplug\n");
return connector_status_connected;
- } else
+ } else {
+ DRM_DEBUG_KMS("CRT not detected via hotplug\n");
return connector_status_disconnected;
+ }
}
- if (intel_crt_detect_ddc(&encoder->base))
+ if (intel_crt_detect_ddc(crt))
return connector_status_connected;
if (!force)
return connector->status;
/* for pre-945g platforms use load detect */
- if (encoder->base.crtc && encoder->base.crtc->enabled) {
- status = intel_crt_load_detect(encoder->base.crtc, encoder);
+ crtc = crt->base.base.crtc;
+ if (crtc && crtc->enabled) {
+ status = intel_crt_load_detect(crtc, crt);
} else {
- crtc = intel_get_load_detect_pipe(encoder, connector,
+ crtc = intel_get_load_detect_pipe(&crt->base, connector,
NULL, &dpms_mode);
if (crtc) {
- if (intel_crt_detect_ddc(&encoder->base))
+ if (intel_crt_detect_ddc(crt))
status = connector_status_connected;
else
- status = intel_crt_load_detect(crtc, encoder);
- intel_release_load_detect_pipe(encoder,
+ status = intel_crt_load_detect(crtc, crt);
+ intel_release_load_detect_pipe(&crt->base,
connector, dpms_mode);
} else
status = connector_status_unknown;
void intel_crt_init(struct drm_device *dev)
{
struct drm_connector *connector;
- struct intel_encoder *intel_encoder;
+ struct intel_crt *crt;
struct intel_connector *intel_connector;
struct drm_i915_private *dev_priv = dev->dev_private;
- intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
- if (!intel_encoder)
+ crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL);
+ if (!crt)
return;
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) {
- kfree(intel_encoder);
+ kfree(crt);
return;
}
drm_connector_init(dev, &intel_connector->base,
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
- drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs,
+ drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
DRM_MODE_ENCODER_DAC);
- intel_connector_attach_encoder(intel_connector, intel_encoder);
+ intel_connector_attach_encoder(intel_connector, &crt->base);
- intel_encoder->type = INTEL_OUTPUT_ANALOG;
- intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
- (1 << INTEL_ANALOG_CLONE_BIT) |
- (1 << INTEL_SDVO_LVDS_CLONE_BIT);
- intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
+ crt->base.type = INTEL_OUTPUT_ANALOG;
+ crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
+ 1 << INTEL_ANALOG_CLONE_BIT |
+ 1 << INTEL_SDVO_LVDS_CLONE_BIT);
+ crt->base.crtc_mask = (1 << 0) | (1 << 1);
connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
- drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs);
+ drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
drm_sysfs_connector_add(connector);
else
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ /*
+ * Configure the automatic hotplug detection stuff
+ */
+ crt->force_hotplug_required = 0;
+ if (HAS_PCH_SPLIT(dev)) {
+ u32 adpa;
+
+ adpa = I915_READ(PCH_ADPA);
+ adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+ adpa |= ADPA_HOTPLUG_BITS;
+ I915_WRITE(PCH_ADPA, adpa);
+ POSTING_READ(PCH_ADPA);
+
+ DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
+ crt->force_hotplug_required = 1;
+ }
+
dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
}
wait_event(dev_priv->pending_flip_queue,
atomic_read(&obj_priv->pending_flip) == 0);
+
+ /* Big Hammer, we also need to ensure that any pending
+ * MI_WAIT_FOR_EVENT inside a user batch buffer on the
+ * current scanout is retired before unpinning the old
+ * framebuffer.
+ */
+ ret = i915_gem_object_flush_gpu(obj_priv, false);
+ if (ret) {
+ i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
}
ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
reg = TRANS_DP_CTL(pipe);
temp = I915_READ(reg);
temp &= ~(TRANS_DP_PORT_SEL_MASK |
- TRANS_DP_SYNC_MASK);
+ TRANS_DP_SYNC_MASK |
+ TRANS_DP_BPC_MASK);
temp |= (TRANS_DP_OUTPUT_ENABLE |
TRANS_DP_ENH_FRAMING);
+ temp |= TRANS_DP_8BPC;
if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
}
}
-#define DATA_N 0x800000
-#define LINK_N 0x80000
-
static void
ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock,
int link_clock, struct fdi_m_n *m_n)
{
- u64 temp;
-
m_n->tu = 64; /* default size */
- temp = (u64) DATA_N * pixel_clock;
- temp = div_u64(temp, link_clock);
- m_n->gmch_m = div_u64(temp * bits_per_pixel, nlanes);
- m_n->gmch_m >>= 3; /* convert to bytes_per_pixel */
- m_n->gmch_n = DATA_N;
+ /* BUG_ON(pixel_clock > INT_MAX / 36); */
+ m_n->gmch_m = bits_per_pixel * pixel_clock;
+ m_n->gmch_n = link_clock * nlanes * 8;
fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
- temp = (u64) LINK_N * pixel_clock;
- m_n->link_m = div_u64(temp, link_clock);
- m_n->link_n = LINK_N;
+ m_n->link_m = pixel_clock;
+ m_n->link_n = link_clock;
fdi_reduce_ratio(&m_n->link_m, &m_n->link_n);
}
/* FDI link */
if (HAS_PCH_SPLIT(dev)) {
+ int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
int lane = 0, link_bw, bpp;
/* CPU eDP doesn't require FDI link, so just set DP M/N
according to current link config */
intel_crtc->fdi_lanes = lane;
+ if (pixel_multiplier > 1)
+ link_bw *= pixel_multiplier;
ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
}
.page_flip = intel_crtc_page_flip,
};
+static void intel_sanitize_modesetting(struct drm_device *dev,
+ int pipe, int plane)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 reg, val;
+
+ if (HAS_PCH_SPLIT(dev))
+ return;
+
+ /* Who knows what state these registers were left in by the BIOS or
+ * grub?
+ *
+ * If we leave the registers in a conflicting state (e.g. with the
+ * display plane reading from the other pipe than the one we intend
+ * to use) then when we attempt to teardown the active mode, we will
+ * not disable the pipes and planes in the correct order -- leaving
+ * a plane reading from a disabled pipe and possibly leading to
+ * undefined behaviour.
+ */
+
+ reg = DSPCNTR(plane);
+ val = I915_READ(reg);
+
+ if ((val & DISPLAY_PLANE_ENABLE) == 0)
+ return;
+ if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
+ return;
+
+ /* This display plane is active and attached to the other CPU pipe. */
+ pipe = !pipe;
+
+ /* Disable the plane and wait for it to stop reading from the pipe. */
+ I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
+ intel_flush_display_plane(dev, plane);
+
+ if (IS_GEN2(dev))
+ intel_wait_for_vblank(dev, pipe);
+
+ if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+ return;
+
+ /* Switch off the pipe. */
+ reg = PIPECONF(pipe);
+ val = I915_READ(reg);
+ if (val & PIPECONF_ENABLE) {
+ I915_WRITE(reg, val & ~PIPECONF_ENABLE);
+ intel_wait_for_pipe_off(dev, pipe);
+ }
+}
static void intel_crtc_init(struct drm_device *dev, int pipe)
{
setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
(unsigned long)intel_crtc);
+
+ intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
}
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder;
bool dpd_is_edp = false;
+ bool has_lvds = false;
if (IS_MOBILE(dev) && !IS_I830(dev))
- intel_lvds_init(dev);
+ has_lvds = intel_lvds_init(dev);
+ if (!has_lvds && !HAS_PCH_SPLIT(dev)) {
+ /* disable the panel fitter on everything but LVDS */
+ I915_WRITE(PFIT_CONTROL, 0);
+ }
if (HAS_PCH_SPLIT(dev)) {
dpd_is_edp = intel_dpd_is_edp(dev);
mode->clock = dev_priv->panel_fixed_mode->clock;
}
- /* Just use VBT values for eDP */
- if (is_edp(intel_dp)) {
- intel_dp->lane_count = dev_priv->edp.lanes;
- intel_dp->link_bw = dev_priv->edp.rate;
- adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
- DRM_DEBUG_KMS("eDP link bw %02x lane count %d clock %d\n",
- intel_dp->link_bw, intel_dp->lane_count,
- adjusted_mode->clock);
- return true;
- }
-
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
}
}
+ if (is_edp(intel_dp)) {
+ /* okay we failed just pick the highest */
+ intel_dp->lane_count = max_lane_count;
+ intel_dp->link_bw = bws[max_clock];
+ adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
+ DRM_DEBUG_KMS("Force picking display port link bw %02x lane "
+ "count %d clock %d\n",
+ intel_dp->link_bw, intel_dp->lane_count,
+ adjusted_mode->clock);
+
+ return true;
+ }
+
return false;
}
}
static uint32_t
-intel_dp_signal_levels(struct intel_dp *intel_dp)
+intel_dp_signal_levels(uint8_t train_set, int lane_count)
{
- struct drm_device *dev = intel_dp->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t signal_levels = 0;
- u8 train_set = intel_dp->train_set[0];
- u32 vswing = train_set & DP_TRAIN_VOLTAGE_SWING_MASK;
- u32 preemphasis = train_set & DP_TRAIN_PRE_EMPHASIS_MASK;
+ uint32_t signal_levels = 0;
- if (is_edp(intel_dp)) {
- vswing = dev_priv->edp.vswing;
- preemphasis = dev_priv->edp.preemphasis;
- }
-
- switch (vswing) {
+ switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
case DP_TRAIN_VOLTAGE_SWING_400:
default:
signal_levels |= DP_VOLTAGE_0_4;
signal_levels |= DP_VOLTAGE_1_2;
break;
}
- switch (preemphasis) {
+ switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
case DP_TRAIN_PRE_EMPHASIS_0:
default:
signal_levels |= DP_PRE_EMPHASIS_0;
return true;
}
-static bool
-intel_dp_aux_handshake_required(struct intel_dp *intel_dp)
-{
- struct drm_device *dev = intel_dp->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (is_edp(intel_dp) && dev_priv->no_aux_handshake)
- return false;
-
- return true;
-}
-
static bool
intel_dp_set_link_train(struct intel_dp *intel_dp,
uint32_t dp_reg_value,
I915_WRITE(intel_dp->output_reg, dp_reg_value);
POSTING_READ(intel_dp->output_reg);
- if (!intel_dp_aux_handshake_required(intel_dp))
- return true;
-
intel_dp_aux_native_write_1(intel_dp,
DP_TRAINING_PATTERN_SET,
dp_train_pat);
POSTING_READ(intel_dp->output_reg);
intel_wait_for_vblank(dev, intel_crtc->pipe);
- if (intel_dp_aux_handshake_required(intel_dp))
- /* Write the link configuration data */
- intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
- intel_dp->link_configuration,
- DP_LINK_CONFIGURATION_SIZE);
+ /* Write the link configuration data */
+ intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
+ intel_dp->link_configuration,
+ DP_LINK_CONFIGURATION_SIZE);
DP |= DP_PORT_EN;
if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
} else {
- signal_levels = intel_dp_signal_levels(intel_dp);
+ signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
}
break;
/* Set training pattern 1 */
- udelay(500);
- if (intel_dp_aux_handshake_required(intel_dp)) {
+ udelay(100);
+ if (!intel_dp_get_link_status(intel_dp))
+ break;
+
+ if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
+ clock_recovery = true;
break;
- } else {
- if (!intel_dp_get_link_status(intel_dp))
- break;
+ }
- if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
- clock_recovery = true;
+ /* Check to see if we've tried the max voltage */
+ for (i = 0; i < intel_dp->lane_count; i++)
+ if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
break;
- }
+ if (i == intel_dp->lane_count)
+ break;
- /* Check to see if we've tried the max voltage */
- for (i = 0; i < intel_dp->lane_count; i++)
- if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
- break;
- if (i == intel_dp->lane_count)
+ /* Check to see if we've tried the same voltage 5 times */
+ if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+ ++tries;
+ if (tries == 5)
break;
+ } else
+ tries = 0;
+ voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
- /* Check to see if we've tried the same voltage 5 times */
- if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
- ++tries;
- if (tries == 5)
- break;
- } else
- tries = 0;
- voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
-
- /* Compute new intel_dp->train_set as requested by target */
- intel_get_adjust_train(intel_dp);
- }
+ /* Compute new intel_dp->train_set as requested by target */
+ intel_get_adjust_train(intel_dp);
}
intel_dp->DP = DP;
signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
} else {
- signal_levels = intel_dp_signal_levels(intel_dp);
+ signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
}
DP_TRAINING_PATTERN_2))
break;
- udelay(500);
-
- if (!intel_dp_aux_handshake_required(intel_dp)) {
+ udelay(400);
+ if (!intel_dp_get_link_status(intel_dp))
break;
- } else {
- if (!intel_dp_get_link_status(intel_dp))
- break;
- if (intel_channel_eq_ok(intel_dp)) {
- channel_eq = true;
- break;
- }
+ if (intel_channel_eq_ok(intel_dp)) {
+ channel_eq = true;
+ break;
+ }
- /* Try 5 times */
- if (tries > 5)
- break;
+ /* Try 5 times */
+ if (tries > 5)
+ break;
- /* Compute new intel_dp->train_set as requested by target */
- intel_get_adjust_train(intel_dp);
- ++tries;
- }
+ /* Compute new intel_dp->train_set as requested by target */
+ intel_get_adjust_train(intel_dp);
+ ++tries;
}
+
if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
reg = DP | DP_LINK_TRAIN_OFF_CPT;
else
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t DP = intel_dp->DP;
+ if ((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)
+ return;
+
DRM_DEBUG_KMS("\n");
if (is_edp(intel_dp)) {
if (is_edp(intel_dp))
DP |= DP_LINK_TRAIN_OFF;
+
+ if (!HAS_PCH_CPT(dev) &&
+ I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
+ struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
+ /* Hardware workaround: leaving our transcoder select
+ * set to transcoder B while it's off will prevent the
+ * corresponding HDMI output on transcoder A.
+ *
+ * Combine this with another hardware workaround:
+ * transcoder select bit can only be cleared while the
+ * port is enabled.
+ */
+ DP &= ~DP_PIPEB_SELECT;
+ I915_WRITE(intel_dp->output_reg, DP);
+
+ /* Changes to enable or select take place the vblank
+ * after being written.
+ */
+ intel_wait_for_vblank(intel_dp->base.base.dev,
+ intel_crtc->pipe);
+ }
+
I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
POSTING_READ(intel_dp->output_reg);
}
extern void intel_dvo_init(struct drm_device *dev);
extern void intel_tv_init(struct drm_device *dev);
extern void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj);
-extern void intel_lvds_init(struct drm_device *dev);
+extern bool intel_lvds_init(struct drm_device *dev);
extern void intel_dp_init(struct drm_device *dev, int dp_reg);
void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
};
struct intel_gpio *gpio;
- if (pin < 1 || pin > 7)
+ if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin])
return NULL;
gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
gpio->reg += PCH_GPIOA - GPIOA;
gpio->dev_priv = dev_priv;
- snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO%c", "?BACDEF?"[pin]);
+ snprintf(gpio->adapter.name, sizeof(gpio->adapter.name),
+ "i915 GPIO%c", "?BACDE?F"[pin]);
gpio->adapter.owner = THIS_MODULE;
gpio->adapter.algo_data = &gpio->algo;
gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev;
"panel",
"dpc",
"dpb",
- "reserved"
+ "reserved",
"dpd",
};
struct drm_i915_private *dev_priv = dev->dev_private;
bus->adapter.owner = THIS_MODULE;
bus->adapter.class = I2C_CLASS_DDC;
snprintf(bus->adapter.name,
- I2C_NAME_SIZE,
- "gmbus %s",
+ sizeof(bus->adapter.name),
+ "i915 gmbus %s",
names[i]);
bus->adapter.dev.parent = &dev->pdev->dev;
/**
* Sets the power state for the panel.
*/
-static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on)
+static void intel_lvds_enable(struct intel_lvds *intel_lvds)
{
struct drm_device *dev = intel_lvds->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
lvds_reg = LVDS;
}
- if (on) {
- I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
- I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
- intel_panel_set_backlight(dev, dev_priv->backlight_level);
- } else {
- dev_priv->backlight_level = intel_panel_get_backlight(dev);
-
- intel_panel_set_backlight(dev, 0);
- I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
+ I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
- if (intel_lvds->pfit_control) {
- if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
- DRM_ERROR("timed out waiting for panel to power off\n");
- I915_WRITE(PFIT_CONTROL, 0);
- intel_lvds->pfit_control = 0;
+ if (intel_lvds->pfit_dirty) {
+ /*
+ * Enable automatic panel scaling so that non-native modes
+ * fill the screen. The panel fitter should only be
+ * adjusted whilst the pipe is disabled, according to
+ * register description and PRM.
+ */
+ DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
+ intel_lvds->pfit_control,
+ intel_lvds->pfit_pgm_ratios);
+ if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) {
+ DRM_ERROR("timed out waiting for panel to power off\n");
+ } else {
+ I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
+ I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
intel_lvds->pfit_dirty = false;
}
+ }
+
+ I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
+ POSTING_READ(lvds_reg);
+
+ intel_panel_set_backlight(dev, dev_priv->backlight_level);
+}
+
+static void intel_lvds_disable(struct intel_lvds *intel_lvds)
+{
+ struct drm_device *dev = intel_lvds->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 ctl_reg, lvds_reg;
+
+ if (HAS_PCH_SPLIT(dev)) {
+ ctl_reg = PCH_PP_CONTROL;
+ lvds_reg = PCH_LVDS;
+ } else {
+ ctl_reg = PP_CONTROL;
+ lvds_reg = LVDS;
+ }
+
+ dev_priv->backlight_level = intel_panel_get_backlight(dev);
+ intel_panel_set_backlight(dev, 0);
+
+ I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
+
+ if (intel_lvds->pfit_control) {
+ if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+ DRM_ERROR("timed out waiting for panel to power off\n");
- I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
+ I915_WRITE(PFIT_CONTROL, 0);
+ intel_lvds->pfit_dirty = true;
}
+
+ I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
POSTING_READ(lvds_reg);
}
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
if (mode == DRM_MODE_DPMS_ON)
- intel_lvds_set_power(intel_lvds, true);
+ intel_lvds_enable(intel_lvds);
else
- intel_lvds_set_power(intel_lvds, false);
+ intel_lvds_disable(intel_lvds);
/* XXX: We never power down the LVDS pairs. */
}
/* Always do a full power on as we do not know what state
* we were left in.
*/
- intel_lvds_set_power(intel_lvds, true);
+ intel_lvds_enable(intel_lvds);
}
static void intel_lvds_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
-
/*
* The LVDS pin pair will already have been turned on in the
* intel_crtc_mode_set since it has a large impact on the DPLL
* settings.
*/
-
- if (HAS_PCH_SPLIT(dev))
- return;
-
- if (!intel_lvds->pfit_dirty)
- return;
-
- /*
- * Enable automatic panel scaling so that non-native modes fill the
- * screen. Should be enabled before the pipe is enabled, according to
- * register description and PRM.
- */
- DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
- intel_lvds->pfit_control,
- intel_lvds->pfit_pgm_ratios);
- if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
- DRM_ERROR("timed out waiting for panel to power off\n");
-
- I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
- I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
- intel_lvds->pfit_dirty = false;
}
/**
* Create the connector, register the LVDS DDC bus, and try to figure out what
* modes we can display on the LVDS panel (if present).
*/
-void intel_lvds_init(struct drm_device *dev)
+bool intel_lvds_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_lvds *intel_lvds;
/* Skip init on machines we know falsely report LVDS */
if (dmi_check_system(intel_no_lvds))
- return;
+ return false;
pin = GMBUS_PORT_PANEL;
if (!lvds_is_present_in_vbt(dev, &pin)) {
DRM_DEBUG_KMS("LVDS is not present in VBT\n");
- return;
+ return false;
}
if (HAS_PCH_SPLIT(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
- return;
+ return false;
if (dev_priv->edp.support) {
DRM_DEBUG_KMS("disable LVDS for eDP support\n");
- return;
+ return false;
}
}
if (!intel_lvds_ddc_probe(dev, pin)) {
DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n");
- return;
+ return false;
}
intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL);
if (!intel_lvds) {
- return;
+ return false;
}
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) {
kfree(intel_lvds);
- return;
+ return false;
}
if (!HAS_PCH_SPLIT(dev)) {
/* keep the LVDS connector */
dev_priv->int_lvds_connector = connector;
drm_sysfs_connector_add(connector);
- return;
+ return true;
failed:
DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
drm_encoder_cleanup(encoder);
kfree(intel_lvds);
kfree(intel_connector);
+ return false;
}
/* G45 ring initialization fails to reset head to zero */
if (head != 0) {
- DRM_ERROR("%s head not reset to zero "
- "ctl %08x head %08x tail %08x start %08x\n",
- ring->name,
- I915_READ_CTL(ring),
- I915_READ_HEAD(ring),
- I915_READ_TAIL(ring),
- I915_READ_START(ring));
+ DRM_DEBUG_KMS("%s head not reset to zero "
+ "ctl %08x head %08x tail %08x start %08x\n",
+ ring->name,
+ I915_READ_CTL(ring),
+ I915_READ_HEAD(ring),
+ I915_READ_TAIL(ring),
+ I915_READ_START(ring));
I915_WRITE_HEAD(ring, 0);
- DRM_ERROR("%s head forced to zero "
- "ctl %08x head %08x tail %08x start %08x\n",
- ring->name,
- I915_READ_CTL(ring),
- I915_READ_HEAD(ring),
- I915_READ_TAIL(ring),
- I915_READ_START(ring));
+ if (I915_READ_HEAD(ring) & HEAD_ADDR) {
+ DRM_ERROR("failed to set %s head to zero "
+ "ctl %08x head %08x tail %08x start %08x\n",
+ ring->name,
+ I915_READ_CTL(ring),
+ I915_READ_HEAD(ring),
+ I915_READ_TAIL(ring),
+ I915_READ_START(ring));
+ }
}
I915_WRITE_CTL(ring,
* This is set if we treat the device as HDMI, instead of DVI.
*/
bool is_hdmi;
- bool has_audio;
+ bool has_hdmi_monitor;
+ bool has_hdmi_audio;
/**
* This is set if we detect output of sdvo device as LVDS and
if (!intel_sdvo_set_target_input(intel_sdvo))
return;
- if (intel_sdvo->is_hdmi &&
+ if (intel_sdvo->has_hdmi_monitor &&
!intel_sdvo_set_avi_infoframe(intel_sdvo))
return;
}
if (intel_crtc->pipe == 1)
sdvox |= SDVO_PIPE_B_SELECT;
- if (intel_sdvo->has_audio)
+ if (intel_sdvo->has_hdmi_audio)
sdvox |= SDVO_AUDIO_ENABLE;
if (INTEL_INFO(dev)->gen >= 4) {
return drm_get_edid(connector, &sdvo->ddc);
}
-static struct drm_connector *
-intel_find_analog_connector(struct drm_device *dev)
-{
- struct drm_connector *connector;
- struct intel_sdvo *encoder;
-
- list_for_each_entry(encoder,
- &dev->mode_config.encoder_list,
- base.base.head) {
- if (encoder->base.type == INTEL_OUTPUT_ANALOG) {
- list_for_each_entry(connector,
- &dev->mode_config.connector_list,
- head) {
- if (&encoder->base ==
- intel_attached_encoder(connector))
- return connector;
- }
- }
- }
-
- return NULL;
-}
-
-static int
-intel_analog_is_connected(struct drm_device *dev)
-{
- struct drm_connector *analog_connector;
-
- analog_connector = intel_find_analog_connector(dev);
- if (!analog_connector)
- return false;
-
- if (analog_connector->funcs->detect(analog_connector, false) ==
- connector_status_disconnected)
- return false;
-
- return true;
-}
-
/* Mac mini hack -- use the same DDC as the analog connector */
static struct edid *
intel_sdvo_get_analog_edid(struct drm_connector *connector)
{
struct drm_i915_private *dev_priv = connector->dev->dev_private;
- if (!intel_analog_is_connected(connector->dev))
- return NULL;
-
- return drm_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+ return drm_get_edid(connector,
+ &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
}
enum drm_connector_status
/* DDC bus is shared, match EDID to connector type */
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
status = connector_status_connected;
- intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid);
- intel_sdvo->has_audio = drm_detect_monitor_audio(edid);
+ if (intel_sdvo->is_hdmi) {
+ intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
+ intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
+ }
}
connector->display_info.raw_edid = NULL;
kfree(edid);
if (status == connector_status_connected) {
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
if (intel_sdvo_connector->force_audio)
- intel_sdvo->has_audio = intel_sdvo_connector->force_audio > 0;
+ intel_sdvo->has_hdmi_audio = intel_sdvo_connector->force_audio > 0;
}
return status;
if (!intel_sdvo_write_cmd(intel_sdvo,
SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
return connector_status_unknown;
- if (intel_sdvo->is_tv) {
- /* add 30ms delay when the output type is SDVO-TV */
+
+ /* add 30ms delay when the output type might be TV */
+ if (intel_sdvo->caps.output_flags &
+ (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0))
mdelay(30);
- }
+
if (!intel_sdvo_read_response(intel_sdvo, &response, 2))
return connector_status_unknown;
edid = intel_sdvo_get_analog_edid(connector);
if (edid != NULL) {
- drm_mode_connector_update_edid_property(connector, edid);
- drm_add_edid_modes(connector, edid);
+ if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+ drm_mode_connector_update_edid_property(connector, edid);
+ drm_add_edid_modes(connector, edid);
+ }
connector->display_info.raw_edid = NULL;
kfree(edid);
}
intel_sdvo_connector->force_audio = val;
- if (val > 0 && intel_sdvo->has_audio)
+ if (val > 0 && intel_sdvo->has_hdmi_audio)
return 0;
- if (val < 0 && !intel_sdvo->has_audio)
+ if (val < 0 && !intel_sdvo->has_hdmi_audio)
return 0;
- intel_sdvo->has_audio = val > 0;
+ intel_sdvo->has_hdmi_audio = val > 0;
goto done;
}
intel_sdvo_set_colorimetry(intel_sdvo,
SDVO_COLORIMETRY_RGB256);
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
+
+ intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
intel_sdvo->is_hdmi = true;
}
intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
- intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
-
return true;
}
*/
#include <linux/backlight.h>
+#include <linux/acpi.h>
#include "drmP.h"
#include "nouveau_drv.h"
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+#ifdef CONFIG_ACPI
+ if (acpi_video_backlight_support()) {
+ NV_INFO(dev, "ACPI backlight interface available, "
+ "not registering our own\n");
+ return 0;
+ }
+#endif
+
switch (dev_priv->card_type) {
case NV_40:
return nouveau_nv40_backlight_init(dev);
struct drm_nouveau_private *dev_priv = dev->dev_private;
unsigned htotal;
- if (dev_priv->chipset >= NV_50) {
+ if (dev_priv->card_type >= NV_50) {
if (NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
NVReadVgaCrtc(dev, 0, 0x1a) == 0)
return false;
nvbo->no_vm = no_vm;
nvbo->tile_mode = tile_mode;
nvbo->tile_flags = tile_flags;
+ nvbo->bo.bdev = &dev_priv->ttm.bdev;
- nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size);
+ nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo),
+ &align, &size);
align >>= PAGE_SHIFT;
nouveau_bo_placement_set(nvbo, flags, 0);
pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags;
}
+static void
+set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
+{
+ struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
+
+ if (dev_priv->card_type == NV_10 &&
+ nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) {
+ /*
+ * Make sure that the color and depth buffers are handled
+ * by independent memory controller units. Up to a 9x
+ * speed up when alpha-blending and depth-test are enabled
+ * at the same time.
+ */
+ int vram_pages = dev_priv->vram_size >> PAGE_SHIFT;
+
+ if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) {
+ nvbo->placement.fpfn = vram_pages / 2;
+ nvbo->placement.lpfn = ~0;
+ } else {
+ nvbo->placement.fpfn = 0;
+ nvbo->placement.lpfn = vram_pages / 2;
+ }
+ }
+}
+
void
nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
{
pl->busy_placement = nvbo->busy_placements;
set_placement_list(nvbo->busy_placements, &pl->num_busy_placement,
type | busy, flags);
+
+ set_placement_range(nvbo, type);
}
int
stride = 16 * 4;
height = amount / stride;
- if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
+ if (new_mem->mem_type == TTM_PL_VRAM &&
+ nouveau_bo_tile_layout(nvbo)) {
ret = RING_SPACE(chan, 8);
if (ret)
return ret;
BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
OUT_RING (chan, 1);
}
- if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
+ if (old_mem->mem_type == TTM_PL_VRAM &&
+ nouveau_bo_tile_layout(nvbo)) {
ret = RING_SPACE(chan, 8);
if (ret)
return ret;
if (dev_priv->card_type == NV_50) {
ret = nv50_mem_vm_bind_linear(dev,
offset + dev_priv->vm_vram_base,
- new_mem->size, nvbo->tile_flags,
+ new_mem->size,
+ nouveau_bo_tile_layout(nvbo),
offset);
if (ret)
return ret;
* nothing to do here.
*/
if (bo->mem.mem_type != TTM_PL_VRAM) {
- if (dev_priv->card_type < NV_50 || !nvbo->tile_flags)
+ if (dev_priv->card_type < NV_50 ||
+ !nouveau_bo_tile_layout(nvbo))
return 0;
}
nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);
if (!nv_encoder && !nouveau_tv_disable)
nv_encoder = find_encoder_by_type(connector, OUTPUT_TV);
- if (nv_encoder) {
+ if (nv_encoder && force) {
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
struct drm_encoder_helper_funcs *helper =
encoder->helper_private;
return ret;
}
+static unsigned
+get_tmds_link_bandwidth(struct drm_connector *connector)
+{
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
+ struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
+ struct dcb_entry *dcb = nv_connector->detected_encoder->dcb;
+
+ if (dcb->location != DCB_LOC_ON_CHIP ||
+ dev_priv->chipset >= 0x46)
+ return 165000;
+ else if (dev_priv->chipset >= 0x40)
+ return 155000;
+ else if (dev_priv->chipset >= 0x18)
+ return 135000;
+ else
+ return 112000;
+}
+
static int
nouveau_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
max_clock = 400000;
break;
case OUTPUT_TMDS:
- if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) ||
- !nv_encoder->dcb->duallink_possible)
- max_clock = 165000;
- else
- max_clock = 330000;
+ max_clock = get_tmds_link_bandwidth(connector);
+ if (nouveau_duallink && nv_encoder->dcb->duallink_possible)
+ max_clock *= 2;
break;
case OUTPUT_ANALOG:
max_clock = nv_encoder->dcb->crtconf.maxfreq;
return NULL;
}
-void
-nouveau_connector_set_polling(struct drm_connector *connector)
-{
- struct drm_device *dev = connector->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc;
- bool spare_crtc = false;
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
- spare_crtc |= !crtc->enabled;
-
- connector->polled = 0;
-
- switch (connector->connector_type) {
- case DRM_MODE_CONNECTOR_VGA:
- case DRM_MODE_CONNECTOR_TV:
- if (dev_priv->card_type >= NV_50 ||
- (nv_gf4_disp_arch(dev) && spare_crtc))
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
- break;
-
- case DRM_MODE_CONNECTOR_DVII:
- case DRM_MODE_CONNECTOR_DVID:
- case DRM_MODE_CONNECTOR_HDMIA:
- case DRM_MODE_CONNECTOR_DisplayPort:
- case DRM_MODE_CONNECTOR_eDP:
- if (dev_priv->card_type >= NV_50)
- connector->polled = DRM_CONNECTOR_POLL_HPD;
- else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
- spare_crtc)
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
- break;
-
- default:
- break;
- }
-}
-
static const struct drm_connector_helper_funcs
nouveau_connector_helper_funcs = {
.get_modes = nouveau_connector_get_modes,
dev->mode_config.scaling_mode_property,
nv_connector->scaling_mode);
}
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
/* fall-through */
case DCB_CONNECTOR_TV_0:
case DCB_CONNECTOR_TV_1:
dev->mode_config.dithering_mode_property,
nv_connector->use_dithering ?
DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
+
+ if (dcb->type != DCB_CONNECTOR_LVDS) {
+ if (dev_priv->card_type >= NV_50)
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ else
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ }
break;
}
- nouveau_connector_set_polling(connector);
-
drm_sysfs_connector_add(connector);
dcb->drm = connector;
return dcb->drm;
struct drm_connector *
nouveau_connector_create(struct drm_device *, int index);
-void
-nouveau_connector_set_polling(struct drm_connector *);
-
int
nouveau_connector_bpp(struct drm_connector *);
int pin_refcnt;
};
+#define nouveau_bo_tile_layout(nvbo) \
+ ((nvbo)->tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)
+
static inline struct nouveau_bo *
nouveau_bo(struct ttm_buffer_object *bo)
{
void (*destroy_context)(struct nouveau_channel *);
int (*load_context)(struct nouveau_channel *);
int (*unload_context)(struct drm_device *);
+ void (*tlb_flush)(struct drm_device *dev);
};
struct nouveau_pgraph_object_method {
void (*destroy_context)(struct nouveau_channel *);
int (*load_context)(struct nouveau_channel *);
int (*unload_context)(struct drm_device *);
+ void (*tlb_flush)(struct drm_device *dev);
void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr,
uint32_t size, uint32_t pitch);
};
struct nv04_crtc_reg {
- unsigned char MiscOutReg; /* */
+ unsigned char MiscOutReg;
uint8_t CRTC[0xa0];
uint8_t CR58[0x10];
uint8_t Sequencer[5];
uint8_t Graphics[9];
uint8_t Attribute[21];
- unsigned char DAC[768]; /* Internal Colorlookuptable */
+ unsigned char DAC[768];
/* PCRTC regs */
uint32_t fb_start;
};
struct nv04_mode_state {
- uint32_t bpp;
- uint32_t width;
- uint32_t height;
- uint32_t interlace;
- uint32_t repaint0;
- uint32_t repaint1;
- uint32_t screen;
- uint32_t scale;
- uint32_t dither;
- uint32_t extra;
- uint32_t fifo;
- uint32_t pixel;
- uint32_t horiz;
- int arbitration0;
- int arbitration1;
- uint32_t pll;
- uint32_t pllB;
- uint32_t vpll;
- uint32_t vpll2;
- uint32_t vpllB;
- uint32_t vpll2B;
+ struct nv04_crtc_reg crtc_reg[2];
uint32_t pllsel;
uint32_t sel_clk;
- uint32_t general;
- uint32_t crtcOwner;
- uint32_t head;
- uint32_t head2;
- uint32_t cursorConfig;
- uint32_t cursor0;
- uint32_t cursor1;
- uint32_t cursor2;
- uint32_t timingH;
- uint32_t timingV;
- uint32_t displayV;
- uint32_t crtcSync;
-
- struct nv04_crtc_reg crtc_reg[2];
};
enum nouveau_card_type {
struct work_struct irq_work;
struct work_struct hpd_work;
+ struct {
+ spinlock_t lock;
+ uint32_t hpd0_bits;
+ uint32_t hpd1_bits;
+ } hpd_state;
+
struct list_head vbl_waiting;
struct {
extern void nv50_fifo_destroy_context(struct nouveau_channel *);
extern int nv50_fifo_load_context(struct nouveau_channel *);
extern int nv50_fifo_unload_context(struct drm_device *);
+extern void nv50_fifo_tlb_flush(struct drm_device *dev);
/* nvc0_fifo.c */
extern int nvc0_fifo_init(struct drm_device *);
extern int nv50_graph_unload_context(struct drm_device *);
extern void nv50_graph_context_switch(struct drm_device *);
extern int nv50_grctx_init(struct nouveau_grctx *);
+extern void nv50_graph_tlb_flush(struct drm_device *dev);
+extern void nv86_graph_tlb_flush(struct drm_device *dev);
/* nvc0_graph.c */
extern int nvc0_graph_init(struct drm_device *);
extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val);
-extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *);
/* nouveau_fence.c */
struct nouveau_fence;
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_semaphore *sema;
+ int ret;
if (!USE_SEMA(dev))
return NULL;
if (!sema)
goto fail;
+ ret = drm_mm_pre_get(&dev_priv->fence.heap);
+ if (ret)
+ goto fail;
+
spin_lock(&dev_priv->fence.lock);
sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0);
if (sema->mem)
- sema->mem = drm_mm_get_block(sema->mem, 4, 0);
+ sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0);
spin_unlock(&dev_priv->fence.lock);
if (!sema->mem)
}
static bool
-nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) {
- switch (tile_flags) {
- case 0x0000:
- case 0x1800:
- case 0x2800:
- case 0x4800:
- case 0x7000:
- case 0x7400:
- case 0x7a00:
- case 0xe000:
- break;
- default:
- NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags);
- return false;
+nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->card_type >= NV_50) {
+ switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) {
+ case 0x0000:
+ case 0x1800:
+ case 0x2800:
+ case 0x4800:
+ case 0x7000:
+ case 0x7400:
+ case 0x7a00:
+ case 0xe000:
+ return true;
+ }
+ } else {
+ if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK))
+ return true;
}
- return true;
+ NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags);
+ return false;
}
int
struct pll_lims pll_lim;
struct nouveau_pll_vals pv;
- uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;
+ enum pll_types pll = head ? PLL_VPLL1 : PLL_VPLL0;
- if (get_pll_limits(dev, pllreg, &pll_lim))
+ if (get_pll_limits(dev, pll, &pll_lim))
return;
- nouveau_hw_get_pllvals(dev, pllreg, &pv);
+ nouveau_hw_get_pllvals(dev, pll, &pv);
if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m &&
pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n &&
pv.M1 = pll_lim.vco1.max_m;
pv.N1 = pll_lim.vco1.min_n;
pv.log2P = pll_lim.max_usable_log2p;
- nouveau_hw_setpll(dev, pllreg, &pv);
+ nouveau_hw_setpll(dev, pll_lim.reg, &pv);
}
/*
NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos);
}
+static inline void
+nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ NVWriteCRTC(dev, head, NV_PCRTC_START, offset);
+
+ if (dev_priv->card_type == NV_04) {
+ /*
+ * Hilarious, the 24th bit doesn't want to stick to
+ * PCRTC_START...
+ */
+ int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX);
+
+ NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX,
+ (cre_heb & ~0x40) | ((offset >> 18) & 0x40));
+ }
+}
+
static inline void
nv_show_cursor(struct drm_device *dev, int head, bool show)
{
if (index >= DCB_MAX_NUM_I2C_ENTRIES)
return NULL;
- if (dev_priv->chipset >= NV_50 && (i2c->entry & 0x00000100)) {
+ if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) {
uint32_t reg = 0xe500, val;
if (i2c->port_type == 6) {
#include "nouveau_connector.h"
#include "nv50_display.h"
+static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
+
+static int nouveau_ratelimit(void)
+{
+ return __ratelimit(&nouveau_ratelimit_state);
+}
+
void
nouveau_irq_preinstall(struct drm_device *dev)
{
if (dev_priv->card_type >= NV_50) {
INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
+ spin_lock_init(&dev_priv->hpd_state.lock);
INIT_LIST_HEAD(&dev_priv->vbl_waiting);
}
}
}
if (status & NV_PFIFO_INTR_DMA_PUSHER) {
- u32 get = nv_rd32(dev, 0x003244);
- u32 put = nv_rd32(dev, 0x003240);
+ u32 dma_get = nv_rd32(dev, 0x003244);
+ u32 dma_put = nv_rd32(dev, 0x003240);
u32 push = nv_rd32(dev, 0x003220);
u32 state = nv_rd32(dev, 0x003228);
u32 ib_get = nv_rd32(dev, 0x003334);
u32 ib_put = nv_rd32(dev, 0x003330);
- NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
+ if (nouveau_ratelimit())
+ NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
"Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
"State 0x%08x Push 0x%08x\n",
- chid, ho_get, get, ho_put, put, ib_get, ib_put,
- state, push);
+ chid, ho_get, dma_get, ho_put,
+ dma_put, ib_get, ib_put, state,
+ push);
/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
nv_wr32(dev, 0x003364, 0x00000000);
- if (get != put || ho_get != ho_put) {
- nv_wr32(dev, 0x003244, put);
+ if (dma_get != dma_put || ho_get != ho_put) {
+ nv_wr32(dev, 0x003244, dma_put);
nv_wr32(dev, 0x003328, ho_put);
} else
if (ib_get != ib_put) {
} else {
NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
"Put 0x%08x State 0x%08x Push 0x%08x\n",
- chid, get, put, state, push);
+ chid, dma_get, dma_put, state, push);
- if (get != put)
- nv_wr32(dev, 0x003244, put);
+ if (dma_get != dma_put)
+ nv_wr32(dev, 0x003244, dma_put);
}
nv_wr32(dev, 0x003228, 0x00000000);
}
if (status) {
- NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
- status, chid);
+ if (nouveau_ratelimit())
+ NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
+ status, chid);
nv_wr32(dev, NV03_PFIFO_INTR_0, status);
status = 0;
}
nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap);
}
-static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
-
-static int nouveau_ratelimit(void)
-{
- return __ratelimit(&nouveau_ratelimit_state);
-}
-
static inline void
nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource)
#include "drmP.h"
#include "drm.h"
#include "drm_sarea.h"
-#include "nouveau_drv.h"
-#define MIN(a,b) a < b ? a : b
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
/*
* NV10-NV40 tiling helpers
}
}
}
- dev_priv->engine.instmem.flush(dev);
- nv50_vm_flush(dev, 5);
- nv50_vm_flush(dev, 0);
- nv50_vm_flush(dev, 4);
+ dev_priv->engine.instmem.flush(dev);
+ dev_priv->engine.fifo.tlb_flush(dev);
+ dev_priv->engine.graph.tlb_flush(dev);
nv50_vm_flush(dev, 6);
return 0;
}
pte++;
}
}
- dev_priv->engine.instmem.flush(dev);
- nv50_vm_flush(dev, 5);
- nv50_vm_flush(dev, 0);
- nv50_vm_flush(dev, 4);
+ dev_priv->engine.instmem.flush(dev);
+ dev_priv->engine.fifo.tlb_flush(dev);
+ dev_priv->engine.graph.tlb_flush(dev);
nv50_vm_flush(dev, 6);
}
void
nouveau_mem_timing_init(struct drm_device *dev)
{
+ /* cards < NVC0 only */
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
tUNK_19 = 1;
tUNK_20 = 0;
tUNK_21 = 0;
- switch (MIN(recordlen,21)) {
- case 21:
+ switch (min(recordlen, 22)) {
+ case 22:
tUNK_21 = entry[21];
- case 20:
+ case 21:
tUNK_20 = entry[20];
- case 19:
+ case 20:
tUNK_19 = entry[19];
- case 18:
+ case 19:
tUNK_18 = entry[18];
default:
tUNK_0 = entry[0];
timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
if(recordlen > 19) {
timing->reg_100228 += (tUNK_19 - 1) << 24;
- } else {
+ }/* I cannot back-up this else-statement right now
+ else {
timing->reg_100228 += tUNK_12 << 24;
- }
+ }*/
/* XXX: reg_10022c */
+ timing->reg_10022c = tUNK_2 - 1;
timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
tUNK_13 << 8 | tUNK_13);
/* XXX: +6? */
timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC);
- if(tUNK_10 > tUNK_11) {
- timing->reg_100234 += tUNK_10 << 16;
- } else {
- timing->reg_100234 += tUNK_11 << 16;
+ timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
+
+ /* XXX; reg_100238, reg_10023c
+ * reg: 0x00??????
+ * reg_10023c:
+ * 0 for pre-NV50 cards
+ * 0x????0202 for NV50+ cards (empirical evidence) */
+ if(dev_priv->card_type >= NV_50) {
+ timing->reg_10023c = 0x202;
}
- /* XXX; reg_100238, reg_10023c */
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
timing->reg_100220, timing->reg_100224,
timing->reg_100228, timing->reg_10022c);
if (ramin == NULL) {
spin_unlock(&dev_priv->ramin_lock);
nouveau_gpuobj_ref(NULL, &gpuobj);
- return ret;
+ return -ENOMEM;
}
ramin = drm_mm_get_block_atomic(ramin, size, align);
}
}
+#ifdef CONFIG_HWMON
static ssize_t
nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
{
static const struct attribute_group hwmon_attrgroup = {
.attrs = hwmon_attributes,
};
+#endif
static int
nouveau_hwmon_init(struct drm_device *dev)
{
+#ifdef CONFIG_HWMON
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
struct device *hwmon_dev;
}
pm->hwmon = hwmon_dev;
-
+#endif
return 0;
}
static void
nouveau_hwmon_fini(struct drm_device *dev)
{
+#ifdef CONFIG_HWMON
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup);
hwmon_device_unregister(pm->hwmon);
}
+#endif
}
int
return -ENOMEM;
}
+static struct nouveau_ramht_entry *
+nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle)
+{
+ struct nouveau_ramht *ramht = chan ? chan->ramht : NULL;
+ struct nouveau_ramht_entry *entry;
+ unsigned long flags;
+
+ if (!ramht)
+ return NULL;
+
+ spin_lock_irqsave(&ramht->lock, flags);
+ list_for_each_entry(entry, &ramht->entries, head) {
+ if (entry->channel == chan &&
+ (!handle || entry->handle == handle)) {
+ list_del(&entry->head);
+ spin_unlock_irqrestore(&ramht->lock, flags);
+
+ return entry;
+ }
+ }
+ spin_unlock_irqrestore(&ramht->lock, flags);
+
+ return NULL;
+}
+
static void
-nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
+nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
- struct nouveau_ramht_entry *entry, *tmp;
+ unsigned long flags;
u32 co, ho;
- list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) {
- if (entry->channel != chan || entry->handle != handle)
- continue;
-
- nouveau_gpuobj_ref(NULL, &entry->gpuobj);
- list_del(&entry->head);
- kfree(entry);
- break;
- }
-
+ spin_lock_irqsave(&chan->ramht->lock, flags);
co = ho = nouveau_ramht_hash_handle(chan, handle);
do {
if (nouveau_ramht_entry_valid(dev, ramht, co) &&
nv_wo32(ramht, co + 0, 0x00000000);
nv_wo32(ramht, co + 4, 0x00000000);
instmem->flush(dev);
- return;
+ goto out;
}
co += 8;
NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
chan->id, handle);
+out:
+ spin_unlock_irqrestore(&chan->ramht->lock, flags);
}
void
nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
{
- struct nouveau_ramht *ramht = chan->ramht;
- unsigned long flags;
+ struct nouveau_ramht_entry *entry;
- spin_lock_irqsave(&ramht->lock, flags);
- nouveau_ramht_remove_locked(chan, handle);
- spin_unlock_irqrestore(&ramht->lock, flags);
+ entry = nouveau_ramht_remove_entry(chan, handle);
+ if (!entry)
+ return;
+
+ nouveau_ramht_remove_hash(chan, entry->handle);
+ nouveau_gpuobj_ref(NULL, &entry->gpuobj);
+ kfree(entry);
}
struct nouveau_gpuobj *
nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
struct nouveau_channel *chan)
{
- struct nouveau_ramht_entry *entry, *tmp;
+ struct nouveau_ramht_entry *entry;
struct nouveau_ramht *ramht;
- unsigned long flags;
if (ref)
kref_get(&ref->refcount);
ramht = *ptr;
if (ramht) {
- spin_lock_irqsave(&ramht->lock, flags);
- list_for_each_entry_safe(entry, tmp, &ramht->entries, head) {
- if (entry->channel != chan)
- continue;
-
- nouveau_ramht_remove_locked(chan, entry->handle);
+ while ((entry = nouveau_ramht_remove_entry(chan, 0))) {
+ nouveau_ramht_remove_hash(chan, entry->handle);
+ nouveau_gpuobj_ref(NULL, &entry->gpuobj);
+ kfree(entry);
}
- spin_unlock_irqrestore(&ramht->lock, flags);
kref_put(&ramht->refcount, nouveau_ramht_del);
}
dev_priv->engine.instmem.flush(nvbe->dev);
if (dev_priv->card_type == NV_50) {
- nv50_vm_flush(dev, 5); /* PGRAPH */
- nv50_vm_flush(dev, 0); /* PFIFO */
+ dev_priv->engine.fifo.tlb_flush(dev);
+ dev_priv->engine.graph.tlb_flush(dev);
}
nvbe->bound = true;
dev_priv->engine.instmem.flush(nvbe->dev);
if (dev_priv->card_type == NV_50) {
- nv50_vm_flush(dev, 5);
- nv50_vm_flush(dev, 0);
+ dev_priv->engine.fifo.tlb_flush(dev);
+ dev_priv->engine.graph.tlb_flush(dev);
}
nvbe->bound = false;
int i, ret;
if (dev_priv->card_type < NV_50) {
- aper_size = (64 * 1024 * 1024);
+ if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024)
+ aper_size = 64 * 1024 * 1024;
+ else
+ aper_size = 512 * 1024 * 1024;
+
obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4;
obj_size += 8; /* ctxdma header */
} else {
engine->graph.destroy_context = nv50_graph_destroy_context;
engine->graph.load_context = nv50_graph_load_context;
engine->graph.unload_context = nv50_graph_unload_context;
+ if (dev_priv->chipset != 0x86)
+ engine->graph.tlb_flush = nv50_graph_tlb_flush;
+ else {
+ /* from what i can see nvidia do this on every
+ * pre-NVA3 board except NVAC, but, we've only
+ * ever seen problems on NV86
+ */
+ engine->graph.tlb_flush = nv86_graph_tlb_flush;
+ }
engine->fifo.channels = 128;
engine->fifo.init = nv50_fifo_init;
engine->fifo.takedown = nv50_fifo_takedown;
engine->fifo.destroy_context = nv50_fifo_destroy_context;
engine->fifo.load_context = nv50_fifo_load_context;
engine->fifo.unload_context = nv50_fifo_unload_context;
+ engine->fifo.tlb_flush = nv50_fifo_tlb_flush;
engine->display.early_init = nv50_display_early_init;
engine->display.late_takedown = nv50_display_late_takedown;
engine->display.create = nv50_display_create;
case NOUVEAU_GETPARAM_PTIMER_TIME:
getparam->value = dev_priv->engine.timer.read(dev);
break;
+ case NOUVEAU_GETPARAM_HAS_BO_USAGE:
+ getparam->value = 1;
+ break;
case NOUVEAU_GETPARAM_GRAPH_UNITS:
/* NV40 and NV50 versions are quite different, but register
* address is the same. User is supposed to know the card
}
/* FALLTHRU */
default:
- NV_ERROR(dev, "unknown parameter %lld\n", getparam->param);
+ NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param);
return -EINVAL;
}
switch (setparam->param) {
default:
- NV_ERROR(dev, "unknown parameter %lld\n", setparam->param);
+ NV_DEBUG(dev, "unknown parameter %lld\n", setparam->param);
return -EINVAL;
}
int offset = sensor->offset_mult / sensor->offset_div;
int core_temp;
- if (dev_priv->chipset >= 0x50) {
+ if (dev_priv->card_type >= NV_50) {
core_temp = nv_rd32(dev, 0x20008);
} else {
core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev;
- struct drm_connector *connector;
unsigned char seq1 = 0, crtc17 = 0;
unsigned char crtc1A;
NVVgaSeqReset(dev, nv_crtc->index, false);
NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A);
-
- /* Update connector polling modes */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head)
- nouveau_connector_set_polling(connector);
}
static bool
/* Update the framebuffer location. */
regp->fb_start = nv_crtc->fb.offset & ~3;
regp->fb_start += (y * drm_fb->pitch) + (x * drm_fb->bits_per_pixel / 8);
- NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_START, regp->fb_start);
+ nv_set_crtc_base(dev, nv_crtc->index, regp->fb_start);
/* Update the arbitration parameters. */
nouveau_calc_arb(dev, crtc->mode.clock, drm_fb->bits_per_pixel,
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder);
- /* For internal panels and gpu scaling on DVI we need the native mode */
- if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
- if (!nv_connector->native_mode)
- return false;
+ if (!nv_connector->native_mode ||
+ nv_connector->scaling_mode == DRM_MODE_SCALE_NONE ||
+ mode->hdisplay > nv_connector->native_mode->hdisplay ||
+ mode->vdisplay > nv_connector->native_mode->vdisplay) {
+ nv_encoder->mode = *adjusted_mode;
+
+ } else {
nv_encoder->mode = *nv_connector->native_mode;
adjusted_mode->clock = nv_connector->native_mode->clock;
- } else {
- nv_encoder->mode = *adjusted_mode;
}
return true;
reg += 4;
nouveau_hw_setpll(dev, reg, &state->calc);
+
+ if (dev_priv->card_type < NV_30 && reg == NV_PRAMDAC_MPLL_COEFF) {
+ if (dev_priv->card_type == NV_20)
+ nv_mask(dev, 0x1002c4, 0, 1 << 20);
+
+ /* Reset the DLLs */
+ nv_mask(dev, 0x1002c0, 0, 1 << 8);
+ }
+
kfree(state);
}
int *N, int *fN, int *M, int *P)
{
fixed20_12 fb_div, a, b;
+ u32 refclk = pll->refclk / 10;
+ u32 max_vco_freq = pll->vco1.maxfreq / 10;
+ u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10;
+ clk /= 10;
- *P = pll->vco1.maxfreq / clk;
+ *P = max_vco_freq / clk;
if (*P > pll->max_p)
*P = pll->max_p;
if (*P < pll->min_p)
*P = pll->min_p;
- /* *M = ceil(refclk / pll->vco.max_inputfreq); */
- a.full = dfixed_const(pll->refclk);
- b.full = dfixed_const(pll->vco1.max_inputfreq);
+ /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */
+ a.full = dfixed_const(refclk + max_vco_inputfreq);
+ b.full = dfixed_const(max_vco_inputfreq);
a.full = dfixed_div(a, b);
- a.full = dfixed_ceil(a);
+ a.full = dfixed_floor(a);
*M = dfixed_trunc(a);
/* fb_div = (vco * *M) / refclk; */
fb_div.full = dfixed_const(clk * *P);
fb_div.full = dfixed_mul(fb_div, a);
- a.full = dfixed_const(pll->refclk);
+ a.full = dfixed_const(refclk);
fb_div.full = dfixed_div(fb_div, a);
/* *N = floor(fb_div); */
}
nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base;
- nv_crtc->fb.tile_flags = fb->nvbo->tile_flags;
+ nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo);
nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) {
ret = RING_SPACE(evo, 2);
fb->nvbo->tile_mode);
}
if (dev_priv->chipset == 0x50)
- OUT_RING(evo, (fb->nvbo->tile_flags << 8) | format);
+ OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format);
else
OUT_RING(evo, format);
struct drm_connector *connector;
const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
uint32_t unplug_mask, plug_mask, change_mask;
- uint32_t hpd0, hpd1 = 0;
+ uint32_t hpd0, hpd1;
- hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050);
+ spin_lock_irq(&dev_priv->hpd_state.lock);
+ hpd0 = dev_priv->hpd_state.hpd0_bits;
+ dev_priv->hpd_state.hpd0_bits = 0;
+ hpd1 = dev_priv->hpd_state.hpd1_bits;
+ dev_priv->hpd_state.hpd1_bits = 0;
+ spin_unlock_irq(&dev_priv->hpd_state.lock);
+
+ hpd0 &= nv_rd32(dev, 0xe050);
if (dev_priv->chipset >= 0x90)
- hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070);
+ hpd1 &= nv_rd32(dev, 0xe070);
plug_mask = (hpd0 & 0x0000ffff) | (hpd1 << 16);
unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000);
helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF);
}
- nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
- if (dev_priv->chipset >= 0x90)
- nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
-
drm_helper_hpd_irq_event(dev);
}
uint32_t delayed = 0;
if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) {
- if (!work_pending(&dev_priv->hpd_work))
- queue_work(dev_priv->wq, &dev_priv->hpd_work);
+ uint32_t hpd0_bits, hpd1_bits = 0;
+
+ hpd0_bits = nv_rd32(dev, 0xe054);
+ nv_wr32(dev, 0xe054, hpd0_bits);
+
+ if (dev_priv->chipset >= 0x90) {
+ hpd1_bits = nv_rd32(dev, 0xe074);
+ nv_wr32(dev, 0xe074, hpd1_bits);
+ }
+
+ spin_lock(&dev_priv->hpd_state.lock);
+ dev_priv->hpd_state.hpd0_bits |= hpd0_bits;
+ dev_priv->hpd_state.hpd1_bits |= hpd1_bits;
+ spin_unlock(&dev_priv->hpd_state.lock);
+
+ queue_work(dev_priv->wq, &dev_priv->hpd_work);
}
while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
return 0;
}
+void
+nv50_fifo_tlb_flush(struct drm_device *dev)
+{
+ nv50_vm_flush(dev, 5);
+}
{ 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */
{}
};
+
+void
+nv50_graph_tlb_flush(struct drm_device *dev)
+{
+ nv50_vm_flush(dev, 0);
+}
+
+void
+nv86_graph_tlb_flush(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+ bool idle, timeout = false;
+ unsigned long flags;
+ u64 start;
+ u32 tmp;
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, 0x400500, 0x00000001, 0x00000000);
+
+ start = ptimer->read(dev);
+ do {
+ idle = true;
+
+ for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) {
+ if ((tmp & 7) == 1)
+ idle = false;
+ }
+
+ for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) {
+ if ((tmp & 7) == 1)
+ idle = false;
+ }
+
+ for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) {
+ if ((tmp & 7) == 1)
+ idle = false;
+ }
+ } while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000));
+
+ if (timeout) {
+ NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380),
+ nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388));
+ }
+
+ nv50_vm_flush(dev, 0);
+
+ nv_mask(dev, 0x400500, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+}
}
dev_priv->engine.instmem.flush(dev);
- nv50_vm_flush(dev, 4);
nv50_vm_flush(dev, 6);
gpuobj->im_bound = 1;
base += 3;
break;
case ATOM_IIO_WRITE:
+ (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1));
ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp);
base += 3;
break;
}
}
- rdev->config.evergreen.tile_config = gb_addr_config;
+ /* setup tiling info dword. gb_addr_config is not adequate since it does
+ * not have bank info, so create a custom tiling dword.
+ * bits 3:0 num_pipes
+ * bits 7:4 num_banks
+ * bits 11:8 group_size
+ * bits 15:12 row_size
+ */
+ rdev->config.evergreen.tile_config = 0;
+ switch (rdev->config.evergreen.max_tile_pipes) {
+ case 1:
+ default:
+ rdev->config.evergreen.tile_config |= (0 << 0);
+ break;
+ case 2:
+ rdev->config.evergreen.tile_config |= (1 << 0);
+ break;
+ case 4:
+ rdev->config.evergreen.tile_config |= (2 << 0);
+ break;
+ case 8:
+ rdev->config.evergreen.tile_config |= (3 << 0);
+ break;
+ }
+ rdev->config.evergreen.tile_config |=
+ ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+ rdev->config.evergreen.tile_config |=
+ ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8;
+ rdev->config.evergreen.tile_config |=
+ ((gb_addr_config & 0x30000000) >> 28) << 12;
+
WREG32(GB_BACKEND_MAP, gb_backend_map);
WREG32(GB_ADDR_CONFIG, gb_addr_config);
WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
obj_size += evergreen_ps_size * 4;
obj_size = ALIGN(obj_size, 256);
- r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM,
+ r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
&rdev->r600_blit.shader_obj);
if (r) {
DRM_ERROR("evergreen failed to allocate shader\n");
u32 tmp;
/* flush hdp cache so updates hit vram */
- if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) {
+ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) &&
+ !(rdev->flags & RADEON_IS_AGP)) {
void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
u32 tmp;
/* r7xx hw bug. write to HDP_DEBUG1 followed by fb read
* rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
+ * This seems to cause problems on some AGP cards. Just use the old
+ * method for them.
*/
WREG32(HDP_DEBUG1, 0);
tmp = readl((void __iomem *)ptr);
mc->vram_end, mc->real_vram_size >> 20);
} else {
u64 base = 0;
- if (rdev->flags & RADEON_IS_IGP)
- base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24;
+ if (rdev->flags & RADEON_IS_IGP) {
+ base = RREG32(MC_VM_FB_LOCATION) & 0xFFFF;
+ base <<= 24;
+ }
radeon_vram_location(rdev, &rdev->mc, base);
rdev->mc.gtt_base_align = 0;
radeon_gtt_location(rdev, mc);
/* Allocate ring buffer */
if (rdev->ih.ring_obj == NULL) {
r = radeon_bo_create(rdev, NULL, rdev->ih.ring_size,
- true,
+ PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT,
&rdev->ih.ring_obj);
if (r) {
void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo)
{
/* r7xx hw bug. write to HDP_DEBUG1 followed by fb read
- * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
+ * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL.
+ * This seems to cause problems on some AGP cards. Just use the old
+ * method for them.
*/
if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) &&
- rdev->vram_scratch.ptr) {
+ rdev->vram_scratch.ptr && !(rdev->flags & RADEON_IS_AGP)) {
void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
u32 tmp;
obj_size += r6xx_ps_size * 4;
obj_size = ALIGN(obj_size, 256);
- r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM,
+ r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
&rdev->r600_blit.shader_obj);
if (r) {
DRM_ERROR("r600 failed to allocate shader\n");
u32 nsamples;
u32 cb_color_base_last[8];
struct radeon_bo *cb_color_bo[8];
+ u64 cb_color_bo_mc[8];
u32 cb_color_bo_offset[8];
struct radeon_bo *cb_color_frag_bo[8];
struct radeon_bo *cb_color_tile_bo[8];
u32 db_depth_size;
u32 db_offset;
struct radeon_bo *db_bo;
+ u64 db_bo_mc;
};
static inline int r600_bpe_from_format(u32 *bpe, u32 format)
return 0;
}
+struct array_mode_checker {
+ int array_mode;
+ u32 group_size;
+ u32 nbanks;
+ u32 npipes;
+ u32 nsamples;
+ u32 bpe;
+};
+
+/* returns alignment in pixels for pitch/height/depth and bytes for base */
+static inline int r600_get_array_mode_alignment(struct array_mode_checker *values,
+ u32 *pitch_align,
+ u32 *height_align,
+ u32 *depth_align,
+ u64 *base_align)
+{
+ u32 tile_width = 8;
+ u32 tile_height = 8;
+ u32 macro_tile_width = values->nbanks;
+ u32 macro_tile_height = values->npipes;
+ u32 tile_bytes = tile_width * tile_height * values->bpe * values->nsamples;
+ u32 macro_tile_bytes = macro_tile_width * macro_tile_height * tile_bytes;
+
+ switch (values->array_mode) {
+ case ARRAY_LINEAR_GENERAL:
+ /* technically tile_width/_height for pitch/height */
+ *pitch_align = 1; /* tile_width */
+ *height_align = 1; /* tile_height */
+ *depth_align = 1;
+ *base_align = 1;
+ break;
+ case ARRAY_LINEAR_ALIGNED:
+ *pitch_align = max((u32)64, (u32)(values->group_size / values->bpe));
+ *height_align = tile_height;
+ *depth_align = 1;
+ *base_align = values->group_size;
+ break;
+ case ARRAY_1D_TILED_THIN1:
+ *pitch_align = max((u32)tile_width,
+ (u32)(values->group_size /
+ (tile_height * values->bpe * values->nsamples)));
+ *height_align = tile_height;
+ *depth_align = 1;
+ *base_align = values->group_size;
+ break;
+ case ARRAY_2D_TILED_THIN1:
+ *pitch_align = max((u32)macro_tile_width,
+ (u32)(((values->group_size / tile_height) /
+ (values->bpe * values->nsamples)) *
+ values->nbanks)) * tile_width;
+ *height_align = macro_tile_height * tile_height;
+ *depth_align = 1;
+ *base_align = max(macro_tile_bytes,
+ (*pitch_align) * values->bpe * (*height_align) * values->nsamples);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static void r600_cs_track_init(struct r600_cs_track *track)
{
int i;
track->cb_color_info[i] = 0;
track->cb_color_bo[i] = NULL;
track->cb_color_bo_offset[i] = 0xFFFFFFFF;
+ track->cb_color_bo_mc[i] = 0xFFFFFFFF;
}
track->cb_target_mask = 0xFFFFFFFF;
track->cb_shader_mask = 0xFFFFFFFF;
track->db_bo = NULL;
+ track->db_bo_mc = 0xFFFFFFFF;
/* assume the biggest format and that htile is enabled */
track->db_depth_info = 7 | (1 << 25);
track->db_depth_view = 0xFFFFC000;
static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
{
struct r600_cs_track *track = p->track;
- u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align;
+ u32 bpe = 0, slice_tile_max, size, tmp;
+ u32 height, height_align, pitch, pitch_align, depth_align;
+ u64 base_offset, base_align;
+ struct array_mode_checker array_check;
volatile u32 *ib = p->ib->ptr;
unsigned array_mode;
i, track->cb_color_info[i]);
return -EINVAL;
}
- /* pitch is the number of 8x8 tiles per row */
- pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1;
+ /* pitch in pixels */
+ pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) * 8;
slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
slice_tile_max *= 64;
- height = slice_tile_max / (pitch * 8);
+ height = slice_tile_max / pitch;
if (height > 8192)
height = 8192;
array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]);
+
+ base_offset = track->cb_color_bo_mc[i] + track->cb_color_bo_offset[i];
+ array_check.array_mode = array_mode;
+ array_check.group_size = track->group_size;
+ array_check.nbanks = track->nbanks;
+ array_check.npipes = track->npipes;
+ array_check.nsamples = track->nsamples;
+ array_check.bpe = bpe;
+ if (r600_get_array_mode_alignment(&array_check,
+ &pitch_align, &height_align, &depth_align, &base_align)) {
+ dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
+ G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i,
+ track->cb_color_info[i]);
+ return -EINVAL;
+ }
switch (array_mode) {
case V_0280A0_ARRAY_LINEAR_GENERAL:
- /* technically height & 0x7 */
break;
case V_0280A0_ARRAY_LINEAR_ALIGNED:
- pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- if (!IS_ALIGNED(height, 8)) {
- dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
- __func__, __LINE__, height);
- return -EINVAL;
- }
break;
case V_0280A0_ARRAY_1D_TILED_THIN1:
- pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
/* avoid breaking userspace */
if (height > 7)
height &= ~0x7;
- if (!IS_ALIGNED(height, 8)) {
- dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
- __func__, __LINE__, height);
- return -EINVAL;
- }
break;
case V_0280A0_ARRAY_2D_TILED_THIN1:
- pitch_align = max((u32)track->nbanks,
- (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- if (!IS_ALIGNED((height / 8), track->npipes)) {
- dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
- __func__, __LINE__, height);
- return -EINVAL;
- }
break;
default:
dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
track->cb_color_info[i]);
return -EINVAL;
}
+
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(height, height_align)) {
+ dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+ __func__, __LINE__, height);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(base_offset, base_align)) {
+ dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+ return -EINVAL;
+ }
+
/* check offset */
- tmp = height * pitch * 8 * bpe;
+ tmp = height * pitch * bpe;
if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
/* the initial DDX does bad things with the CB size occasionally */
return -EINVAL;
}
}
- if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) {
- dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]);
- return -EINVAL;
- }
/* limit max tile */
- tmp = (height * pitch * 8) >> 6;
+ tmp = (height * pitch) >> 6;
if (tmp < slice_tile_max)
slice_tile_max = tmp;
- tmp = S_028060_PITCH_TILE_MAX(pitch - 1) |
+ tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) |
S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
ib[track->cb_color_size_idx[i]] = tmp;
return 0;
/* Check depth buffer */
if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
G_028800_Z_ENABLE(track->db_depth_control)) {
- u32 nviews, bpe, ntiles, pitch, pitch_align, height, size, slice_tile_max;
+ u32 nviews, bpe, ntiles, size, slice_tile_max;
+ u32 height, height_align, pitch, pitch_align, depth_align;
+ u64 base_offset, base_align;
+ struct array_mode_checker array_check;
+ int array_mode;
+
if (track->db_bo == NULL) {
dev_warn(p->dev, "z/stencil with no depth buffer\n");
return -EINVAL;
ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
} else {
size = radeon_bo_size(track->db_bo);
- pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1;
+ /* pitch in pixels */
+ pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
slice_tile_max *= 64;
- height = slice_tile_max / (pitch * 8);
+ height = slice_tile_max / pitch;
if (height > 8192)
height = 8192;
- switch (G_028010_ARRAY_MODE(track->db_depth_info)) {
+ base_offset = track->db_bo_mc + track->db_offset;
+ array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
+ array_check.array_mode = array_mode;
+ array_check.group_size = track->group_size;
+ array_check.nbanks = track->nbanks;
+ array_check.npipes = track->npipes;
+ array_check.nsamples = track->nsamples;
+ array_check.bpe = bpe;
+ if (r600_get_array_mode_alignment(&array_check,
+ &pitch_align, &height_align, &depth_align, &base_align)) {
+ dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+ G_028010_ARRAY_MODE(track->db_depth_info),
+ track->db_depth_info);
+ return -EINVAL;
+ }
+ switch (array_mode) {
case V_028010_ARRAY_1D_TILED_THIN1:
- pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8);
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
/* don't break userspace */
height &= ~0x7;
- if (!IS_ALIGNED(height, 8)) {
- dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
- __func__, __LINE__, height);
- return -EINVAL;
- }
break;
case V_028010_ARRAY_2D_TILED_THIN1:
- pitch_align = max((u32)track->nbanks,
- (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- if (!IS_ALIGNED((height / 8), track->npipes)) {
- dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
- __func__, __LINE__, height);
- return -EINVAL;
- }
break;
default:
dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
track->db_depth_info);
return -EINVAL;
}
- if (!IS_ALIGNED(track->db_offset, track->group_size)) {
- dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset);
+
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(height, height_align)) {
+ dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
+ __func__, __LINE__, height);
return -EINVAL;
}
+ if (!IS_ALIGNED(base_offset, base_align)) {
+ dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+ return -EINVAL;
+ }
+
ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
tmp = ntiles * bpe * 64 * nviews;
if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
- dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n",
+ dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n",
track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
radeon_bo_size(track->db_bo));
return -EINVAL;
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->cb_color_base_last[tmp] = ib[idx];
track->cb_color_bo[tmp] = reloc->robj;
+ track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset;
break;
case DB_DEPTH_BASE:
r = r600_cs_packet_next_reloc(p, &reloc);
track->db_offset = radeon_get_ib_value(p, idx) << 8;
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->db_bo = reloc->robj;
+ track->db_bo_mc = reloc->lobj.gpu_offset;
break;
case DB_HTILE_DATA_BASE:
case SQ_PGM_START_FS:
static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
struct radeon_bo *texture,
struct radeon_bo *mipmap,
+ u64 base_offset,
+ u64 mip_offset,
u32 tiling_flags)
{
struct r600_cs_track *track = p->track;
u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0;
- u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align;
+ u32 word0, word1, l0_size, mipmap_size;
+ u32 height_align, pitch, pitch_align, depth_align;
+ u64 base_align;
+ struct array_mode_checker array_check;
/* on legacy kernel we don't perform advanced check */
if (p->rdev == NULL)
return 0;
+ /* convert to bytes */
+ base_offset <<= 8;
+ mip_offset <<= 8;
+
word0 = radeon_get_ib_value(p, idx + 0);
if (tiling_flags & RADEON_TILING_MACRO)
word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
return -EINVAL;
}
- pitch = G_038000_PITCH(word0) + 1;
- switch (G_038000_TILE_MODE(word0)) {
- case V_038000_ARRAY_LINEAR_GENERAL:
- pitch_align = 1;
- /* XXX check height align */
- break;
- case V_038000_ARRAY_LINEAR_ALIGNED:
- pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- /* XXX check height align */
- break;
- case V_038000_ARRAY_1D_TILED_THIN1:
- pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- /* XXX check height align */
- break;
- case V_038000_ARRAY_2D_TILED_THIN1:
- pitch_align = max((u32)track->nbanks,
- (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- /* XXX check height align */
- break;
- default:
- dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
- G_038000_TILE_MODE(word0), word0);
+ /* pitch in texels */
+ pitch = (G_038000_PITCH(word0) + 1) * 8;
+ array_check.array_mode = G_038000_TILE_MODE(word0);
+ array_check.group_size = track->group_size;
+ array_check.nbanks = track->nbanks;
+ array_check.npipes = track->npipes;
+ array_check.nsamples = 1;
+ array_check.bpe = bpe;
+ if (r600_get_array_mode_alignment(&array_check,
+ &pitch_align, &height_align, &depth_align, &base_align)) {
+ dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n",
+ __func__, __LINE__, G_038000_TILE_MODE(word0));
+ return -EINVAL;
+ }
+
+ /* XXX check height as well... */
+
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(base_offset, base_align)) {
+ dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n",
+ __func__, __LINE__, base_offset);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(mip_offset, base_align)) {
+ dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n",
+ __func__, __LINE__, mip_offset);
return -EINVAL;
}
- /* XXX check offset align */
word0 = radeon_get_ib_value(p, idx + 4);
word1 = radeon_get_ib_value(p, idx + 5);
mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
mipmap = reloc->robj;
r = r600_check_texture_resource(p, idx+(i*7)+1,
- texture, mipmap, reloc->lobj.tiling_flags);
+ texture, mipmap,
+ base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2),
+ mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3),
+ reloc->lobj.tiling_flags);
if (r)
return r;
ib[idx+1+(i*7)+2] += base_offset;
#define R600_HDP_NONSURFACE_BASE 0x2c04
#define R600_BUS_CNTL 0x5420
+# define R600_BIOS_ROM_DIS (1 << 1)
#define R600_CONFIG_CNTL 0x5424
#define R600_CONFIG_MEMSIZE 0x5428
#define R600_CONFIG_F0_BASE 0x542C
#define PTE_READABLE (1 << 5)
#define PTE_WRITEABLE (1 << 6)
+/* tiling bits */
+#define ARRAY_LINEAR_GENERAL 0x00000000
+#define ARRAY_LINEAR_ALIGNED 0x00000001
+#define ARRAY_1D_TILED_THIN1 0x00000002
+#define ARRAY_2D_TILED_THIN1 0x00000004
+
/* Registers */
#define ARB_POP 0x2418
#define ENABLE_TC128 (1 << 30)
(rdev->family == CHIP_RS400) || \
(rdev->family == CHIP_RS480))
#define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600))
+#define ASIC_IS_DCE2(rdev) ((rdev->family == CHIP_RS600) || \
+ (rdev->family == CHIP_RS690) || \
+ (rdev->family == CHIP_RS740) || \
+ (rdev->family >= CHIP_R600))
#define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620))
#define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730))
#define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR))
}
}
+ /* some DCE3 boards have bad data for this entry */
+ if (ASIC_IS_DCE3(rdev)) {
+ if ((i == 4) &&
+ (gpio->usClkMaskRegisterIndex == 0x1fda) &&
+ (gpio->sucI2cId.ucAccess == 0x94))
+ gpio->sucI2cId.ucAccess = 0x14;
+ }
+
if (gpio->sucI2cId.ucAccess == id) {
i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
}
}
+ /* some DCE3 boards have bad data for this entry */
+ if (ASIC_IS_DCE3(rdev)) {
+ if ((i == 4) &&
+ (gpio->usClkMaskRegisterIndex == 0x1fda) &&
+ (gpio->sucI2cId.ucAccess == 0x94))
+ gpio->sucI2cId.ucAccess = 0x14;
+ }
+
i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
size = bsize;
n = 1024;
- r = radeon_bo_create(rdev, NULL, size, true, sdomain, &sobj);
+ r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, sdomain, &sobj);
if (r) {
goto out_cleanup;
}
if (r) {
goto out_cleanup;
}
- r = radeon_bo_create(rdev, NULL, size, true, ddomain, &dobj);
+ r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, ddomain, &dobj);
if (r) {
goto out_cleanup;
}
}
return true;
}
+
static bool r700_read_disabled_bios(struct radeon_device *rdev)
{
uint32_t viph_control;
bool r;
viph_control = RREG32(RADEON_VIPH_CONTROL);
- bus_cntl = RREG32(RADEON_BUS_CNTL);
+ bus_cntl = RREG32(R600_BUS_CNTL);
d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
/* disable VIP */
WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
/* enable the rom */
- WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+ WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
/* Disable VGA mode */
WREG32(AVIVO_D1VGA_CONTROL,
(d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
cg_spll_status = RREG32(R600_CG_SPLL_STATUS);
}
WREG32(RADEON_VIPH_CONTROL, viph_control);
- WREG32(RADEON_BUS_CNTL, bus_cntl);
+ WREG32(R600_BUS_CNTL, bus_cntl);
WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
bool r;
viph_control = RREG32(RADEON_VIPH_CONTROL);
- bus_cntl = RREG32(RADEON_BUS_CNTL);
+ bus_cntl = RREG32(R600_BUS_CNTL);
d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
/* disable VIP */
WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
/* enable the rom */
- WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+ WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
/* Disable VGA mode */
WREG32(AVIVO_D1VGA_CONTROL,
(d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
/* restore regs */
WREG32(RADEON_VIPH_CONTROL, viph_control);
- WREG32(RADEON_BUS_CNTL, bus_cntl);
+ WREG32(R600_BUS_CNTL, bus_cntl);
WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
}
if (clk_mask && data_mask) {
+ /* system specific masks */
i2c.mask_clk_mask = clk_mask;
i2c.mask_data_mask = data_mask;
i2c.a_clk_mask = clk_mask;
i2c.en_data_mask = data_mask;
i2c.y_clk_mask = clk_mask;
i2c.y_data_mask = data_mask;
+ } else if ((ddc_line == RADEON_GPIOPAD_MASK) ||
+ (ddc_line == RADEON_MDGPIO_MASK)) {
+ /* default gpiopad masks */
+ i2c.mask_clk_mask = (0x20 << 8);
+ i2c.mask_data_mask = 0x80;
+ i2c.a_clk_mask = (0x20 << 8);
+ i2c.a_data_mask = 0x80;
+ i2c.en_clk_mask = (0x20 << 8);
+ i2c.en_data_mask = 0x80;
+ i2c.y_clk_mask = (0x20 << 8);
+ i2c.y_data_mask = 0x80;
} else {
+ /* default masks for ddc pads */
i2c.mask_clk_mask = RADEON_GPIO_EN_1;
i2c.mask_data_mask = RADEON_GPIO_EN_0;
i2c.a_clk_mask = RADEON_GPIO_A_1;
clk = RBIOS8(offset + 3 + (i * 5) + 3);
data = RBIOS8(offset + 3 + (i * 5) + 4);
i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
- clk, data);
+ (1 << clk), (1 << data));
rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
break;
}
static int radeon_dp_get_modes(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
int ret;
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ if (!radeon_dig_connector->edp_on)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
+ }
ret = radeon_ddc_get_modes(radeon_connector);
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ if (!radeon_dig_connector->edp_on)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_OFF);
+ }
+
return ret;
}
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
/* eDP is always DP */
radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
+ if (!radeon_dig_connector->edp_on)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
if (radeon_dp_getdpcd(radeon_connector))
ret = connector_status_connected;
+ if (!radeon_dig_connector->edp_on)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_OFF);
} else {
radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
break;
case DRM_MODE_CONNECTOR_DVIA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
1);
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
break;
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_DVID:
rdev->mode_info.load_detect_property,
1);
}
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_DVII)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_HDMIA:
case DRM_MODE_CONNECTOR_HDMIB:
0);
}
subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_DisplayPort:
case DRM_MODE_CONNECTOR_eDP:
rdev->mode_info.underscan_vborder_property,
0);
}
+ connector->interlace_allowed = true;
+ /* in theory with a DP to VGA converter... */
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Composite:
radeon_atombios_get_tv_info(rdev));
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_LVDS:
radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN);
subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
break;
}
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
break;
case DRM_MODE_CONNECTOR_DVIA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
1);
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
break;
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_DVID:
1);
}
subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_DVII)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Composite:
radeon_combios_get_tv_info(rdev));
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_LVDS:
drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN);
subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
break;
}
int r;
if (rdev->wb.wb_obj == NULL) {
- r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
+ r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
mc->mc_vram_size = mc->aper_size;
}
mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
- dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n",
+ dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
mc->mc_vram_size >> 20, mc->vram_start,
mc->vram_end, mc->real_vram_size >> 20);
}
mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align;
}
mc->gtt_end = mc->gtt_start + mc->gtt_size - 1;
- dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n",
+ dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n",
mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end);
}
return false;
}
}
+
void
radeon_link_encoder_connector(struct drm_device *dev)
{
return NULL;
}
+struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_encoder *other_encoder;
+ struct radeon_encoder *other_radeon_encoder;
+
+ if (radeon_encoder->is_ext_encoder)
+ return NULL;
+
+ list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) {
+ if (other_encoder == encoder)
+ continue;
+ other_radeon_encoder = to_radeon_encoder(other_encoder);
+ if (other_radeon_encoder->is_ext_encoder &&
+ (radeon_encoder->devices & other_radeon_encoder->devices))
+ return other_encoder;
+ }
+ return NULL;
+}
+
void radeon_panel_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
}
-void
-atombios_external_tmds_setup(struct drm_encoder *encoder, int action)
-{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args;
- int index = 0;
-
- memset(&args, 0, sizeof(args));
-
- index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
-
- args.sXTmdsEncoder.ucEnable = action;
-
- if (radeon_encoder->pixel_clock > 165000)
- args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL;
-
- /*if (pScrn->rgbBits == 8)*/
- args.sXTmdsEncoder.ucMisc |= (1 << 1);
-
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
-}
+union dvo_encoder_control {
+ ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds;
+ DVO_ENCODER_CONTROL_PS_ALLOCATION dvo;
+ DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3;
+};
-static void
-atombios_ddia_setup(struct drm_encoder *encoder, int action)
+void
+atombios_dvo_setup(struct drm_encoder *encoder, int action)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- DVO_ENCODER_CONTROL_PS_ALLOCATION args;
- int index = 0;
+ union dvo_encoder_control args;
+ int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
memset(&args, 0, sizeof(args));
- index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
+ if (ASIC_IS_DCE3(rdev)) {
+ /* DCE3+ */
+ args.dvo_v3.ucAction = action;
+ args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ args.dvo_v3.ucDVOConfig = 0; /* XXX */
+ } else if (ASIC_IS_DCE2(rdev)) {
+ /* DCE2 (pre-DCE3 R6xx, RS600/690/740 */
+ args.dvo.sDVOEncoder.ucAction = action;
+ args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ /* DFP1, CRT1, TV1 depending on the type of port */
+ args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX;
+
+ if (radeon_encoder->pixel_clock > 165000)
+ args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL;
+ } else {
+ /* R4xx, R5xx */
+ args.ext_tmds.sXTmdsEncoder.ucEnable = action;
- args.sDVOEncoder.ucAction = action;
- args.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ if (radeon_encoder->pixel_clock > 165000)
+ args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL;
- if (radeon_encoder->pixel_clock > 165000)
- args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL;
+ /*if (pScrn->rgbBits == 8)*/
+ args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB;
+ }
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
}
union lvds_encoder_control {
if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
- args.v1.ucMisc |= (1 << 1);
+ args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
} else {
if (dig->linkb)
args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
if (radeon_encoder->pixel_clock > 165000)
args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
/*if (pScrn->rgbBits == 8) */
- args.v1.ucMisc |= (1 << 1);
+ args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
}
break;
case 2:
int
atombios_get_encoder_mode(struct drm_encoder *encoder)
{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct drm_connector *connector;
struct radeon_connector_atom_dig *dig_connector;
connector = radeon_get_connector_for_encoder(encoder);
- if (!connector)
- return 0;
-
+ if (!connector) {
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ return ATOM_ENCODER_MODE_DVI;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+ default:
+ return ATOM_ENCODER_MODE_CRT;
+ }
+ }
radeon_connector = to_radeon_connector(connector);
switch (connector->connector_type) {
memset(&args, 0, sizeof(args));
switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
+ break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
+void
+atombios_set_edp_panel_power(struct drm_connector *connector, int action)
+{
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct drm_device *dev = radeon_connector->base.dev;
+ struct radeon_device *rdev = dev->dev_private;
+ union dig_transmitter_control args;
+ int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
+ uint8_t frev, crev;
+
+ if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
+ return;
+
+ if (!ASIC_IS_DCE4(rdev))
+ return;
+
+ if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) ||
+ (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
+ return;
+
+ if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ memset(&args, 0, sizeof(args));
+
+ args.v1.ucAction = action;
+
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+union external_encoder_control {
+ EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1;
+};
+
+static void
+atombios_external_encoder_setup(struct drm_encoder *encoder,
+ struct drm_encoder *ext_encoder,
+ int action)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ union external_encoder_control args;
+ struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+ int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
+ u8 frev, crev;
+ int dp_clock = 0;
+ int dp_lane_count = 0;
+ int connector_object_id = 0;
+
+ if (connector) {
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *dig_connector =
+ radeon_connector->con_priv;
+
+ dp_clock = dig_connector->dp_clock;
+ dp_lane_count = dig_connector->dp_lane_count;
+ connector_object_id =
+ (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+ }
+
+ memset(&args, 0, sizeof(args));
+
+ if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ switch (frev) {
+ case 1:
+ /* no params on frev 1 */
+ break;
+ case 2:
+ switch (crev) {
+ case 1:
+ case 2:
+ args.v1.sDigEncoder.ucAction = action;
+ args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder);
+
+ if (args.v1.sDigEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
+ if (dp_clock == 270000)
+ args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+ args.v1.sDigEncoder.ucLaneNum = dp_lane_count;
+ } else if (radeon_encoder->pixel_clock > 165000)
+ args.v1.sDigEncoder.ucLaneNum = 8;
+ else
+ args.v1.sDigEncoder.ucLaneNum = 4;
+ break;
+ default:
+ DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+ return;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+ return;
+ }
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
static void
atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
int index = 0;
bool is_dig = false;
break;
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
case ENCODER_OBJECT_ID_INTERNAL_DDI:
- case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ if (ASIC_IS_DCE3(rdev))
+ is_dig = true;
+ else
+ index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
+ break;
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
break;
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) {
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+ if (connector &&
+ (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *radeon_dig_connector =
+ radeon_connector->con_priv;
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
+ radeon_dig_connector->edp_on = true;
+ }
dp_link_train(encoder, connector);
if (ASIC_IS_DCE4(rdev))
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON);
}
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0);
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) {
+ struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+
if (ASIC_IS_DCE4(rdev))
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF);
+ if (connector &&
+ (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *radeon_dig_connector =
+ radeon_connector->con_priv;
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_OFF);
+ radeon_dig_connector->edp_on = false;
+ }
}
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
break;
}
} else {
switch (mode) {
case DRM_MODE_DPMS_ON:
args.ucAction = ATOM_ENABLE;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ args.ucAction = ATOM_LCD_BLON;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ }
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
args.ucAction = ATOM_DISABLE;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ args.ucAction = ATOM_LCD_BLOFF;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ }
break;
}
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
+
+ if (ext_encoder) {
+ int action;
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ default:
+ action = ATOM_ENABLE;
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ action = ATOM_DISABLE;
+ break;
+ }
+ atombios_external_encoder_setup(encoder, ext_encoder, action);
+ }
+
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
}
break;
default:
DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
- break;
+ return;
}
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
radeon_encoder->pixel_clock = adjusted_mode->clock;
}
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
- atombios_ddia_setup(encoder, ATOM_ENABLE);
- break;
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
- atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+ atombios_dvo_setup(encoder, ATOM_ENABLE);
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
}
break;
}
+
+ if (ext_encoder) {
+ atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
+ }
+
atombios_apply_encoder_quirks(encoder, adjusted_mode);
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
}
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
- atombios_ddia_setup(encoder, ATOM_DISABLE);
- break;
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
- atombios_external_tmds_setup(encoder, ATOM_DISABLE);
+ atombios_dvo_setup(encoder, ATOM_DISABLE);
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
radeon_encoder->active_device = 0;
}
+/* these are handled by the primary encoders */
+static void radeon_atom_ext_prepare(struct drm_encoder *encoder)
+{
+
+}
+
+static void radeon_atom_ext_commit(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+radeon_atom_ext_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+
+}
+
+static void radeon_atom_ext_disable(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode)
+{
+
+}
+
+static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = {
+ .dpms = radeon_atom_ext_dpms,
+ .mode_fixup = radeon_atom_ext_mode_fixup,
+ .prepare = radeon_atom_ext_prepare,
+ .mode_set = radeon_atom_ext_mode_set,
+ .commit = radeon_atom_ext_commit,
+ .disable = radeon_atom_ext_disable,
+ /* no detect for TMDS/LVDS yet */
+};
+
static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = {
.dpms = radeon_atom_encoder_dpms,
.mode_fixup = radeon_atom_mode_fixup,
radeon_encoder->devices = supported_device;
radeon_encoder->rmx_type = RMX_OFF;
radeon_encoder->underscan_type = UNDERSCAN_OFF;
+ radeon_encoder->is_ext_encoder = false;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
radeon_encoder->rmx_type = RMX_FULL;
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
+ } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+ radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
} else {
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
}
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
break;
+ case ENCODER_OBJECT_ID_SI170B:
+ case ENCODER_OBJECT_ID_CH7303:
+ case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
+ case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
+ case ENCODER_OBJECT_ID_TITFP513:
+ case ENCODER_OBJECT_ID_VT1623:
+ case ENCODER_OBJECT_ID_HDMI_SI1930:
+ /* these are handled by the primary encoders */
+ radeon_encoder->is_ext_encoder = true;
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
+ else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+ else
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs);
+ break;
}
}
if (rdev->gart.table.vram.robj == NULL) {
r = radeon_bo_create(rdev, NULL, rdev->gart.table_size,
- true, RADEON_GEM_DOMAIN_VRAM,
- &rdev->gart.table.vram.robj);
+ PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->gart.table.vram.robj);
if (r) {
return r;
}
if (alignment < PAGE_SIZE) {
alignment = PAGE_SIZE;
}
- r = radeon_bo_create(rdev, gobj, size, kernel, initial_domain, &robj);
+ r = radeon_bo_create(rdev, gobj, size, alignment, kernel, initial_domain, &robj);
if (r) {
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n",
((rdev->family <= CHIP_RS480) ||
((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) {
/* set the radeon hw i2c adapter */
- sprintf(i2c->adapter.name, "Radeon i2c hw bus %s", name);
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+ "Radeon i2c hw bus %s", name);
i2c->adapter.algo = &radeon_i2c_algo;
ret = i2c_add_adapter(&i2c->adapter);
if (ret) {
}
} else {
/* set the radeon bit adapter */
- sprintf(i2c->adapter.name, "Radeon i2c bit bus %s", name);
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+ "Radeon i2c bit bus %s", name);
i2c->adapter.algo_data = &i2c->algo.bit;
i2c->algo.bit.pre_xfer = pre_xfer;
i2c->algo.bit.post_xfer = post_xfer;
i2c->rec = *rec;
i2c->adapter.owner = THIS_MODULE;
i2c->dev = dev;
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+ "Radeon aux bus %s", name);
i2c_set_adapdata(&i2c->adapter, i2c);
i2c->adapter.algo_data = &i2c->algo.dp;
i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch;
default:
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
crtc);
- return EINVAL;
+ return -EINVAL;
}
} else {
switch (crtc) {
default:
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
crtc);
- return EINVAL;
+ return -EINVAL;
}
}
if (rdev->is_atom_bios) {
radeon_encoder->pixel_clock = adjusted_mode->clock;
- atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+ atombios_dvo_setup(encoder, ATOM_ENABLE);
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
} else {
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
int hdmi_config_offset;
int hdmi_audio_workaround;
int hdmi_buffer_status;
+ bool is_ext_encoder;
};
struct radeon_connector_atom_dig {
u8 dp_sink_type;
int dp_clock;
int dp_lane_count;
+ bool edp_on;
};
struct radeon_gpio_rec {
struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv);
struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index);
struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index);
-extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action);
+extern void atombios_dvo_setup(struct drm_encoder *encoder, int action);
extern void atombios_digital_setup(struct drm_encoder *encoder, int action);
extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
+extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action);
extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
u32 c = 0;
rbo->placement.fpfn = 0;
- rbo->placement.lpfn = rbo->rdev->mc.active_vram_size >> PAGE_SHIFT;
+ rbo->placement.lpfn = 0;
rbo->placement.placement = rbo->placements;
rbo->placement.busy_placement = rbo->placements;
if (domain & RADEON_GEM_DOMAIN_VRAM)
}
int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
- unsigned long size, bool kernel, u32 domain,
- struct radeon_bo **bo_ptr)
+ unsigned long size, int byte_align, bool kernel, u32 domain,
+ struct radeon_bo **bo_ptr)
{
struct radeon_bo *bo;
enum ttm_bo_type type;
+ unsigned long page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT;
+ unsigned long max_size = 0;
int r;
if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) {
}
*bo_ptr = NULL;
+ /* maximun bo size is the minimun btw visible vram and gtt size */
+ max_size = min(rdev->mc.visible_vram_size, rdev->mc.gtt_size);
+ if ((page_align << PAGE_SHIFT) >= max_size) {
+ printk(KERN_WARNING "%s:%d alloc size %ldM bigger than %ldMb limit\n",
+ __func__, __LINE__, page_align >> (20 - PAGE_SHIFT), max_size >> 20);
+ return -ENOMEM;
+ }
+
retry:
bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL);
if (bo == NULL)
/* Kernel allocation are uninterruptible */
mutex_lock(&rdev->vram_mutex);
r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
- &bo->placement, 0, 0, !kernel, NULL, size,
+ &bo->placement, page_align, 0, !kernel, NULL, size,
&radeon_ttm_bo_destroy);
mutex_unlock(&rdev->vram_mutex);
if (unlikely(r != 0)) {
}
extern int radeon_bo_create(struct radeon_device *rdev,
- struct drm_gem_object *gobj, unsigned long size,
- bool kernel, u32 domain,
- struct radeon_bo **bo_ptr);
+ struct drm_gem_object *gobj, unsigned long size,
+ int byte_align,
+ bool kernel, u32 domain,
+ struct radeon_bo **bo_ptr);
extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr);
extern void radeon_bo_kunmap(struct radeon_bo *bo);
extern void radeon_bo_unref(struct radeon_bo **bo);
INIT_LIST_HEAD(&rdev->ib_pool.bogus_ib);
/* Allocate 1M object buffer */
r = radeon_bo_create(rdev, NULL, RADEON_IB_POOL_SIZE*64*1024,
- true, RADEON_GEM_DOMAIN_GTT,
- &rdev->ib_pool.robj);
+ PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT,
+ &rdev->ib_pool.robj);
if (r) {
DRM_ERROR("radeon: failed to ib pool (%d).\n", r);
return r;
rdev->cp.ring_size = ring_size;
/* Allocate ring buffer */
if (rdev->cp.ring_obj == NULL) {
- r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, true,
+ r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT,
&rdev->cp.ring_obj);
if (r) {
goto out_cleanup;
}
- r = radeon_bo_create(rdev, NULL, size, true, RADEON_GEM_DOMAIN_VRAM,
+ r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
&vram_obj);
if (r) {
DRM_ERROR("Failed to create VRAM object\n");
void **gtt_start, **gtt_end;
void **vram_start, **vram_end;
- r = radeon_bo_create(rdev, NULL, size, true,
+ r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, gtt_obj + i);
if (r) {
DRM_ERROR("Failed to create GTT object %d\n", i);
DRM_ERROR("Failed initializing VRAM heap.\n");
return r;
}
- r = radeon_bo_create(rdev, NULL, 256 * 1024, true,
+ r = radeon_bo_create(rdev, NULL, 256 * 1024, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM,
&rdev->stollen_vga_memory);
if (r) {
if (rdev->vram_scratch.robj == NULL) {
r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE,
- true, RADEON_GEM_DOMAIN_VRAM,
- &rdev->vram_scratch.robj);
+ PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->vram_scratch.robj);
if (r) {
return r;
}
int ret;
while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) {
+ /**
+ * Deadlock avoidance for multi-bo reserving.
+ */
if (use_sequence && bo->seq_valid &&
(sequence - bo->val_seq < (1 << 31))) {
return -EAGAIN;
}
if (use_sequence) {
+ /**
+ * Wake up waiters that may need to recheck for deadlock,
+ * if we decreased the sequence number.
+ */
+ if (unlikely((bo->val_seq - sequence < (1 << 31))
+ || !bo->seq_valid))
+ wake_up_all(&bo->event_queue);
+
bo->val_seq = sequence;
bo->seq_valid = true;
} else {
&vmw_vram_sys_placement, true,
&vmw_user_dmabuf_destroy);
if (unlikely(ret != 0))
- return ret;
+ goto out_no_dmabuf;
tmp = ttm_bo_reference(&vmw_user_bo->dma.base);
ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile,
false,
ttm_buffer_type,
&vmw_user_dmabuf_release, NULL);
- if (unlikely(ret != 0)) {
- ttm_bo_unref(&tmp);
- } else {
+ if (unlikely(ret != 0))
+ goto out_no_base_object;
+ else {
rep->handle = vmw_user_bo->base.hash.key;
rep->map_handle = vmw_user_bo->dma.base.addr_space_offset;
rep->cur_gmr_id = vmw_user_bo->base.hash.key;
rep->cur_gmr_offset = 0;
}
- ttm_bo_unref(&tmp);
+out_no_base_object:
+ ttm_bo_unref(&tmp);
+out_no_dmabuf:
ttm_read_unlock(&vmaster->lock);
- return 0;
+ return ret;
}
int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
struct egalax_data *td;
struct hid_report *report;
- td = kmalloc(sizeof(struct egalax_data), GFP_KERNEL);
+ td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL);
if (!td) {
dev_err(&hdev->dev, "cannot allocate eGalax data\n");
return -ENOMEM;
clear_bit(*old_keycode, dev->keybit);
set_bit(usage->code, dev->keybit);
- dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n",
+ dbg_hid("Assigned keycode %d to HID usage code %x\n",
usage->code, usage->hid);
/*
*
* as seen in the HID specification v1.11 6.2.2.7 Global Items.
*
- * Only exponent 1 length units are processed. Centimeters are converted to
- * inches. Degrees are converted to radians.
+ * Only exponent 1 length units are processed. Centimeters and inches are
+ * converted to millimeters. Degrees are converted to radians.
*/
static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
{
*/
if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
if (field->unit == 0x11) { /* If centimeters */
- /* Convert to inches */
- prev = logical_extents;
- logical_extents *= 254;
- if (logical_extents < prev)
+ /* Convert to millimeters */
+ unit_exponent += 1;
+ } else if (field->unit == 0x13) { /* If inches */
+ /* Convert to millimeters */
+ prev = physical_extents;
+ physical_extents *= 254;
+ if (physical_extents < prev)
return 0;
- unit_exponent += 2;
- } else if (field->unit != 0x13) { /* If not inches */
+ unit_exponent -= 1;
+ } else {
return 0;
}
} else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
.driver_data = (unsigned long)ff_joystick },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654), /* FGT Force Feedback Wheel */
.driver_data = (unsigned long)ff_joystick },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a), /* F430 Force Feedback Wheel */
+ .driver_data = (unsigned long)ff_joystick },
{ }
};
MODULE_DEVICE_TABLE(hid, tm_devices);
#include <linux/hid.h>
#include <linux/mutex.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/hidraw.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
int nr = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct adm1026_data *data = i2c_get_clientdata(client);
- int val, orig_div, new_div, shift;
+ int val, orig_div, new_div;
val = simple_strtol(buf, NULL, 10);
new_div = DIV_TO_REG(val);
- if (new_div == 0) {
- return -EINVAL;
- }
+
mutex_lock(&data->update_lock);
orig_div = data->fan_div[nr];
data->fan_div[nr] = DIV_FROM_REG(new_div);
if (nr < 4) { /* 0 <= nr < 4 */
- shift = 2 * nr;
adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3,
- ((DIV_TO_REG(orig_div) & (~(0x03 << shift))) |
- (new_div << shift)));
+ (DIV_TO_REG(data->fan_div[0]) << 0) |
+ (DIV_TO_REG(data->fan_div[1]) << 2) |
+ (DIV_TO_REG(data->fan_div[2]) << 4) |
+ (DIV_TO_REG(data->fan_div[3]) << 6));
} else { /* 3 < nr < 8 */
- shift = 2 * (nr - 4);
adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7,
- ((DIV_TO_REG(orig_div) & (~(0x03 << (2 * shift)))) |
- (new_div << shift)));
+ (DIV_TO_REG(data->fan_div[4]) << 0) |
+ (DIV_TO_REG(data->fan_div[5]) << 2) |
+ (DIV_TO_REG(data->fan_div[6]) << 4) |
+ (DIV_TO_REG(data->fan_div[7]) << 6));
}
if (data->fan_div[nr] != orig_div) {
0
};
+#ifdef MODULE
static struct pci_device_id i5k_amb_ids[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, i5k_amb_ids);
+#endif
static int __devinit i5k_amb_probe(struct platform_device *pdev)
{
#define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14
#define IT87_REG_PWM(nr) (0x15 + (nr))
+#define IT87_REG_PWM_DUTY(nr) (0x63 + (nr) * 8)
#define IT87_REG_VIN(nr) (0x20 + (nr))
#define IT87_REG_TEMP(nr) (0x29 + (nr))
u8 fan_main_ctrl; /* Register value */
u8 fan_ctl; /* Register value */
- /* The following 3 arrays correspond to the same registers. The
- * meaning of bits 6-0 depends on the value of bit 7, and we want
- * to preserve settings on mode changes, so we have to track all
- * values separately. */
+ /* The following 3 arrays correspond to the same registers up to
+ * the IT8720F. The meaning of bits 6-0 depends on the value of bit
+ * 7, and we want to preserve settings on mode changes, so we have
+ * to track all values separately.
+ * Starting with the IT8721F, the manual PWM duty cycles are stored
+ * in separate registers (8-bit values), so the separate tracking
+ * is no longer needed, but it is still done to keep the driver
+ * simple. */
u8 pwm_ctrl[3]; /* Register value */
- u8 pwm_duty[3]; /* Manual PWM value set by user (bit 6-0) */
+ u8 pwm_duty[3]; /* Manual PWM value set by user */
u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */
/* Automatic fan speed control registers */
data->fan_main_ctrl);
} else {
if (val == 1) /* Manual mode */
- data->pwm_ctrl[nr] = data->pwm_duty[nr];
+ data->pwm_ctrl[nr] = data->type == it8721 ?
+ data->pwm_temp_map[nr] :
+ data->pwm_duty[nr];
else /* Automatic mode */
data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
return -EINVAL;
mutex_lock(&data->update_lock);
- data->pwm_duty[nr] = pwm_to_reg(data, val);
- /* If we are in manual mode, write the duty cycle immediately;
- * otherwise, just store it for later use. */
- if (!(data->pwm_ctrl[nr] & 0x80)) {
- data->pwm_ctrl[nr] = data->pwm_duty[nr];
- it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
+ if (data->type == it8721) {
+ /* If we are in automatic mode, the PWM duty cycle register
+ * is read-only so we can't write the value */
+ if (data->pwm_ctrl[nr] & 0x80) {
+ mutex_unlock(&data->update_lock);
+ return -EBUSY;
+ }
+ data->pwm_duty[nr] = pwm_to_reg(data, val);
+ it87_write_value(data, IT87_REG_PWM_DUTY(nr),
+ data->pwm_duty[nr]);
+ } else {
+ data->pwm_duty[nr] = pwm_to_reg(data, val);
+ /* If we are in manual mode, write the duty cycle immediately;
+ * otherwise, just store it for later use. */
+ if (!(data->pwm_ctrl[nr] & 0x80)) {
+ data->pwm_ctrl[nr] = data->pwm_duty[nr];
+ it87_write_value(data, IT87_REG_PWM(nr),
+ data->pwm_ctrl[nr]);
+ }
}
mutex_unlock(&data->update_lock);
return count;
* channels to use when later setting to automatic mode later.
* Use a 1:1 mapping by default (we are clueless.)
* In both cases, the value can (and should) be changed by the user
- * prior to switching to a different mode. */
+ * prior to switching to a different mode.
+ * Note that this is no longer needed for the IT8721F and later, as
+ * these have separate registers for the temperature mapping and the
+ * manual duty cycle. */
for (i = 0; i < 3; i++) {
data->pwm_temp_map[i] = i;
data->pwm_duty[i] = 0x7f; /* Full speed */
static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
{
data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
- if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
+ if (data->type == it8721) {
data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
- else /* Manual mode */
- data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+ data->pwm_duty[nr] = it87_read_value(data,
+ IT87_REG_PWM_DUTY(nr));
+ } else {
+ if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
+ data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+ else /* Manual mode */
+ data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+ }
if (has_old_autopwm(data)) {
int i;
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int lis3lv02d_i2c_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
return 0;
}
-#else
-#define lis3lv02d_i2c_suspend NULL
-#define lis3lv02d_i2c_resume NULL
-#define lis3lv02d_i2c_shutdown NULL
-#endif
+#endif /* CONFIG_PM_SLEEP */
+#ifdef CONFIG_PM_RUNTIME
static int lis3_i2c_runtime_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
lis3lv02d_poweron(lis3);
return 0;
}
+#endif /* CONFIG_PM_RUNTIME */
static const struct i2c_device_id lis3lv02d_id[] = {
{"lis3lv02d", 0 },
/* Power (virtual) */
LTC4215_POWER(power1_input);
-LTC4215_ALARM(power1_alarm, (1 << 3), LTC4215_STATUS);
/* Input Voltage */
LTC4215_VOLTAGE(in1_input, LTC4215_ADIN);
/* Output Voltage */
LTC4215_VOLTAGE(in2_input, LTC4215_SOURCE);
+LTC4215_ALARM(in2_min_alarm, (1 << 3), LTC4215_STATUS);
/* Finally, construct an array of pointers to members of the above objects,
* as required for sysfs_create_group()
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr,
- &sensor_dev_attr_power1_alarm.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min_alarm.dev_attr.attr,
NULL,
};
In doubt, say Y.
config I2C_SMBUS
- tristate
- prompt "SMBus-specific protocols" if !I2C_HELPER_AUTO
+ tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
help
Say Y here if you want support for SMBus extensions to the I2C
specification. At the moment, the only supported extension is
#
menu "I2C Algorithms"
- depends on !I2C_HELPER_AUTO
+ visible if !I2C_HELPER_AUTO
config I2C_ALGOBIT
tristate "I2C bit-banging interfaces"
tristate "I2C PCA 9564 interfaces"
endmenu
-
-# In automatic configuration mode, we still have to define the
-# symbols to avoid unmet dependencies.
-
-if I2C_HELPER_AUTO
-config I2C_ALGOBIT
- tristate
-config I2C_ALGOPCF
- tristate
-config I2C_ALGOPCA
- tristate
-endif
/* Initialize struct members */
snprintf(mrst->adap.name, sizeof(mrst->adap.name),
- "MRST/Medfield I2C at %lx", start);
+ "Intel MID I2C at %lx", start);
mrst->adap.owner = THIS_MODULE;
mrst->adap.algo = &intel_mid_i2c_algorithm;
mrst->adap.dev.parent = &dev->dev;
pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
- if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
- lapic_timer_reliable_states = 0xFFFFFFFF;
if (boot_cpu_data.x86 != 6) /* family 6 */
return -ENODEV;
case 0x1F: /* Core i7 and i5 Processor - Nehalem */
case 0x2E: /* Nehalem-EX Xeon */
case 0x2F: /* Westmere-EX Xeon */
- lapic_timer_reliable_states = (1 << 1); /* C1 */
-
case 0x25: /* Westmere */
case 0x2C: /* Westmere */
cpuidle_state_table = nehalem_cstates;
case 0x1C: /* 28 - Atom Processor */
case 0x26: /* 38 - Lincroft Atom Processor */
- lapic_timer_reliable_states = (1 << 1); /* C1 */
cpuidle_state_table = atom_cstates;
break;
case 0x2D: /* SNB Xeon */
cpuidle_state_table = snb_cstates;
break;
-#ifdef FUTURE_USE
- case 0x17: /* 23 - Core 2 Duo */
- lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
-#endif
default:
pr_debug(PREFIX "does not run on family %d model %d\n",
return -ENODEV;
}
+ if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
+ lapic_timer_reliable_states = 0xFFFFFFFF;
+
pr_debug(PREFIX "v" INTEL_IDLE_VERSION
" model 0x%X\n", boot_cpu_data.x86_model);
}
EXPORT_SYMBOL(ib_ud_header_init);
-/**
- * ib_lrh_header_pack - Pack LRH header struct into wire format
- * @lrh:unpacked LRH header struct
- * @buf:Buffer to pack into
- *
- * ib_lrh_header_pack() packs the LRH header structure @lrh into
- * wire format in the buffer @buf.
- */
-int ib_lrh_header_pack(struct ib_unpacked_lrh *lrh, void *buf)
-{
- ib_pack(lrh_table, ARRAY_SIZE(lrh_table), lrh, buf);
- return 0;
-}
-EXPORT_SYMBOL(ib_lrh_header_pack);
-
-/**
- * ib_lrh_header_unpack - Unpack LRH structure from wire format
- * @lrh:unpacked LRH header struct
- * @buf:Buffer to pack into
- *
- * ib_lrh_header_unpack() unpacks the LRH header structure from
- * wire format (in buf) into @lrh.
- */
-int ib_lrh_header_unpack(void *buf, struct ib_unpacked_lrh *lrh)
-{
- ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), buf, lrh);
- return 0;
-}
-EXPORT_SYMBOL(ib_lrh_header_unpack);
-
/**
* ib_ud_header_pack - Pack UD header struct into wire format
* @header:UD header struct
return ret ? ret : in_len;
}
+static int copy_wc_to_user(void __user *dest, struct ib_wc *wc)
+{
+ struct ib_uverbs_wc tmp;
+
+ tmp.wr_id = wc->wr_id;
+ tmp.status = wc->status;
+ tmp.opcode = wc->opcode;
+ tmp.vendor_err = wc->vendor_err;
+ tmp.byte_len = wc->byte_len;
+ tmp.ex.imm_data = (__u32 __force) wc->ex.imm_data;
+ tmp.qp_num = wc->qp->qp_num;
+ tmp.src_qp = wc->src_qp;
+ tmp.wc_flags = wc->wc_flags;
+ tmp.pkey_index = wc->pkey_index;
+ tmp.slid = wc->slid;
+ tmp.sl = wc->sl;
+ tmp.dlid_path_bits = wc->dlid_path_bits;
+ tmp.port_num = wc->port_num;
+ tmp.reserved = 0;
+
+ if (copy_to_user(dest, &tmp, sizeof tmp))
+ return -EFAULT;
+
+ return 0;
+}
+
ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
int out_len)
{
struct ib_uverbs_poll_cq cmd;
- struct ib_uverbs_poll_cq_resp *resp;
+ struct ib_uverbs_poll_cq_resp resp;
+ u8 __user *header_ptr;
+ u8 __user *data_ptr;
struct ib_cq *cq;
- struct ib_wc *wc;
- int ret = 0;
- int i;
- int rsize;
+ struct ib_wc wc;
+ int ret;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL);
- if (!wc)
- return -ENOMEM;
-
- rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc);
- resp = kmalloc(rsize, GFP_KERNEL);
- if (!resp) {
- ret = -ENOMEM;
- goto out_wc;
- }
-
cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
- if (!cq) {
- ret = -EINVAL;
- goto out;
- }
+ if (!cq)
+ return -EINVAL;
- resp->count = ib_poll_cq(cq, cmd.ne, wc);
+ /* we copy a struct ib_uverbs_poll_cq_resp to user space */
+ header_ptr = (void __user *)(unsigned long) cmd.response;
+ data_ptr = header_ptr + sizeof resp;
- put_cq_read(cq);
+ memset(&resp, 0, sizeof resp);
+ while (resp.count < cmd.ne) {
+ ret = ib_poll_cq(cq, 1, &wc);
+ if (ret < 0)
+ goto out_put;
+ if (!ret)
+ break;
+
+ ret = copy_wc_to_user(data_ptr, &wc);
+ if (ret)
+ goto out_put;
- for (i = 0; i < resp->count; i++) {
- resp->wc[i].wr_id = wc[i].wr_id;
- resp->wc[i].status = wc[i].status;
- resp->wc[i].opcode = wc[i].opcode;
- resp->wc[i].vendor_err = wc[i].vendor_err;
- resp->wc[i].byte_len = wc[i].byte_len;
- resp->wc[i].ex.imm_data = (__u32 __force) wc[i].ex.imm_data;
- resp->wc[i].qp_num = wc[i].qp->qp_num;
- resp->wc[i].src_qp = wc[i].src_qp;
- resp->wc[i].wc_flags = wc[i].wc_flags;
- resp->wc[i].pkey_index = wc[i].pkey_index;
- resp->wc[i].slid = wc[i].slid;
- resp->wc[i].sl = wc[i].sl;
- resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits;
- resp->wc[i].port_num = wc[i].port_num;
+ data_ptr += sizeof(struct ib_uverbs_wc);
+ ++resp.count;
}
- if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize))
+ if (copy_to_user(header_ptr, &resp, sizeof resp)) {
ret = -EFAULT;
+ goto out_put;
+ }
-out:
- kfree(resp);
+ ret = in_len;
-out_wc:
- kfree(wc);
- return ret ? ret : in_len;
+out_put:
+ put_cq_read(cq);
+ return ret;
}
ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
dst->grh.sgid_index = src->grh.sgid_index;
dst->grh.hop_limit = src->grh.hop_limit;
dst->grh.traffic_class = src->grh.traffic_class;
+ memset(&dst->grh.reserved, 0, sizeof(dst->grh.reserved));
dst->dlid = src->dlid;
dst->sl = src->sl;
dst->src_path_bits = src->src_path_bits;
dst->static_rate = src->static_rate;
dst->is_global = src->ah_flags & IB_AH_GRH ? 1 : 0;
dst->port_num = src->port_num;
+ dst->reserved = 0;
}
EXPORT_SYMBOL(ib_copy_ah_attr_to_user);
void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
struct ib_qp_attr *src)
{
+ dst->qp_state = src->qp_state;
dst->cur_qp_state = src->cur_qp_state;
dst->path_mtu = src->path_mtu;
dst->path_mig_state = src->path_mig_state;
dst->rnr_retry = src->rnr_retry;
dst->alt_port_num = src->alt_port_num;
dst->alt_timeout = src->alt_timeout;
+ memset(dst->reserved, 0, sizeof(dst->reserved));
}
EXPORT_SYMBOL(ib_copy_qp_attr_to_user);
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/jiffies.h>
-#include <linux/smp_lock.h>
#include <asm/pgtable.h>
#include "ipath_kernel.h"
struct net_device *ndev;
enum ib_mtu tmp;
- props->active_width = IB_WIDTH_4X;
+ props->active_width = IB_WIDTH_1X;
props->active_speed = 4;
props->port_cap_flags = IB_PORT_CM_SUP;
props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port];
tmp = iboe_get_mtu(ndev->mtu);
props->active_mtu = tmp ? min(props->max_mtu, tmp) : IB_MTU_256;
- props->state = netif_running(ndev) && netif_oper_up(ndev) ?
+ props->state = (netif_running(ndev) && netif_carrier_ok(ndev)) ?
IB_PORT_ACTIVE : IB_PORT_DOWN;
props->phys_state = state_to_phys_state(props->state);
ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ?
MLX4_WQE_CTRL_FENCE : 0) | size;
+ if (be16_to_cpu(vlan) < 0x1000) {
+ ctrl->ins_vlan = 1 << 6;
+ ctrl->vlan_tag = vlan;
+ }
+
/*
* Make sure descriptor is fully written before
* setting ownership bit (because HW can start
ctrl->owner_opcode = mlx4_ib_opcode[wr->opcode] |
(ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0) | blh;
- if (be16_to_cpu(vlan) < 0x1000) {
- ctrl->ins_vlan = 1 << 6;
- ctrl->vlan_tag = vlan;
- }
-
stamp = ind + qp->sq_spare_wqes;
ind += DIV_ROUND_UP(size * 16, 1U << qp->sq.wqe_shift);
}
}
-static int srp_queuecommand(struct scsi_cmnd *scmnd,
+static int srp_queuecommand_lck(struct scsi_cmnd *scmnd,
void (*done)(struct scsi_cmnd *))
{
struct srp_target_port *target = host_to_target(scmnd->device->host);
return SCSI_MLQUEUE_HOST_BUSY;
}
+static DEF_SCSI_QCMD(srp_queuecommand)
+
static int srp_alloc_iu_bufs(struct srp_target_port *target)
{
int i;
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/rcupdate.h>
-#include <linux/smp_lock.h>
#include "input-compat.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
if (index >= dev->keycodemax)
return -EINVAL;
- if (dev->keycodesize < sizeof(dev->keycode) &&
+ if (dev->keycodesize < sizeof(ke->keycode) &&
(ke->keycode >> (dev->keycodesize * 8)))
return -EINVAL;
goto err_free_tgfx;
}
+ parport_put_port(pp);
return tgfx;
err_free_dev:
To compile this driver as a module, choose M here: the
module will be called gpio_keys.
+config KEYBOARD_GPIO_POLLED
+ tristate "Polled GPIO buttons"
+ depends on GENERIC_GPIO
+ select INPUT_POLLDEV
+ help
+ This driver implements support for buttons connected
+ to GPIO pins that are not capable of generating interrupts.
+
+ Say Y here if your device has buttons connected
+ directly to such GPIO pins. Your board-specific
+ setup logic must also provide a platform device,
+ with configuration data saying which GPIOs are used.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gpio_keys_polled.
+
config KEYBOARD_TCA6416
tristate "TCA6416 Keypad Support"
depends on I2C
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
+obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o
obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
--- /dev/null
+/*
+ * Driver for buttons on GPIO lines not capable of generating interrupts
+ *
+ * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com>
+ *
+ * This file was based on: /drivers/input/misc/cobalt_btns.c
+ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * also was based on: /drivers/input/keyboard/gpio_keys.c
+ * Copyright 2005 Phil Blundell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+
+#define DRV_NAME "gpio-keys-polled"
+
+struct gpio_keys_button_data {
+ int last_state;
+ int count;
+ int threshold;
+ int can_sleep;
+};
+
+struct gpio_keys_polled_dev {
+ struct input_polled_dev *poll_dev;
+ struct device *dev;
+ struct gpio_keys_platform_data *pdata;
+ struct gpio_keys_button_data data[0];
+};
+
+static void gpio_keys_polled_check_state(struct input_dev *input,
+ struct gpio_keys_button *button,
+ struct gpio_keys_button_data *bdata)
+{
+ int state;
+
+ if (bdata->can_sleep)
+ state = !!gpio_get_value_cansleep(button->gpio);
+ else
+ state = !!gpio_get_value(button->gpio);
+
+ if (state != bdata->last_state) {
+ unsigned int type = button->type ?: EV_KEY;
+
+ input_event(input, type, button->code,
+ !!(state ^ button->active_low));
+ input_sync(input);
+ bdata->count = 0;
+ bdata->last_state = state;
+ }
+}
+
+static void gpio_keys_polled_poll(struct input_polled_dev *dev)
+{
+ struct gpio_keys_polled_dev *bdev = dev->private;
+ struct gpio_keys_platform_data *pdata = bdev->pdata;
+ struct input_dev *input = dev->input;
+ int i;
+
+ for (i = 0; i < bdev->pdata->nbuttons; i++) {
+ struct gpio_keys_button_data *bdata = &bdev->data[i];
+
+ if (bdata->count < bdata->threshold)
+ bdata->count++;
+ else
+ gpio_keys_polled_check_state(input, &pdata->buttons[i],
+ bdata);
+ }
+}
+
+static void gpio_keys_polled_open(struct input_polled_dev *dev)
+{
+ struct gpio_keys_polled_dev *bdev = dev->private;
+ struct gpio_keys_platform_data *pdata = bdev->pdata;
+
+ if (pdata->enable)
+ pdata->enable(bdev->dev);
+}
+
+static void gpio_keys_polled_close(struct input_polled_dev *dev)
+{
+ struct gpio_keys_polled_dev *bdev = dev->private;
+ struct gpio_keys_platform_data *pdata = bdev->pdata;
+
+ if (pdata->disable)
+ pdata->disable(bdev->dev);
+}
+
+static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
+{
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct gpio_keys_polled_dev *bdev;
+ struct input_polled_dev *poll_dev;
+ struct input_dev *input;
+ int error;
+ int i;
+
+ if (!pdata || !pdata->poll_interval)
+ return -EINVAL;
+
+ bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +
+ pdata->nbuttons * sizeof(struct gpio_keys_button_data),
+ GFP_KERNEL);
+ if (!bdev) {
+ dev_err(dev, "no memory for private data\n");
+ return -ENOMEM;
+ }
+
+ poll_dev = input_allocate_polled_device();
+ if (!poll_dev) {
+ dev_err(dev, "no memory for polled device\n");
+ error = -ENOMEM;
+ goto err_free_bdev;
+ }
+
+ poll_dev->private = bdev;
+ poll_dev->poll = gpio_keys_polled_poll;
+ poll_dev->poll_interval = pdata->poll_interval;
+ poll_dev->open = gpio_keys_polled_open;
+ poll_dev->close = gpio_keys_polled_close;
+
+ input = poll_dev->input;
+
+ input->evbit[0] = BIT(EV_KEY);
+ input->name = pdev->name;
+ input->phys = DRV_NAME"/input0";
+ input->dev.parent = &pdev->dev;
+
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = 0x0100;
+
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct gpio_keys_button *button = &pdata->buttons[i];
+ struct gpio_keys_button_data *bdata = &bdev->data[i];
+ unsigned int gpio = button->gpio;
+ unsigned int type = button->type ?: EV_KEY;
+
+ if (button->wakeup) {
+ dev_err(dev, DRV_NAME " does not support wakeup\n");
+ error = -EINVAL;
+ goto err_free_gpio;
+ }
+
+ error = gpio_request(gpio,
+ button->desc ? button->desc : DRV_NAME);
+ if (error) {
+ dev_err(dev, "unable to claim gpio %u, err=%d\n",
+ gpio, error);
+ goto err_free_gpio;
+ }
+
+ error = gpio_direction_input(gpio);
+ if (error) {
+ dev_err(dev,
+ "unable to set direction on gpio %u, err=%d\n",
+ gpio, error);
+ goto err_free_gpio;
+ }
+
+ bdata->can_sleep = gpio_cansleep(gpio);
+ bdata->last_state = -1;
+ bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
+ pdata->poll_interval);
+
+ input_set_capability(input, type, button->code);
+ }
+
+ bdev->poll_dev = poll_dev;
+ bdev->dev = dev;
+ bdev->pdata = pdata;
+ platform_set_drvdata(pdev, bdev);
+
+ error = input_register_polled_device(poll_dev);
+ if (error) {
+ dev_err(dev, "unable to register polled device, err=%d\n",
+ error);
+ goto err_free_gpio;
+ }
+
+ /* report initial state of the buttons */
+ for (i = 0; i < pdata->nbuttons; i++)
+ gpio_keys_polled_check_state(input, &pdata->buttons[i],
+ &bdev->data[i]);
+
+ return 0;
+
+err_free_gpio:
+ while (--i >= 0)
+ gpio_free(pdata->buttons[i].gpio);
+
+ input_free_polled_device(poll_dev);
+
+err_free_bdev:
+ kfree(bdev);
+
+ platform_set_drvdata(pdev, NULL);
+ return error;
+}
+
+static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
+{
+ struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev);
+ struct gpio_keys_platform_data *pdata = bdev->pdata;
+ int i;
+
+ input_unregister_polled_device(bdev->poll_dev);
+
+ for (i = 0; i < pdata->nbuttons; i++)
+ gpio_free(pdata->buttons[i].gpio);
+
+ input_free_polled_device(bdev->poll_dev);
+
+ kfree(bdev);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver gpio_keys_polled_driver = {
+ .probe = gpio_keys_polled_probe,
+ .remove = __devexit_p(gpio_keys_polled_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init gpio_keys_polled_init(void)
+{
+ return platform_driver_register(&gpio_keys_polled_driver);
+}
+
+static void __exit gpio_keys_polled_exit(void)
+{
+ platform_driver_unregister(&gpio_keys_polled_driver);
+}
+
+module_init(gpio_keys_polled_init);
+module_exit(gpio_keys_polled_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_DESCRIPTION("Polled GPIO Buttons driver");
+MODULE_ALIAS("platform:" DRV_NAME);
#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
-#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100)
+#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
+#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */
#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000)
/* synaptics modes query bits */
gscps2_reset(ps2port);
ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f;
- snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s",
+ snprintf(serio->name, sizeof(serio->name), "gsc-ps2-%s",
(ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse");
strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys));
serio->id.type = SERIO_8042;
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/serio.h>
}
static DEVICE_ATTR(pointer_mode,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletPointerMode, store_tabletPointerMode);
/***********************************************************************
}
static DEVICE_ATTR(coordinate_mode,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletCoordinateMode, store_tabletCoordinateMode);
/***********************************************************************
}
static DEVICE_ATTR(tool_mode,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletToolMode, store_tabletToolMode);
/***********************************************************************
}
static DEVICE_ATTR(xtilt,
- S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt);
+ S_IRUGO | S_IWUSR, show_tabletXtilt, store_tabletXtilt);
/***********************************************************************
* support routines for the 'ytilt' file. Note that this file
}
static DEVICE_ATTR(ytilt,
- S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt);
+ S_IRUGO | S_IWUSR, show_tabletYtilt, store_tabletYtilt);
/***********************************************************************
* support routines for the 'jitter' file. Note that this file
}
static DEVICE_ATTR(jitter,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletJitterDelay, store_tabletJitterDelay);
/***********************************************************************
}
static DEVICE_ATTR(delay,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletProgrammableDelay, store_tabletProgrammableDelay);
/***********************************************************************
}
static DEVICE_ATTR(stylus_upper,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletStylusUpper, store_tabletStylusUpper);
/***********************************************************************
}
static DEVICE_ATTR(stylus_lower,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletStylusLower, store_tabletStylusLower);
/***********************************************************************
}
static DEVICE_ATTR(mouse_left,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletMouseLeft, store_tabletMouseLeft);
/***********************************************************************
}
static DEVICE_ATTR(mouse_middle,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletMouseMiddle, store_tabletMouseMiddle);
/***********************************************************************
}
static DEVICE_ATTR(mouse_right,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletMouseRight, store_tabletMouseRight);
/***********************************************************************
}
static DEVICE_ATTR(wheel,
- S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel);
+ S_IRUGO | S_IWUSR, show_tabletWheel, store_tabletWheel);
/***********************************************************************
* support routines for the 'execute' file. Note that this file
}
static DEVICE_ATTR(execute,
- S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute);
+ S_IRUGO | S_IWUSR, show_tabletExecute, store_tabletExecute);
/***********************************************************************
* support routines for the 'odm_code' file. Note that this file
{ "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
static struct wacom_features wacom_features_0xD3 =
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD8 =
+ { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xDA =
+ { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xDB =
+ { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT };
#define USB_DEVICE_WACOM(prod) \
USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \
{ USB_DEVICE_WACOM(0xD1) },
{ USB_DEVICE_WACOM(0xD2) },
{ USB_DEVICE_WACOM(0xD3) },
+ { USB_DEVICE_WACOM(0xD8) },
+ { USB_DEVICE_WACOM(0xDA) },
+ { USB_DEVICE_WACOM(0xDB) },
{ USB_DEVICE_WACOM(0xF0) },
{ USB_DEVICE_WACOM(0xCC) },
{ USB_DEVICE_WACOM(0x90) },
#ifdef CONFIG_TOUCHSCREEN_USB_ITM
{USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
+ {USB_DEVICE(0x16e3, 0xf9e9), .driver_info = DEVTYPE_ITM},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
static int __init icn_init(void)
{
char *p;
- char rev[10];
+ char rev[20];
memset(&dev, 0, sizeof(icn_dev));
dev.memaddr = (membase & 0x0ffc000);
spin_lock_init(&dev.devlock);
if ((p = strchr(revision, ':'))) {
- strcpy(rev, p + 1);
+ strncpy(rev, p + 1, 20);
p = strchr(rev, '$');
- *p = 0;
+ if (p)
+ *p = 0;
} else
strcpy(rev, " ??? ");
printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
This is not related to standard keyboard LEDs which are controlled
via the input system.
-if NEW_LEDS
-
config LEDS_CLASS
bool "LED Class Support"
+ depends on NEW_LEDS
help
This option enables the led sysfs class in /sys/class/leds. You'll
need this to do anything useful with LEDs. If unsure, say N.
-if LEDS_CLASS
+if NEW_LEDS
comment "LED drivers"
config LEDS_88PM860X
tristate "LED Support for Marvell 88PM860x PMIC"
+ depends on LEDS_CLASS
depends on MFD_88PM860X
help
This option enables support for on-chip LED drivers found on Marvell
config LEDS_ATMEL_PWM
tristate "LED Support using Atmel PWM outputs"
+ depends on LEDS_CLASS
depends on ATMEL_PWM
help
This option enables support for LEDs driven using outputs
config LEDS_LOCOMO
tristate "LED Support for Locomo device"
+ depends on LEDS_CLASS
depends on SHARP_LOCOMO
help
This option enables support for the LEDs on Sharp Locomo.
config LEDS_MIKROTIK_RB532
tristate "LED Support for Mikrotik Routerboard 532"
+ depends on LEDS_CLASS
depends on MIKROTIK_RB532
help
This option enables support for the so called "User LED" of
config LEDS_S3C24XX
tristate "LED Support for Samsung S3C24XX GPIO LEDs"
+ depends on LEDS_CLASS
depends on ARCH_S3C2410
help
This option enables support for LEDs connected to GPIO lines
config LEDS_AMS_DELTA
tristate "LED Support for the Amstrad Delta (E3)"
+ depends on LEDS_CLASS
depends on MACH_AMS_DELTA
help
This option enables support for the LEDs on Amstrad Delta (E3).
config LEDS_NET48XX
tristate "LED Support for Soekris net48xx series Error LED"
+ depends on LEDS_CLASS
depends on SCx200_GPIO
help
This option enables support for the Soekris net4801 and net4826 error
config LEDS_FSG
tristate "LED Support for the Freecom FSG-3"
+ depends on LEDS_CLASS
depends on MACH_FSG
help
This option enables support for the LEDs on the Freecom FSG-3.
config LEDS_WRAP
tristate "LED Support for the WRAP series LEDs"
+ depends on LEDS_CLASS
depends on SCx200_GPIO
help
This option enables support for the PCEngines WRAP programmable LEDs.
config LEDS_ALIX2
tristate "LED Support for ALIX.2 and ALIX.3 series"
+ depends on LEDS_CLASS
depends on X86 && !GPIO_CS5535 && !CS5535_GPIO
help
This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
config LEDS_H1940
tristate "LED Support for iPAQ H1940 device"
+ depends on LEDS_CLASS
depends on ARCH_H1940
help
This option enables support for the LEDs on the h1940.
config LEDS_COBALT_QUBE
tristate "LED Support for the Cobalt Qube series front LED"
+ depends on LEDS_CLASS
depends on MIPS_COBALT
help
This option enables support for the front LED on Cobalt Qube series
config LEDS_SUNFIRE
tristate "LED support for SunFire servers."
+ depends on LEDS_CLASS
depends on SPARC64
select LEDS_TRIGGERS
help
config LEDS_HP6XX
tristate "LED Support for the HP Jornada 6xx"
+ depends on LEDS_CLASS
depends on SH_HP6XX
help
This option enables LED support for the handheld
config LEDS_PCA9532
tristate "LED driver for PCA9532 dimmer"
+ depends on LEDS_CLASS
depends on I2C && INPUT && EXPERIMENTAL
help
This option enables support for NXP pca9532
config LEDS_GPIO
tristate "LED Support for GPIO connected LEDs"
+ depends on LEDS_CLASS
depends on GENERIC_GPIO
help
This option enables support for the LEDs connected to GPIO
config LEDS_LP3944
tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
+ depends on LEDS_CLASS
depends on I2C
help
This option enables support for LEDs connected to the National
config LEDS_CLEVO_MAIL
tristate "Mail LED on Clevo notebook"
+ depends on LEDS_CLASS
depends on X86 && SERIO_I8042 && DMI
help
This driver makes the mail LED accessible from userspace
config LEDS_PCA955X
tristate "LED Support for PCA955x I2C chips"
+ depends on LEDS_CLASS
depends on I2C
help
This option enables support for LEDs connected to PCA955x
config LEDS_WM831X_STATUS
tristate "LED support for status LEDs on WM831x PMICs"
+ depends on LEDS_CLASS
depends on MFD_WM831X
help
This option enables support for the status LEDs of the WM831x
config LEDS_WM8350
tristate "LED Support for WM8350 AudioPlus PMIC"
+ depends on LEDS_CLASS
depends on MFD_WM8350
help
This option enables support for LEDs driven by the Wolfson
config LEDS_DA903X
tristate "LED Support for DA9030/DA9034 PMIC"
+ depends on LEDS_CLASS
depends on PMIC_DA903X
help
This option enables support for on-chip LED drivers found
config LEDS_DAC124S085
tristate "LED Support for DAC124S085 SPI DAC"
+ depends on LEDS_CLASS
depends on SPI
help
This option enables support for DAC124S085 SPI DAC from NatSemi,
config LEDS_PWM
tristate "PWM driven LED Support"
+ depends on LEDS_CLASS
depends on HAVE_PWM
help
This option enables support for pwm driven LEDs
config LEDS_REGULATOR
tristate "REGULATOR driven LED support"
+ depends on LEDS_CLASS
depends on REGULATOR
help
This option enables support for regulator driven LEDs.
config LEDS_BD2802
tristate "LED driver for BD2802 RGB LED"
+ depends on LEDS_CLASS
depends on I2C
help
This option enables support for BD2802GU RGB LED driver chips
config LEDS_INTEL_SS4200
tristate "LED driver for Intel NAS SS4200 series"
+ depends on LEDS_CLASS
depends on PCI && DMI
help
This option enables support for the Intel SS4200 series of
config LEDS_LT3593
tristate "LED driver for LT3593 controllers"
+ depends on LEDS_CLASS
depends on GENERIC_GPIO
help
This option enables support for LEDs driven by a Linear Technology
config LEDS_ADP5520
tristate "LED Support for ADP5520/ADP5501 PMIC"
+ depends on LEDS_CLASS
depends on PMIC_ADP5520
help
This option enables support for on-chip LED drivers found
config LEDS_DELL_NETBOOKS
tristate "External LED on Dell Business Netbooks"
+ depends on LEDS_CLASS
depends on X86 && ACPI_WMI
help
This adds support for the Latitude 2100 and similar
config LEDS_MC13783
tristate "LED Support for MC13783 PMIC"
+ depends on LEDS_CLASS
depends on MFD_MC13783
help
This option enable support for on-chip LED drivers found
config LEDS_NS2
tristate "LED support for Network Space v2 GPIO LEDs"
+ depends on LEDS_CLASS
depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2 || D2NET_V2
default y
help
config LEDS_TRIGGERS
bool "LED Trigger support"
+ depends on LEDS_CLASS
help
This option enables trigger support for the leds class.
These triggers allow kernel events to drive the LEDs and can
be configured via sysfs. If unsure, say Y.
-if LEDS_TRIGGERS
-
comment "LED Triggers"
config LEDS_TRIGGER_TIMER
tristate "LED Timer Trigger"
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled by a programmable timer
via sysfs. Some LED hardware can be programmed to start
config LEDS_TRIGGER_IDE_DISK
bool "LED IDE Disk Trigger"
depends on IDE_GD_ATA
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled by IDE disk activity.
If unsure, say Y.
config LEDS_TRIGGER_HEARTBEAT
tristate "LED Heartbeat Trigger"
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled by a CPU load average.
The flash frequency is a hyperbolic function of the 1-minute
config LEDS_TRIGGER_BACKLIGHT
tristate "LED backlight Trigger"
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled as a backlight device: they
turn off and on when the display is blanked and unblanked.
config LEDS_TRIGGER_GPIO
tristate "LED GPIO Trigger"
+ depends on LEDS_TRIGGERS
depends on GPIOLIB
help
This allows LEDs to be controlled by gpio events. It's good
config LEDS_TRIGGER_DEFAULT_ON
tristate "LED Default ON Trigger"
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be initialised in the ON state.
If unsure, say Y.
comment "iptables trigger is under Netfilter config (LED target)"
depends on LEDS_TRIGGERS
-endif # LEDS_TRIGGERS
-
-endif # LEDS_CLASS
-
endif # NEW_LEDS
u8 num_leds;
};
-#define cdev_to_led(c) container_of(c, struct lp5521_led, cdev)
-#define engine_to_lp5521(eng) container_of((eng), struct lp5521_chip, \
- engines[(eng)->id - 1])
-#define led_to_lp5521(led) container_of((led), struct lp5521_chip, \
- leds[(led)->id])
+static inline struct lp5521_led *cdev_to_led(struct led_classdev *cdev)
+{
+ return container_of(cdev, struct lp5521_led, cdev);
+}
+
+static inline struct lp5521_chip *engine_to_lp5521(struct lp5521_engine *engine)
+{
+ return container_of(engine, struct lp5521_chip,
+ engines[engine->id - 1]);
+}
+
+static inline struct lp5521_chip *led_to_lp5521(struct lp5521_led *led)
+{
+ return container_of(led, struct lp5521_chip,
+ leds[led->id]);
+}
static void lp5521_led_brightness_work(struct work_struct *work);
/* move current engine to direct mode and remember the state */
ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT);
- usleep_range(1000, 10000);
+ /* Mode change requires min 500 us delay. 1 - 2 ms with margin */
+ usleep_range(1000, 2000);
ret |= lp5521_read(client, LP5521_REG_OP_MODE, &mode);
/* For loading, all the engines to load mode */
lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
- usleep_range(1000, 10000);
+ /* Mode change requires min 500 us delay. 1 - 2 ms with margin */
+ usleep_range(1000, 2000);
lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
- usleep_range(1000, 10000);
+ /* Mode change requires min 500 us delay. 1 - 2 ms with margin */
+ usleep_range(1000, 2000);
addr = LP5521_PROG_MEM_BASE + eng->prog_page * LP5521_PROG_MEM_SIZE;
i2c_smbus_write_i2c_block_data(client,
lp5521_init_engine(chip, attr_group);
- lp5521_write(client, LP5521_REG_RESET, 0xff);
-
- usleep_range(10000, 20000);
-
/* Set all PWMs to direct control mode */
ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F);
ret |= lp5521_write(client, LP5521_REG_ENABLE,
LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM |
LP5521_EXEC_RUN);
- /* enable takes 500us */
- usleep_range(500, 20000);
+ /* enable takes 500us. 1 - 2 ms leaves some margin */
+ usleep_range(1000, 2000);
return ret;
}
LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM);
if (ret)
return ret;
- usleep_range(1000, 10000);
+ /* enable takes 500us. 1 - 2 ms leaves some margin */
+ usleep_range(1000, 2000);
ret = lp5521_read(client, LP5521_REG_ENABLE, &buf);
if (ret)
return ret;
if (pdata->enable) {
pdata->enable(0);
- usleep_range(1000, 10000);
+ usleep_range(1000, 2000); /* Keep enable down at least 1ms */
pdata->enable(1);
- usleep_range(1000, 10000); /* Spec says min 500us */
+ usleep_range(1000, 2000); /* 500us abs min. */
}
+ lp5521_write(client, LP5521_REG_RESET, 0xff);
+ usleep_range(10000, 20000); /*
+ * Exact value is not available. 10 - 20ms
+ * appears to be enough for reset.
+ */
ret = lp5521_detect(client);
if (ret) {
u8 num_leds;
};
-#define cdev_to_led(c) container_of(c, struct lp5523_led, cdev)
+static inline struct lp5523_led *cdev_to_led(struct led_classdev *cdev)
+{
+ return container_of(cdev, struct lp5523_led, cdev);
+}
-static struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine)
+static inline struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine)
{
return container_of(engine, struct lp5523_chip,
engines[engine->id - 1]);
}
-static struct lp5523_chip *led_to_lp5523(struct lp5523_led *led)
+static inline struct lp5523_chip *led_to_lp5523(struct lp5523_led *led)
{
return container_of(led, struct lp5523_chip,
leds[led->id]);
{ 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0},
};
- lp5523_write(client, LP5523_REG_RESET, 0xff);
-
- usleep_range(10000, 100000);
-
ret |= lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE);
- /* Chip startup time after reset is 500 us */
- usleep_range(1000, 10000);
+ /* Chip startup time is 500 us, 1 - 2 ms gives some margin */
+ usleep_range(1000, 2000);
ret |= lp5523_write(client, LP5523_REG_CONFIG,
LP5523_AUTO_INC | LP5523_PWR_SAVE |
return -1;
}
- /* Wait 3ms and check the engine status */
- usleep_range(3000, 20000);
+ /* Let the programs run for couple of ms and check the engine status */
+ usleep_range(3000, 6000);
lp5523_read(client, LP5523_REG_STATUS, &status);
status &= LP5523_ENG_STATUS_MASK;
/* Measure VDD (i.e. VBAT) first (channel 16 corresponds to VDD) */
lp5523_write(chip->client, LP5523_REG_LED_TEST_CTRL,
LP5523_EN_LEDTEST | 16);
- usleep_range(3000, 10000);
+ usleep_range(3000, 6000); /* ADC conversion time is typically 2.7 ms */
ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
if (!(status & LP5523_LEDTEST_DONE))
- usleep_range(3000, 10000);
+ usleep_range(3000, 6000); /* Was not ready. Wait little bit */
ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &vdd);
vdd--; /* There may be some fluctuation in measurement */
chip->pdata->led_config[i].led_current);
lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0xff);
- /* let current stabilize 2ms before measurements start */
- usleep_range(2000, 10000);
+ /* let current stabilize 2 - 4ms before measurements start */
+ usleep_range(2000, 4000);
lp5523_write(chip->client,
LP5523_REG_LED_TEST_CTRL,
LP5523_EN_LEDTEST | i);
- /* ledtest takes 2.7ms */
- usleep_range(3000, 10000);
+ /* ADC conversion time is 2.7 ms typically */
+ usleep_range(3000, 6000);
ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
if (!(status & LP5523_LEDTEST_DONE))
- usleep_range(3000, 10000);
+ usleep_range(3000, 6000);/* Was not ready. Wait. */
ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &adc);
if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM)
if (pdata->enable) {
pdata->enable(0);
- usleep_range(1000, 10000);
+ usleep_range(1000, 2000); /* Keep enable down at least 1ms */
pdata->enable(1);
- usleep_range(1000, 10000); /* Spec says min 500us */
+ usleep_range(1000, 2000); /* 500us abs min. */
}
+ lp5523_write(client, LP5523_REG_RESET, 0xff);
+ usleep_range(10000, 20000); /*
+ * Exact value is not available. 10 - 20ms
+ * appears to be enough for reset.
+ */
ret = lp5523_detect(client);
if (ret)
goto fail2;
DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
}
},
+ {}
};
/*
config ADB_PMU_LED_IDE
bool "Use front LED as IDE LED by default"
depends on ADB_PMU_LED
+ depends on LEDS_CLASS
select LEDS_TRIGGERS
select LEDS_TRIGGER_IDE_DISK
help
bio_put(bio);
}
-static void submit_flushes(mddev_t *mddev)
+static void md_submit_flush_data(struct work_struct *ws);
+
+static void submit_flushes(struct work_struct *ws)
{
+ mddev_t *mddev = container_of(ws, mddev_t, flush_work);
mdk_rdev_t *rdev;
+ INIT_WORK(&mddev->flush_work, md_submit_flush_data);
+ atomic_set(&mddev->flush_pending, 1);
rcu_read_lock();
list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0 &&
rdev_dec_pending(rdev, mddev);
}
rcu_read_unlock();
+ if (atomic_dec_and_test(&mddev->flush_pending))
+ queue_work(md_wq, &mddev->flush_work);
}
static void md_submit_flush_data(struct work_struct *ws)
mddev_t *mddev = container_of(ws, mddev_t, flush_work);
struct bio *bio = mddev->flush_bio;
- atomic_set(&mddev->flush_pending, 1);
-
if (bio->bi_size == 0)
/* an empty barrier - all done */
bio_endio(bio, 0);
if (mddev->pers->make_request(mddev, bio))
generic_make_request(bio);
}
- if (atomic_dec_and_test(&mddev->flush_pending)) {
- mddev->flush_bio = NULL;
- wake_up(&mddev->sb_wait);
- }
+
+ mddev->flush_bio = NULL;
+ wake_up(&mddev->sb_wait);
}
void md_flush_request(mddev_t *mddev, struct bio *bio)
mddev->flush_bio = bio;
spin_unlock_irq(&mddev->write_lock);
- atomic_set(&mddev->flush_pending, 1);
- INIT_WORK(&mddev->flush_work, md_submit_flush_data);
-
- submit_flushes(mddev);
-
- if (atomic_dec_and_test(&mddev->flush_pending))
- queue_work(md_wq, &mddev->flush_work);
+ INIT_WORK(&mddev->flush_work, submit_flushes);
+ queue_work(md_wq, &mddev->flush_work);
}
EXPORT_SYMBOL(md_flush_request);
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
rdev->sb_page);
md_super_wait(rdev->mddev);
- return num_sectors / 2; /* kB for sysfs */
+ return num_sectors;
}
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
rdev->sb_page);
md_super_wait(rdev->mddev);
- return num_sectors / 2; /* kB for sysfs */
+ return num_sectors;
}
static struct super_type super_types[] = {
if (mddev->kobj.sd &&
sysfs_create_group(&mddev->kobj, &md_bitmap_group))
printk(KERN_DEBUG "pointless warning\n");
+
+ blk_queue_flush(mddev->queue, REQ_FLUSH | REQ_FUA);
abort:
mutex_unlock(&disks_mutex);
if (!error && mddev->kobj.sd) {
PTR_ERR(rdev));
return PTR_ERR(rdev);
}
- /* set save_raid_disk if appropriate */
+ /* set saved_raid_disk if appropriate */
if (!mddev->persistent) {
if (info->state & (1<<MD_DISK_SYNC) &&
info->raid_disk < mddev->raid_disks)
} else
super_types[mddev->major_version].
validate_super(mddev, rdev);
- rdev->saved_raid_disk = rdev->raid_disk;
+ if (test_bit(In_sync, &rdev->flags))
+ rdev->saved_raid_disk = rdev->raid_disk;
+ else
+ rdev->saved_raid_disk = -1;
clear_bit(In_sync, &rdev->flags); /* just to be sure */
if (info->state & (1<<MD_DISK_WRITEMOSTLY))
|| kthread_should_stop(),
thread->timeout);
- clear_bit(THREAD_WAKEUP, &thread->flags);
-
- thread->run(thread->mddev);
+ if (test_and_clear_bit(THREAD_WAKEUP, &thread->flags))
+ thread->run(thread->mddev);
}
return 0;
* is not possible.
*/
if (!test_bit(Faulty, &rdev->flags) &&
+ !mddev->recovery_disabled &&
mddev->degraded < conf->raid_disks) {
err = -EBUSY;
goto abort;
return 0;
out_free_conf:
+ md_unregister_thread(mddev->thread);
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
safe_put_page(conf->tmppage);
kfree(conf->mirrors);
kfree(conf);
mddev->private = NULL;
- md_unregister_thread(mddev->thread);
out:
return -EIO;
}
select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
-menuconfig MEDIA_TUNER_CUSTOMISE
+config MEDIA_TUNER_CUSTOMISE
bool "Customize analog and hybrid tuner modules to build"
depends on MEDIA_TUNER
default y if EMBEDDED
If unsure say N.
-if MEDIA_TUNER_CUSTOMISE
+menu "Customize TV tuners"
+ visible if MEDIA_TUNER_CUSTOMISE
config MEDIA_TUNER_SIMPLE
tristate "Simple tuner support"
default m if MEDIA_TUNER_CUSTOMISE
help
NXP TDA18218 silicon tuner driver.
-
-endif # MEDIA_TUNER_CUSTOMISE
+endmenu
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include "dvb_ca_en50221.h"
#include <linux/list.h>
#include <linux/freezer.h>
#include <linux/jiffies.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include <asm/processor.h>
If unsure say N.
-if DVB_FE_CUSTOMISE
-
menu "Customise DVB Frontends"
+ visible if DVB_FE_CUSTOMISE
comment "Multistandard (satellite) frontends"
depends on DVB_CORE
tristate "Dummy frontend driver"
default n
endmenu
-
-endif
#include <linux/io.h>
#include <asm/div64.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
#include <linux/io.h>
#include <asm/div64.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
#include <asm/div64.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
goto unregister_v4l2_dev;
}
- sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, NULL,
+ sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter,
pdata->subdev_board_info, NULL);
if (!sd) {
dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/version.h>
#include <linux/videodev2.h>
#
menu "Encoders/decoders and other helper chips"
- depends on !VIDEO_HELPER_CHIPS_AUTO
+ visible if !VIDEO_HELPER_CHIPS_AUTO
comment "Audio decoders"
be abstracted out if we ever need to support a different
demod) */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "au8522", 0x8e >> 1, NULL);
+ "au8522", 0x8e >> 1, NULL);
if (sd == NULL)
printk(KERN_ERR "analog subdev registration failed\n");
}
if (dev->board.tuner_type != TUNER_ABSENT) {
/* Load the tuner module, which does the attach */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tuner", dev->board.tuner_addr, NULL);
+ "tuner", dev->board.tuner_addr, NULL);
if (sd == NULL)
printk(KERN_ERR "tuner subdev registration fail\n");
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "saa6588", 0, addrs);
+ &btv->c.i2c_adap, "saa6588", 0, addrs);
btv->has_saa6588 = (sd != NULL);
}
};
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "msp3400", 0, addrs);
+ &btv->c.i2c_adap, "msp3400", 0, addrs);
if (btv->sd_msp34xx)
return;
goto no_audio;
};
if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tda7432", 0, addrs))
+ &btv->c.i2c_adap, "tda7432", 0, addrs))
return;
goto no_audio;
}
case 3: {
/* The user specified that we should probe for tvaudio */
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs());
+ &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
goto no_audio;
found is really something else (e.g. a tea6300). */
if (!bttv_tvcards[btv->c.type].no_msp34xx) {
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "msp3400",
+ &btv->c.i2c_adap, "msp3400",
0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1));
} else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "msp3400",
+ &btv->c.i2c_adap, "msp3400",
0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1));
}
};
if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tda7432", 0, addrs))
+ &btv->c.i2c_adap, "tda7432", 0, addrs))
return;
}
/* Now see if we can find one of the tvaudio devices. */
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs());
+ &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
/* Load tuner module before issuing tuner config call! */
if (bttv_tvcards[btv->c.type].has_radio)
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tuner",
+ &btv->c.i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tuner",
+ &btv->c.i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tuner",
+ &btv->c.i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
#include "bttvp.h"
cam->sensor_addr = 0x42;
cam->sensor = v4l2_i2c_new_subdev_cfg(&cam->v4l2_dev, &cam->i2c_adapter,
- "ov7670", "ov7670", 0, &sensor_cfg, cam->sensor_addr,
- NULL);
+ "ov7670", 0, &sensor_cfg, cam->sensor_addr, NULL);
if (cam->sensor == NULL) {
ret = -ENODEV;
goto out_smbus;
if (hw == CX18_HW_TUNER) {
/* special tuner group handling */
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, NULL, type, 0, cx->card_i2c->radio);
+ adap, type, 0, cx->card_i2c->radio);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, NULL, type, 0, cx->card_i2c->demod);
+ adap, type, 0, cx->card_i2c->demod);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, NULL, type, 0, cx->card_i2c->tv);
+ adap, type, 0, cx->card_i2c->tv);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
return -1;
/* It's an I2C device other than an analog tuner or IR chip */
- sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, NULL, type, hw_addrs[idx],
+ sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, type, hw_addrs[idx],
NULL);
if (sd != NULL)
sd->grp_id = hw;
if (dev->board.decoder == CX231XX_AVDECODER) {
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[0].i2c_adap,
- NULL, "cx25840", 0x88 >> 1, NULL);
+ "cx25840", 0x88 >> 1, NULL);
if (dev->sd_cx25840 == NULL)
cx231xx_info("cx25840 subdev registration failure\n");
cx25840_call(dev, core, load_fw);
if (dev->board.tuner_type != TUNER_ABSENT) {
dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
- NULL, "tuner",
+ "tuner",
dev->tuner_addr, NULL);
if (dev->sd_tuner == NULL)
cx231xx_info("tuner subdev registration failure\n");
case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
- NULL, "cx25840", 0x88 >> 1, NULL);
+ "cx25840", 0x88 >> 1, NULL);
if (dev->sd_cx25840) {
dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE;
v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
if (dev->tuner_addr)
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
- NULL, "tuner", dev->tuner_addr, NULL);
+ "tuner", dev->tuner_addr, NULL);
else
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_bus[1].i2c_adap, NULL,
+ &dev->i2c_bus[1].i2c_adap,
"tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
if (sd) {
struct tuner_setup tun_setup;
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
-#include <linux/smp_lock.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/cx2341x.h>
later code configures a tea5767.
*/
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- NULL, "tuner",
- 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+ "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
if (has_demod)
v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap, NULL, "tuner",
+ &core->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (core->board.tuner_addr == ADDR_UNSET) {
v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap, NULL, "tuner",
+ &core->i2c_adap, "tuner",
0, has_demod ? tv_addrs + 4 : tv_addrs);
} else {
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- NULL, "tuner", core->board.tuner_addr, NULL);
+ "tuner", core->board.tuner_addr, NULL);
}
}
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
if (core->board.audio_chip == V4L2_IDENT_WM8775)
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- NULL, "wm8775", 0x36 >> 1, NULL);
+ "wm8775", 0x36 >> 1, NULL);
if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
/* This probes for a tda9874 as is used on some
Pixelview Ultra boards. */
- v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap,
- NULL, "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
+ v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
+ "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
}
switch (core->boardnr) {
vpfe_dev->sd[i] =
v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
i2c_adap,
- NULL,
&sdinfo->board_info,
NULL);
if (vpfe_dev->sd[i]) {
vpif_obj.sd[i] =
v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
i2c_adap,
- NULL,
&subdevdata->board_info,
NULL);
for (i = 0; i < subdev_count; i++) {
vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
- i2c_adap, NULL,
+ i2c_adap,
&subdevdata[i].board_info,
NULL);
if (!vpif_obj.sd[i]) {
/* request some modules */
if (dev->board.has_msp34xx)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "msp3400", 0, msp3400_addrs);
+ "msp3400", 0, msp3400_addrs);
if (dev->board.decoder == EM28XX_SAA711X)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "saa7115_auto", 0, saa711x_addrs);
+ "saa7115_auto", 0, saa711x_addrs);
if (dev->board.decoder == EM28XX_TVP5150)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tvp5150", 0, tvp5150_addrs);
+ "tvp5150", 0, tvp5150_addrs);
if (dev->em28xx_sensor == EM28XX_MT9V011) {
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "mt9v011", 0, mt9v011_addrs);
+ &dev->i2c_adap, "mt9v011", 0, mt9v011_addrs);
v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
}
if (dev->board.adecoder == EM28XX_TVAUDIO)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tvaudio", dev->board.tvaudio_addr, NULL);
+ "tvaudio", dev->board.tvaudio_addr, NULL);
if (dev->board.tuner_type != TUNER_ABSENT) {
int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
if (dev->board.radio.type)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tuner", dev->board.radio_addr, NULL);
+ "tuner", dev->board.radio_addr, NULL);
if (has_demod)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == 0) {
enum v4l2_i2c_tuner_type type =
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(type));
if (sd)
dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
} else {
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tuner", dev->tuner_addr, NULL);
+ "tuner", dev->tuner_addr, NULL);
}
}
ad = i2c_get_adapter(0);
viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
- NULL, "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
+ "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
viu_dev->vidq.timeout.function = viu_vid_timeout;
viu_dev->vidq.timeout.data = (unsigned long)viu_dev;
return -1;
if (hw == IVTV_HW_TUNER) {
/* special tuner handling */
- sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, NULL, type,
- 0, itv->card_i2c->radio);
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+ itv->card_i2c->radio);
if (sd)
sd->grp_id = 1 << idx;
- sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, NULL, type,
- 0, itv->card_i2c->demod);
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+ itv->card_i2c->demod);
if (sd)
sd->grp_id = 1 << idx;
- sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, NULL, type,
- 0, itv->card_i2c->tv);
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+ itv->card_i2c->tv);
if (sd)
sd->grp_id = 1 << idx;
return sd ? 0 : -1;
/* It's an I2C device other than an analog tuner or IR chip */
if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, NULL, type, 0, I2C_ADDRS(hw_addrs[idx]));
+ adap, type, 0, I2C_ADDRS(hw_addrs[idx]));
} else if (hw == IVTV_HW_CX25840) {
struct cx25840_platform_data pdata;
pdata.pvr150_workaround = itv->pvr150_workaround;
sd = v4l2_i2c_new_subdev_cfg(&itv->v4l2_dev,
- adap, NULL, type, 0, &pdata, hw_addrs[idx],
- NULL);
+ adap, type, 0, &pdata, hw_addrs[idx], NULL);
} else {
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, NULL, type, hw_addrs[idx], NULL);
+ adap, type, hw_addrs[idx], NULL);
}
if (sd)
sd->grp_id = 1 << idx;
}
mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "saa7111", I2C_SAA7111A, NULL);
+ "saa7111", I2C_SAA7111A, NULL);
mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "tea6420", I2C_TEA6420_1, NULL);
+ "tea6420", I2C_TEA6420_1, NULL);
mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "tea6420", I2C_TEA6420_2, NULL);
+ "tea6420", I2C_TEA6420_2, NULL);
mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "tea6415c", I2C_TEA6415C, NULL);
+ "tea6415c", I2C_TEA6415C, NULL);
mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "tda9840", I2C_TDA9840, NULL);
+ "tda9840", I2C_TDA9840, NULL);
mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "tuner", I2C_TUNER, NULL);
+ "tuner", I2C_TUNER, NULL);
/* check if all devices are present */
if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
" Setting up with specified i2c address 0x%x",
mid, i2caddr[0]);
sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
- NULL, fname,
- i2caddr[0], NULL);
+ fname, i2caddr[0], NULL);
} else {
pvr2_trace(PVR2_TRACE_INIT,
"Module ID %u:"
" Setting up with address probe list",
mid);
sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
- NULL, fname,
- 0, i2caddr);
+ fname, 0, i2caddr);
}
if (!sd) {
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
#include <linux/usb/input.h>
#endif
#include <linux/videodev2.h>
#include <linux/version.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
return ERR_PTR(-ENOMEM);
sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
- MODULE_NAME, isp_info->board_info, NULL);
+ isp_info->board_info, NULL);
if (!sd) {
v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
return NULL;
so we do not need to probe for a radio tuner device. */
if (dev->radio_type != UNSET)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
dev->radio_addr, NULL);
if (has_demod)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == ADDR_UNSET) {
enum v4l2_i2c_tuner_type type =
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(type));
} else {
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
dev->tuner_addr, NULL);
}
}
if (card_is_empress(dev)) {
struct v4l2_subdev *sd =
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "saa6752hs",
+ "saa6752hs",
saa7134_boards[dev->board].empress_addr, NULL);
if (sd)
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "saa6588",
+ &dev->i2c_adap, "saa6588",
0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr));
if (sd) {
printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include "saa7134-reg.h"
#include <media/tveeprom.h>
#include <media/videobuf-dma-sg.h>
#include <media/videobuf-dvb.h>
-#include <linux/smp_lock.h>
#include <dvb_demux.h>
#include <dvb_frontend.h>
#include <dvb_net.h>
goto ereset;
subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
- NULL, vou_pdata->board_info, NULL);
+ vou_pdata->board_info, NULL);
if (!subdev) {
ret = -ENOMEM;
goto ei2cnd;
icl->board_info->platform_data = icd;
subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
- NULL, icl->board_info, NULL);
+ icl->board_info, NULL);
if (!subdev)
goto ei2cnd;
hit-and-miss. */
mdelay(10);
v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, NULL,
+ &usbvision->i2c_adap,
"saa7115_auto", 0, saa711x_addrs);
break;
}
struct tuner_setup tun_setup;
sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, NULL,
+ &usbvision->i2c_adap,
"tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
/* depending on whether we found a demod or not, select
the tuner type. */
type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, NULL,
+ &usbvision->i2c_adap,
"tuner", 0, v4l2_i2c_tuner_addrs(type));
if (sd == NULL)
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/vmalloc.h>
/* Load an i2c sub-device. */
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter, const char *module_name,
- struct i2c_board_info *info, const unsigned short *probe_addrs)
+ struct i2c_adapter *adapter, struct i2c_board_info *info,
+ const unsigned short *probe_addrs)
{
struct v4l2_subdev *sd = NULL;
struct i2c_client *client;
BUG_ON(!v4l2_dev);
- if (module_name)
- request_module(module_name);
- else
- request_module(I2C_MODULE_PREFIX "%s", info->type);
+ request_module(I2C_MODULE_PREFIX "%s", info->type);
/* Create the i2c client */
if (info->addr == 0 && probe_addrs)
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter,
- const char *module_name, const char *client_type,
+ struct i2c_adapter *adapter, const char *client_type,
int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs)
{
info.irq = irq;
info.platform_data = platform_data;
- return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name,
- &info, probe_addrs);
+ return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <media/v4l2-ioctl.h>
#ifdef CONFIG_COMPAT
*/
sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31);
cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter,
- "ov7670", "ov7670", 0x42 >> 1, NULL);
+ "ov7670", 0x42 >> 1, NULL);
if (cam->sensor == NULL) {
dev_err(&pdev->dev, "Unable to find the sensor!\n");
ret = -ENODEV;
vino_drvdata->decoder =
v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
- NULL, "saa7191", 0, I2C_ADDRS(0x45));
+ "saa7191", 0, I2C_ADDRS(0x45));
vino_drvdata->camera =
v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
- NULL, "indycam", 0, I2C_ADDRS(0x2b));
+ "indycam", 0, I2C_ADDRS(0x2b));
dprintk("init complete!\n");
}
zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
- &zr->i2c_adapter, NULL, zr->card.i2c_decoder,
+ &zr->i2c_adapter, zr->card.i2c_decoder,
0, zr->card.addrs_decoder);
if (zr->card.i2c_encoder)
zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
- &zr->i2c_adapter,
- NULL, zr->card.i2c_encoder,
+ &zr->i2c_adapter, zr->card.i2c_encoder,
0, zr->card.addrs_encoder);
dprintk(2,
static int mptfc_target_alloc(struct scsi_target *starget);
static int mptfc_slave_alloc(struct scsi_device *sdev);
-static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
- void (*done)(struct scsi_cmnd *));
+static int mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt);
static void mptfc_target_destroy(struct scsi_target *starget);
static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
static void __devexit mptfc_remove(struct pci_dev *pdev);
}
static int
-mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptfc_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
struct mptfc_rport_info *ri;
struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
return mptscsih_qcmd(SCpnt,done);
}
+static DEF_SCSI_QCMD(mptfc_qcmd)
+
/*
* mptfc_display_port_link_speed - displaying link speed
* @ioc: Pointer to MPT_ADAPTER structure
}
static int
-mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptsas_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
MPT_SCSI_HOST *hd;
MPT_ADAPTER *ioc;
return mptscsih_qcmd(SCpnt,done);
}
+static DEF_SCSI_QCMD(mptsas_qcmd)
+
/**
* mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
* if the device under question is currently in the
}
static int
-mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptspi_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host);
VirtDevice *vdevice = SCpnt->device->hostdata;
return mptscsih_qcmd(SCpnt,done);
}
+static DEF_SCSI_QCMD(mptspi_qcmd)
+
static void mptspi_slave_destroy(struct scsi_device *sdev)
{
struct scsi_target *starget = scsi_target(sdev);
* Locks: takes the controller lock on error path only
*/
-static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
+static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt,
void (*done) (struct scsi_cmnd *))
{
struct i2o_controller *c;
exit:
return rc;
-};
+}
+
+static DEF_SCSI_QCMD(i2o_scsi_queuecommand)
/**
* i2o_scsi_abort - abort a running command
static int isl29020_remove(struct i2c_client *client)
{
- struct als_data *data = i2c_get_clientdata(client);
sysfs_remove_group(&client->dev.kobj, &m_als_gr);
- kfree(data);
return 0;
}
module_init(sensor_isl29020_init);
module_exit(sensor_isl29020_exit);
-MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
+MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com>");
MODULE_DESCRIPTION("Intersil isl29020 ALS Driver");
MODULE_LICENSE("GPL v2");
* nodes that can comprise an access protection grouping. The access
* protection is in regards to memory, IOI and IPI.
*/
- max_regions = 64;
region_size = xp_region_size;
- switch (region_size) {
- case 128:
- max_regions *= 2;
- case 64:
- max_regions *= 2;
- case 32:
- max_regions *= 2;
- region_size = 16;
- DBUG_ON(!is_shub2());
+ if (is_uv())
+ max_regions = 256;
+ else {
+ max_regions = 64;
+
+ switch (region_size) {
+ case 128:
+ max_regions *= 2;
+ case 64:
+ max_regions *= 2;
+ case 32:
+ max_regions *= 2;
+ region_size = 16;
+ DBUG_ON(!is_shub2());
+ }
}
for (region = 0; region < max_regions; region++) {
if (host->caps & MMC_CAP_DISABLE)
cancel_delayed_work(&host->disable);
- cancel_delayed_work(&host->detect);
+ cancel_delayed_work_sync(&host->detect);
mmc_flush_scheduled_work();
/* clear pm flags now and let card drivers set them as needed */
struct mmc_card *oldcard)
{
struct mmc_card *card;
- int err, ddr = MMC_SDR_MODE;
+ int err, ddr = 0;
u32 cid[4];
unsigned int max_dtr;
1 << bus_width, ddr);
err = 0;
} else {
- mmc_card_set_ddr_mode(card);
+ if (ddr)
+ mmc_card_set_ddr_mode(card);
+ else
+ ddr = MMC_SDR_MODE;
+
mmc_set_bus_width_ddr(card->host, bus_width, ddr);
}
}
BUG_ON(!host->card);
/* Make sure card is powered before detecting it */
- err = pm_runtime_get_sync(&host->card->dev);
- if (err < 0)
- goto out;
+ if (host->caps & MMC_CAP_POWER_OFF_CARD) {
+ err = pm_runtime_get_sync(&host->card->dev);
+ if (err < 0)
+ goto out;
+ }
mmc_claim_host(host);
mmc_release_host(host);
+ /*
+ * Tell PM core it's OK to power off the card now.
+ *
+ * The _sync variant is used in order to ensure that the card
+ * is left powered off in case an error occurred, and the card
+ * is going to be removed.
+ *
+ * Since there is no specific reason to believe a new user
+ * is about to show up at this point, the _sync variant is
+ * desirable anyway.
+ */
+ if (host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_put_sync(&host->card->dev);
+
out:
if (err) {
mmc_sdio_remove(host);
mmc_detach_bus(host);
mmc_release_host(host);
}
-
- /* Tell PM core that we're done */
- pm_runtime_put(&host->card->dev);
}
/*
card = host->card;
/*
- * Let runtime PM core know our card is active
+ * Enable runtime PM only if supported by host+card+board
*/
- err = pm_runtime_set_active(&card->dev);
- if (err)
- goto remove;
+ if (host->caps & MMC_CAP_POWER_OFF_CARD) {
+ /*
+ * Let runtime PM core know our card is active
+ */
+ err = pm_runtime_set_active(&card->dev);
+ if (err)
+ goto remove;
- /*
- * Enable runtime PM for this card
- */
- pm_runtime_enable(&card->dev);
+ /*
+ * Enable runtime PM for this card
+ */
+ pm_runtime_enable(&card->dev);
+ }
/*
* The number of functions on the card is encoded inside
goto remove;
/*
- * Enable Runtime PM for this func
+ * Enable Runtime PM for this func (if supported)
*/
- pm_runtime_enable(&card->sdio_func[i]->dev);
+ if (host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_enable(&card->sdio_func[i]->dev);
}
mmc_release_host(host);
#include <linux/pm_runtime.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include "sdio_cis.h"
* it should call pm_runtime_put_noidle() in its probe routine and
* pm_runtime_get_noresume() in its remove routine.
*/
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- goto out;
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ goto out;
+ }
/* Set the default block size so the driver is sure it's something
* sensible. */
return 0;
disable_runtimepm:
- pm_runtime_put_noidle(dev);
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_put_noidle(dev);
out:
return ret;
}
{
struct sdio_driver *drv = to_sdio_driver(dev->driver);
struct sdio_func *func = dev_to_sdio_func(dev);
- int ret;
+ int ret = 0;
/* Make sure card is powered before invoking ->remove() */
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- goto out;
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ goto out;
+ }
drv->remove(func);
}
/* First, undo the increment made directly above */
- pm_runtime_put_noidle(dev);
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_put_noidle(dev);
/* Then undo the runtime PM settings in sdio_bus_probe() */
- pm_runtime_put_noidle(dev);
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_put_noidle(dev);
out:
return ret;
static int sdio_bus_pm_prepare(struct device *dev)
{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+
/*
* Resume an SDIO device which was suspended at run time at this
* point, in order to allow standard SDIO suspend/resume paths
* since there is little point in failing system suspend if a
* device can't be resumed.
*/
- pm_runtime_resume(dev);
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_resume(dev);
return 0;
}
* Monitor a 0->1 transition first
*/
if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) {
- while ((!(OMAP_HSMMC_READ(host, SYSCTL) & bit))
+ while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
&& (i++ < limit))
cpu_relax();
}
#include <linux/clk.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdhci-pltfm.h>
+#include <mach/hardware.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
clk_enable(clk);
pltfm_host->clk = clk;
+ if (cpu_is_mx35() || cpu_is_mx51())
+ host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+
+ /* Fix errata ENGcm07207 which is present on i.MX25 and i.MX35 */
+ if (cpu_is_mx25() || cpu_is_mx35())
+ host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
+
return 0;
}
};
struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
- .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_MULTIBLOCK
- | SDHCI_QUIRK_BROKEN_ADMA,
+ .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA,
/* ADMA has issues. Might be fixable */
- /* NO_MULTIBLOCK might be MX35 only (Errata: ENGcm07207) */
.ops = &sdhci_esdhc_ops,
.init = esdhc_pltfm_init,
.exit = esdhc_pltfm_exit,
* ADMA operation is disabled for Moorestown platform due to
* hardware bugs.
*/
-static int mrst_hc1_probe(struct sdhci_pci_chip *chip)
+static int mrst_hc_probe(struct sdhci_pci_chip *chip)
{
/*
- * slots number is fixed here for MRST as SDIO3 is never used and has
- * hardware bugs.
+ * slots number is fixed here for MRST as SDIO3/5 are never used and
+ * have hardware bugs.
*/
chip->num_slots = 1;
return 0;
.quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
};
-static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1 = {
+static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = {
.quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
- .probe = mrst_hc1_probe,
+ .probe = mrst_hc_probe,
};
static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
.device = PCI_DEVICE_ID_INTEL_MRST_SD1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_MRST_SD2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2,
},
{
{
struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot;
+ mmc_pm_flag_t slot_pm_flags;
mmc_pm_flag_t pm_flags = 0;
int i, ret;
return ret;
}
- pm_flags |= slot->host->mmc->pm_flags;
+ slot_pm_flags = slot->host->mmc->pm_flags;
+ if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ)
+ sdhci_enable_irq_wakeups(slot->host);
+
+ pm_flags |= slot_pm_flags;
}
if (chip->fixes && chip->fixes->suspend) {
pci_save_state(pdev);
if (pm_flags & MMC_PM_KEEP_POWER) {
- if (pm_flags & MMC_PM_WAKE_SDIO_IRQ)
+ if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
+ pci_pme_active(pdev, true);
pci_enable_wake(pdev, PCI_D3hot, 1);
+ }
pci_set_power_state(pdev, PCI_D3hot);
} else {
pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
if (pdata->quirks)
host->quirks |= pdata->quirks;
+ /* If slot design supports 8 bit data, indicate this to MMC. */
+ if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
+ host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "failed to add host\n");
if (host->ops->platform_send_init_74_clocks)
host->ops->platform_send_init_74_clocks(host, ios->power_mode);
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-
- if (ios->bus_width == MMC_BUS_WIDTH_8)
- ctrl |= SDHCI_CTRL_8BITBUS;
- else
- ctrl &= ~SDHCI_CTRL_8BITBUS;
+ /*
+ * If your platform has 8-bit width support but is not a v3 controller,
+ * or if it requires special setup code, you should implement that in
+ * platform_8bit_width().
+ */
+ if (host->ops->platform_8bit_width)
+ host->ops->platform_8bit_width(host, ios->bus_width);
+ else {
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ if (ios->bus_width == MMC_BUS_WIDTH_8) {
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ if (host->version >= SDHCI_SPEC_300)
+ ctrl |= SDHCI_CTRL_8BITBUS;
+ } else {
+ if (host->version >= SDHCI_SPEC_300)
+ ctrl &= ~SDHCI_CTRL_8BITBUS;
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ ctrl |= SDHCI_CTRL_4BITBUS;
+ else
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ }
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ }
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- ctrl |= SDHCI_CTRL_4BITBUS;
- else
- ctrl &= ~SDHCI_CTRL_4BITBUS;
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if ((ios->timing == MMC_TIMING_SD_HS ||
ios->timing == MMC_TIMING_MMC_HS)
EXPORT_SYMBOL_GPL(sdhci_resume_host);
+void sdhci_enable_irq_wakeups(struct sdhci_host *host)
+{
+ u8 val;
+ val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
+ val |= SDHCI_WAKE_ON_INT;
+ sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
+}
+
+EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups);
+
#endif /* CONFIG_PM */
/*****************************************************************************\
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
else
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
+
mmc->f_max = host->max_clk;
mmc->caps |= MMC_CAP_SDIO_IRQ;
+ /*
+ * A controller may support 8-bit width, but the board itself
+ * might not have the pins brought out. Boards that support
+ * 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in
+ * their platform code before calling sdhci_add_host(), and we
+ * won't assume 8-bit width for hosts without that CAP.
+ */
if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
- mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
if (caps & SDHCI_CAN_DO_HISPD)
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
#define SDHCI_CTRL_ADMA1 0x08
#define SDHCI_CTRL_ADMA32 0x10
#define SDHCI_CTRL_ADMA64 0x18
-#define SDHCI_CTRL_8BITBUS 0x20
+#define SDHCI_CTRL_8BITBUS 0x20
#define SDHCI_POWER_CONTROL 0x29
#define SDHCI_POWER_ON 0x01
#define SDHCI_BLOCK_GAP_CONTROL 0x2A
#define SDHCI_WAKE_UP_CONTROL 0x2B
+#define SDHCI_WAKE_ON_INT 0x01
+#define SDHCI_WAKE_ON_INSERT 0x02
+#define SDHCI_WAKE_ON_REMOVE 0x04
#define SDHCI_CLOCK_CONTROL 0x2C
#define SDHCI_DIVIDER_SHIFT 8
#define SDHCI_CLOCK_BASE_SHIFT 8
#define SDHCI_MAX_BLOCK_MASK 0x00030000
#define SDHCI_MAX_BLOCK_SHIFT 16
+#define SDHCI_CAN_DO_8BIT 0x00040000
#define SDHCI_CAN_DO_ADMA2 0x00080000
#define SDHCI_CAN_DO_ADMA1 0x00100000
#define SDHCI_CAN_DO_HISPD 0x00200000
unsigned int (*get_max_clock)(struct sdhci_host *host);
unsigned int (*get_min_clock)(struct sdhci_host *host);
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
+ int (*platform_8bit_width)(struct sdhci_host *host,
+ int width);
void (*platform_send_init_74_clocks)(struct sdhci_host *host,
u8 power_mode);
unsigned int (*get_ro)(struct sdhci_host *host);
#ifdef CONFIG_PM
extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
extern int sdhci_resume_host(struct sdhci_host *host);
+extern void sdhci_enable_irq_wakeups(struct sdhci_host *host);
#endif
#endif /* __SDHCI_HW_H */
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct mmc_host *mmc;
struct ushc_data *ushc;
- int ret = -ENOMEM;
+ int ret;
mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
if (mmc == NULL)
mmc->max_blk_count = 511;
ushc->int_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (ushc->int_urb == NULL)
+ if (ushc->int_urb == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL);
- if (ushc->int_data == NULL)
+ if (ushc->int_data == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
usb_fill_int_urb(ushc->int_urb, ushc->usb_dev,
usb_rcvintpipe(usb_dev,
intf->cur_altsetting->endpoint[0].desc.bEndpointAddress),
intf->cur_altsetting->endpoint[0].desc.bInterval);
ushc->cbw_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (ushc->cbw_urb == NULL)
+ if (ushc->cbw_urb == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
- if (ushc->cbw == NULL)
+ if (ushc->cbw == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
ushc->cbw->signature = USHC_CBW_SIGNATURE;
usb_fill_bulk_urb(ushc->cbw_urb, ushc->usb_dev, usb_sndbulkpipe(usb_dev, 2),
cbw_callback, ushc);
ushc->data_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (ushc->data_urb == NULL)
+ if (ushc->data_urb == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (ushc->csw_urb == NULL)
+ if (ushc->csw_urb == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
- if (ushc->csw == NULL)
+ if (ushc->csw == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
usb_fill_bulk_urb(ushc->csw_urb, ushc->usb_dev, usb_rcvbulkpipe(usb_dev, 6),
ushc->csw, sizeof(struct ushc_csw),
csw_callback, ushc);
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-static int __init pxa2xx_flash_probe(struct platform_device *pdev)
+static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
{
struct flash_platform_data *flash = pdev->dev.platform_data;
struct pxa2xx_flash_info *info;
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#define CONFIG_MTD_NAND_OMAP_HWECC
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
uint32_t data = 0;
struct ubi_vid_hdr vid_hdr;
- addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset;
+ /*
+ * It is important to first invalidate the EC header, and then the VID
+ * header. Otherwise a power cut may lead to valid EC header and
+ * invalid VID header, in which case UBI will treat this PEB as
+ * corrupted and will try to preserve it, and print scary warnings (see
+ * the header comment in scan.c for more information).
+ */
+ addr = (loff_t)pnum * ubi->peb_size;
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
if (!err) {
- addr -= ubi->vid_hdr_aloffset;
+ addr += ubi->vid_hdr_aloffset;
err = ubi->mtd->write(ubi->mtd, addr, 4, &written,
(void *)&data);
if (!err)
/*
* We failed to write to the media. This was observed with Spansion
- * S29GL512N NOR flash. Most probably the eraseblock erasure was
- * interrupted at a very inappropriate moment, so it became unwritable.
- * In this case we probably anyway have garbage in this PEB.
+ * S29GL512N NOR flash. Most probably the previously eraseblock erasure
+ * was interrupted at a very inappropriate moment, so it became
+ * unwritable. In this case we probably anyway have garbage in this
+ * PEB.
*/
err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
- if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR)
- /*
- * The VID header is corrupted, so we can safely erase this
- * PEB and not afraid that it will be treated as a valid PEB in
- * case of an unclean reboot.
- */
- return 0;
+ if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) {
+ struct ubi_ec_hdr ec_hdr;
+
+ err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0);
+ if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR)
+ /*
+ * Both VID and EC headers are corrupted, so we can
+ * safely erase this PEB and not afraid that it will be
+ * treated as a valid PEB in case of an unclean reboot.
+ */
+ return 0;
+ }
/*
* The PEB contains a valid VID header, but we cannot invalidate it.
* erased, so it became unstable and corrupted, and should be
* erased.
*/
- return 0;
+ err = 0;
+ goto out_unlock;
}
if (err)
- return err;
+ goto out_unlock;
- if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size)) {
- mutex_unlock(&ubi->buf_mutex);
- return 0;
- }
+ if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size))
+ goto out_unlock;
ubi_err("PEB %d contains corrupted VID header, and the data does not "
"contain all 0xFF, this may be a non-UBI PEB or a severe VID "
pnum, ubi->leb_start, ubi->leb_size);
ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
ubi->peb_buf1, ubi->leb_size, 1);
+ err = 1;
+
+out_unlock:
mutex_unlock(&ubi->buf_mutex);
- return 1;
+ return err;
}
/**
* impossible to distinguish it from a PEB which just
* contains garbage because of a power cut during erase
* operation. So we just schedule this PEB for erasure.
+ *
+ * Besides, in case of NOR flash, we deliberatly
+ * corrupt both headers because NOR flash erasure is
+ * slow and can start from the end.
*/
err = 0;
else
#define DEVICE_PCI(dev) NULL
#endif
-#define VORTEX_PCI(vp) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL)
+#define VORTEX_PCI(vp) \
+ ((struct pci_dev *) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL))
#ifdef CONFIG_EISA
#define DEVICE_EISA(dev) (((dev)->bus == &eisa_bus_type) ? to_eisa_device((dev)) : NULL)
#define DEVICE_EISA(dev) NULL
#endif
-#define VORTEX_EISA(vp) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL)
+#define VORTEX_EISA(vp) \
+ ((struct eisa_device *) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL))
/* The action to take with a media selection timer tick.
Note that we deviate from the 3Com order by checking 10base2 before AUI.
{
unsigned int protocol = (status >> 16) & 0x3;
- if (likely((protocol == RxProtoTCP) && (!(status & TCPFail))))
+ if (((protocol == RxProtoTCP) && !(status & TCPFail)) ||
+ ((protocol == RxProtoUDP) && !(status & UDPFail)))
return 1;
- else if ((protocol == RxProtoUDP) && (!(status & UDPFail)))
- return 1;
- else if ((protocol == RxProtoIP) && (!(status & IPFail)))
- return 1;
- return 0;
+ else
+ return 0;
}
static int cp_rx_poll(struct napi_struct *napi, int budget)
depends on PCI
select MII
---help---
- This is a gigabit ethernet driver for Topcliff PCH.
- Topcliff PCH is the platform controller hub that is used in Intel's
+ This is a gigabit ethernet driver for EG20T PCH.
+ EG20T PCH is the platform controller hub that is used in Intel's
general embedded platform.
- Topcliff PCH has Gigabit Ethernet interface.
+ EG20T PCH has Gigabit Ethernet interface.
Using this interface, it is able to access system devices connected
to Gigabit Ethernet.
This driver enables Gigabit Ethernet function.
source "drivers/net/caif/Kconfig"
+config TILE_NET
+ tristate "Tilera GBE/XGBE network driver support"
+ depends on TILE
+ default y
+ select CRC32
+ help
+ This is a standard Linux network device driver for the
+ on-chip Tilera Gigabit Ethernet and XAUI interfaces.
+
+ To compile this driver as a module, choose M here: the module
+ will be called tile_net.
+
config XEN_NETDEV_FRONTEND
tristate "Xen network device frontend driver"
depends on XEN
obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
obj-$(CONFIG_PCH_GBE) += pch_gbe/
+obj-$(CONFIG_TILE_NET) += tile/
addr[0] = addr[1] = 0;
AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
if (atl1c_check_eeprom_exist(hw)) {
- if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) {
+ if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) {
/* Enable OTP CLK */
if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
otp_ctrl_data |= OTP_CTRL_CLK_EN;
spin_lock_irqsave(&aup->lock, flags);
if (force_reset || (!aup->mac_enabled)) {
- writel(MAC_EN_CLOCK_ENABLE, &aup->enable);
+ writel(MAC_EN_CLOCK_ENABLE, aup->enable);
au_sync_delay(2);
writel((MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2
- | MAC_EN_CLOCK_ENABLE), &aup->enable);
+ | MAC_EN_CLOCK_ENABLE), aup->enable);
au_sync_delay(2);
aup->mac_enabled = 1;
au1000_hard_stop(dev);
- writel(MAC_EN_CLOCK_ENABLE, &aup->enable);
+ writel(MAC_EN_CLOCK_ENABLE, aup->enable);
au_sync_delay(2);
- writel(0, &aup->enable);
+ writel(0, aup->enable);
au_sync_delay(2);
aup->tx_full = 0;
/* set a random MAC now in case platform_data doesn't provide one */
random_ether_addr(dev->dev_addr);
- writel(0, &aup->enable);
+ writel(0, aup->enable);
aup->mac_enabled = 0;
pd = pdev->dev.platform_data;
__b44_set_flow_ctrl(bp, pause_enab);
}
-#ifdef SSB_DRIVER_MIPS
-extern char *nvram_get(char *name);
+#ifdef CONFIG_BCM47XX
+#include <asm/mach-bcm47xx/nvram.h>
static void b44_wap54g10_workaround(struct b44 *bp)
{
- const char *str;
+ char buf[20];
u32 val;
int err;
* see https://dev.openwrt.org/ticket/146
* check and reset bit "isolate"
*/
- str = nvram_get("boardnum");
- if (!str)
+ if (nvram_getenv("boardnum", buf, sizeof(buf)) < 0)
return;
- if (simple_strtoul(str, NULL, 0) == 2) {
+ if (simple_strtoul(buf, NULL, 0) == 2) {
err = __b44_readphy(bp, 0, MII_BMCR, &val);
if (err)
goto error;
i = 0;
netdev_for_each_mc_addr(ha, netdev)
- memcpy(req->mac[i].byte, ha->addr, ETH_ALEN);
+ memcpy(req->mac[i++].byte, ha->addr, ETH_ALEN);
} else {
req->promiscuous = 1;
}
int status, i = 0, num_imgs = 0;
const u8 *p;
+ if (!netif_running(adapter->netdev)) {
+ dev_err(&adapter->pdev->dev,
+ "Firmware load not allowed (interface is down)\n");
+ return -EPERM;
+ }
+
strcpy(fw_file, func);
status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
* (you will need to reboot afterwards) */
/* #define BNX2X_STOP_ON_ERROR */
-#define DRV_MODULE_VERSION "1.60.00-4"
-#define DRV_MODULE_RELDATE "2010/11/01"
+#define DRV_MODULE_VERSION "1.60.01-0"
+#define DRV_MODULE_RELDATE "2010/11/12"
#define BNX2X_BC_VER 0x040200
#define BNX2X_MULTI_QUEUE
}
#endif
-static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb,
- struct eth_tx_parse_bd_e2 *pbd,
- u32 xmit_type)
+static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
+ u32 xmit_type)
{
- pbd->parsing_data |= cpu_to_le16(skb_shinfo(skb)->gso_size) <<
- ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT;
+ *parsing_data |= (skb_shinfo(skb)->gso_size <<
+ ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
+ ETH_TX_PARSE_BD_E2_LSO_MSS;
if ((xmit_type & XMIT_GSO_V6) &&
(ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6))
- pbd->parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
+ *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
}
/**
* @return header len
*/
static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
- struct eth_tx_parse_bd_e2 *pbd,
- u32 xmit_type)
+ u32 *parsing_data, u32 xmit_type)
{
- pbd->parsing_data |= cpu_to_le16(tcp_hdrlen(skb)/4) <<
- ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT;
+ *parsing_data |= ((tcp_hdrlen(skb)/4) <<
+ ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
+ ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
- pbd->parsing_data |= cpu_to_le16(((unsigned char *)tcp_hdr(skb) -
- skb->data) / 2) <<
- ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT;
+ *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) <<
+ ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
+ ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
}
struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
struct eth_tx_parse_bd_e1x *pbd_e1x = NULL;
struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
+ u32 pbd_e2_parsing_data = 0;
u16 pkt_prod, bd_prod;
int nbd, fp_index;
dma_addr_t mapping;
memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2));
/* Set PBD in checksum offload case */
if (xmit_type & XMIT_CSUM)
- hlen = bnx2x_set_pbd_csum_e2(bp,
- skb, pbd_e2, xmit_type);
+ hlen = bnx2x_set_pbd_csum_e2(bp, skb,
+ &pbd_e2_parsing_data,
+ xmit_type);
} else {
pbd_e1x = &fp->tx_desc_ring[bd_prod].parse_bd_e1x;
memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x));
bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
hlen, bd_prod, ++nbd);
if (CHIP_IS_E2(bp))
- bnx2x_set_pbd_gso_e2(skb, pbd_e2, xmit_type);
+ bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data,
+ xmit_type);
else
bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
}
+
+ /* Set the PBD's parsing_data field if not zero
+ * (for the chips newer than 57711).
+ */
+ if (pbd_e2_parsing_data)
+ pbd_e2->parsing_data = cpu_to_le32(pbd_e2_parsing_data);
+
tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
/* Handle fragmented skb */
/****************************************************************************
* SRC initializations
****************************************************************************/
-
+#ifdef BCM_CNIC
/* called during init func stage */
static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2,
dma_addr_t t2_mapping, int src_cid_count)
U64_HI((u64)t2_mapping +
(src_cid_count-1) * sizeof(struct src_ent)));
}
-
+#endif
#endif /* BNX2X_INIT_OPS_H */
default:
pr_err("Unknown board_type (%ld), aborting\n",
ent->driver_data);
- return ENODEV;
+ return -ENODEV;
}
cid_count += CNIC_CONTEXT_USE;
/*----------------------------- Global variables ----------------------------*/
#ifdef CONFIG_NET_POLL_CONTROLLER
-cpumask_var_t netpoll_block_tx;
+atomic_t netpoll_block_tx = ATOMIC_INIT(0);
#endif
static const char * const version =
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (in_dev) {
+ read_lock(&in_dev->mc_list_lock);
for (im = in_dev->mc_list; im; im = im->next)
ip_mc_rejoin_group(im);
+ read_unlock(&in_dev->mc_list_lock);
}
rcu_read_unlock();
/* If this is the first slave, then we need to set the master's hardware
* address to be the same as the slave's. */
- if (bond->slave_cnt == 0)
+ if (is_zero_ether_addr(bond->dev->dev_addr))
memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
slave_dev->addr_len);
if (res)
goto out;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- if (!alloc_cpumask_var(&netpoll_block_tx, GFP_KERNEL)) {
- res = -ENOMEM;
- goto out;
- }
-#endif
-
res = register_pernet_subsys(&bond_net_ops);
if (res)
goto out;
rtnl_link_unregister(&bond_link_ops);
err_link:
unregister_pernet_subsys(&bond_net_ops);
-#ifdef CONFIG_NET_POLL_CONTROLLER
- free_cpumask_var(netpoll_block_tx);
-#endif
goto out;
}
unregister_pernet_subsys(&bond_net_ops);
#ifdef CONFIG_NET_POLL_CONTROLLER
- free_cpumask_var(netpoll_block_tx);
+ /*
+ * Make sure we don't have an imbalance on our netpoll blocking
+ */
+ WARN_ON(atomic_read(&netpoll_block_tx));
#endif
}
#ifdef CONFIG_NET_POLL_CONTROLLER
-extern cpumask_var_t netpoll_block_tx;
+extern atomic_t netpoll_block_tx;
static inline void block_netpoll_tx(void)
{
- preempt_disable();
- BUG_ON(cpumask_test_and_set_cpu(smp_processor_id(),
- netpoll_block_tx));
+ atomic_inc(&netpoll_block_tx);
}
static inline void unblock_netpoll_tx(void)
{
- BUG_ON(!cpumask_test_and_clear_cpu(smp_processor_id(),
- netpoll_block_tx));
- preempt_enable();
+ atomic_dec(&netpoll_block_tx);
}
static inline int is_netpoll_tx_blocked(struct net_device *dev)
{
if (unlikely(dev->priv_flags & IFF_IN_NETPOLL))
- return cpumask_test_cpu(smp_processor_id(), netpoll_block_tx);
+ return atomic_read(&netpoll_block_tx);
return 0;
}
#else
* License terms: GNU General Public License (GPL) version 2
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ":" __func__ "():" fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
#include <linux/version.h>
#include <linux/init.h>
* License terms: GNU General Public License (GPL) version 2
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ":" __func__ "():" fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
#include <linux/spinlock.h>
#include <linux/sched.h>
ndev = alloc_netdev(sizeof(struct cfspi),
"cfspi%d", cfspi_setup);
- if (!dev)
- return -ENODEV;
+ if (!ndev)
+ return -ENOMEM;
cfspi = netdev_priv(ndev);
netif_stop_queue(ndev);
if (index < NEXACT_MAC)
ret++;
else if (hash)
- *hash |= (1 << hash_mac_addr(addr[i]));
+ *hash |= (1ULL << hash_mac_addr(addr[i]));
}
return ret;
}
}
/*
- * Collect up to maxaddrs worth of a netdevice's unicast addresses into an
- * array of addrss pointers and return the number collected.
+ * Collect up to maxaddrs worth of a netdevice's unicast addresses, starting
+ * at a specified offset within the list, into an array of addrss pointers and
+ * return the number collected.
*/
-static inline int collect_netdev_uc_list_addrs(const struct net_device *dev,
- const u8 **addr,
- unsigned int maxaddrs)
+static inline unsigned int collect_netdev_uc_list_addrs(const struct net_device *dev,
+ const u8 **addr,
+ unsigned int offset,
+ unsigned int maxaddrs)
{
+ unsigned int index = 0;
unsigned int naddr = 0;
const struct netdev_hw_addr *ha;
- for_each_dev_addr(dev, ha) {
- addr[naddr++] = ha->addr;
- if (naddr >= maxaddrs)
- break;
- }
+ for_each_dev_addr(dev, ha)
+ if (index++ >= offset) {
+ addr[naddr++] = ha->addr;
+ if (naddr >= maxaddrs)
+ break;
+ }
return naddr;
}
/*
- * Collect up to maxaddrs worth of a netdevice's multicast addresses into an
- * array of addrss pointers and return the number collected.
+ * Collect up to maxaddrs worth of a netdevice's multicast addresses, starting
+ * at a specified offset within the list, into an array of addrss pointers and
+ * return the number collected.
*/
-static inline int collect_netdev_mc_list_addrs(const struct net_device *dev,
- const u8 **addr,
- unsigned int maxaddrs)
+static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device *dev,
+ const u8 **addr,
+ unsigned int offset,
+ unsigned int maxaddrs)
{
+ unsigned int index = 0;
unsigned int naddr = 0;
const struct netdev_hw_addr *ha;
- netdev_for_each_mc_addr(ha, dev) {
- addr[naddr++] = ha->addr;
- if (naddr >= maxaddrs)
- break;
- }
+ netdev_for_each_mc_addr(ha, dev)
+ if (index++ >= offset) {
+ addr[naddr++] = ha->addr;
+ if (naddr >= maxaddrs)
+ break;
+ }
return naddr;
}
u64 mhash = 0;
u64 uhash = 0;
bool free = true;
- u16 filt_idx[7];
+ unsigned int offset, naddr;
const u8 *addr[7];
- int ret, naddr = 0;
+ int ret;
const struct port_info *pi = netdev_priv(dev);
/* first do the secondary unicast addresses */
- naddr = collect_netdev_uc_list_addrs(dev, addr, ARRAY_SIZE(addr));
- if (naddr > 0) {
+ for (offset = 0; ; offset += naddr) {
+ naddr = collect_netdev_uc_list_addrs(dev, addr, offset,
+ ARRAY_SIZE(addr));
+ if (naddr == 0)
+ break;
+
ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
- naddr, addr, filt_idx, &uhash, sleep);
+ naddr, addr, NULL, &uhash, sleep);
if (ret < 0)
return ret;
}
/* next set up the multicast addresses */
- naddr = collect_netdev_mc_list_addrs(dev, addr, ARRAY_SIZE(addr));
- if (naddr > 0) {
+ for (offset = 0; ; offset += naddr) {
+ naddr = collect_netdev_mc_list_addrs(dev, addr, offset,
+ ARRAY_SIZE(addr));
+ if (naddr == 0)
+ break;
+
ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
- naddr, addr, filt_idx, &mhash, sleep);
+ naddr, addr, NULL, &mhash, sleep);
if (ret < 0)
return ret;
+ free = false;
}
return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0,
{
struct sge *s = &adapter->sge;
int q10g, n10g, qidx, pidx, qs;
+ size_t iqe_size;
/*
* We should not be called till we know how many Queue Sets we can
}
s->ethqsets = qidx;
+ /*
+ * The Ingress Queue Entry Size for our various Response Queues needs
+ * to be big enough to accommodate the largest message we can receive
+ * from the chip/firmware; which is 64 bytes ...
+ */
+ iqe_size = 64;
+
/*
* Set up default Queue Set parameters ... Start off with the
* shortest interrupt holdoff timer.
struct sge_eth_rxq *rxq = &s->ethrxq[qs];
struct sge_eth_txq *txq = &s->ethtxq[qs];
- init_rspq(&rxq->rspq, 0, 0, 1024, L1_CACHE_BYTES);
+ init_rspq(&rxq->rspq, 0, 0, 1024, iqe_size);
rxq->fl.size = 72;
txq->q.size = 1024;
}
* The firmware event queue is used for link state changes and
* notifications of TX DMA completions.
*/
- init_rspq(&s->fw_evtq, SGE_TIMER_RSTRT_CNTR, 0, 512,
- L1_CACHE_BYTES);
+ init_rspq(&s->fw_evtq, SGE_TIMER_RSTRT_CNTR, 0, 512, iqe_size);
/*
* The forwarded interrupt queue is used when we're in MSI interrupt
* any time ...
*/
init_rspq(&s->intrq, SGE_TIMER_RSTRT_CNTR, 0, MSIX_ENTRIES + 1,
- L1_CACHE_BYTES);
+ iqe_size);
}
/*
unsigned int naddr, const u8 **addr, u16 *idx,
u64 *hash, bool sleep_ok)
{
- int i, ret;
+ int offset, ret = 0;
+ unsigned nfilters = 0;
+ unsigned int rem = naddr;
struct fw_vi_mac_cmd cmd, rpl;
- struct fw_vi_mac_exact *p;
- size_t len16;
- if (naddr > ARRAY_SIZE(cmd.u.exact))
+ if (naddr > FW_CLS_TCAM_NUM_ENTRIES)
return -EINVAL;
- len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
- u.exact[naddr]), 16);
- memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
- (free ? FW_CMD_EXEC : 0) |
- FW_VI_MAC_CMD_VIID(viid));
- cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
- FW_CMD_LEN16(len16));
+ for (offset = 0; offset < naddr; /**/) {
+ unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact)
+ ? rem
+ : ARRAY_SIZE(cmd.u.exact));
+ size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+ u.exact[fw_naddr]), 16);
+ struct fw_vi_mac_exact *p;
+ int i;
- for (i = 0, p = cmd.u.exact; i < naddr; i++, p++) {
- p->valid_to_idx =
- cpu_to_be16(FW_VI_MAC_CMD_VALID |
- FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
- memcpy(p->macaddr, addr[i], sizeof(p->macaddr));
- }
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ (free ? FW_CMD_EXEC : 0) |
+ FW_VI_MAC_CMD_VIID(viid));
+ cmd.freemacs_to_len16 =
+ cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
+ FW_CMD_LEN16(len16));
+
+ for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) {
+ p->valid_to_idx = cpu_to_be16(
+ FW_VI_MAC_CMD_VALID |
+ FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
+ memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
+ }
+
+
+ ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl,
+ sleep_ok);
+ if (ret && ret != -ENOMEM)
+ break;
- ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, sleep_ok);
- if (ret)
- return ret;
-
- for (i = 0, p = rpl.u.exact; i < naddr; i++, p++) {
- u16 index = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx));
-
- if (idx)
- idx[i] = (index >= FW_CLS_TCAM_NUM_ENTRIES
- ? 0xffff
- : index);
- if (index < FW_CLS_TCAM_NUM_ENTRIES)
- ret++;
- else if (hash)
- *hash |= (1 << hash_mac_addr(addr[i]));
+ for (i = 0, p = rpl.u.exact; i < fw_naddr; i++, p++) {
+ u16 index = FW_VI_MAC_CMD_IDX_GET(
+ be16_to_cpu(p->valid_to_idx));
+
+ if (idx)
+ idx[offset+i] =
+ (index >= FW_CLS_TCAM_NUM_ENTRIES
+ ? 0xffff
+ : index);
+ if (index < FW_CLS_TCAM_NUM_ENTRIES)
+ nfilters++;
+ else if (hash)
+ *hash |= (1ULL << hash_mac_addr(addr[offset+i]));
+ }
+
+ free = false;
+ offset += fw_naddr;
+ rem -= fw_naddr;
}
+
+ /*
+ * If there were no errors or we merely ran out of room in our MAC
+ * address arena, return the number of filters actually written.
+ */
+ if (ret == 0 || ret == -ENOMEM)
+ ret = nfilters;
return ret;
}
char e1000_driver_name[] = "e1000";
static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-#define DRV_VERSION "7.3.21-k6-NAPI"
+#define DRV_VERSION "7.3.21-k8-NAPI"
const char e1000_driver_version[] = DRV_VERSION;
static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
struct net_device *netdev = adapter->netdev;
u32 rctl, tctl;
- /* signal that we're down so the interrupt handler does not
- * reschedule our watchdog timer */
- set_bit(__E1000_DOWN, &adapter->flags);
/* disable receives in the hardware */
rctl = er32(RCTL);
e1000_irq_disable(adapter);
+ /*
+ * Setting DOWN must be after irq_disable to prevent
+ * a screaming interrupt. Setting DOWN also prevents
+ * timers and tasks from rescheduling.
+ */
+ set_bit(__E1000_DOWN, &adapter->flags);
+
del_timer_sync(&adapter->tx_fifo_stall_timer);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
}
+static int ehea_set_flags(struct net_device *dev, u32 data)
+{
+ return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO
+ | ETH_FLAG_TXVLAN
+ | ETH_FLAG_RXVLAN);
+}
+
const struct ethtool_ops ehea_ethtool_ops = {
.get_settings = ehea_get_settings,
.get_drvinfo = ehea_get_drvinfo,
.get_ethtool_stats = ehea_get_ethtool_stats,
.get_rx_csum = ehea_get_rx_csum,
.set_settings = ehea_set_settings,
+ .get_flags = ethtool_op_get_flags,
+ .set_flags = ehea_set_flags,
.nway_reset = ehea_nway_reset, /* Restart autonegotiation */
};
skb_arr_rq1[index] = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
if (!skb_arr_rq1[index]) {
+ ehea_info("Unable to allocate enough skb in the array\n");
pr->rq1_skba.os_skbs = fill_wqes - i;
break;
}
struct net_device *dev = pr->port->netdev;
int i;
- for (i = 0; i < pr->rq1_skba.len; i++) {
+ if (nr_rq1a > pr->rq1_skba.len) {
+ ehea_error("NR_RQ1A bigger than skb array len\n");
+ return;
+ }
+
+ for (i = 0; i < nr_rq1a; i++) {
skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE);
- if (!skb_arr_rq1[i])
+ if (!skb_arr_rq1[i]) {
+ ehea_info("No enough memory to allocate skb array\n");
break;
+ }
}
/* Ring doorbell */
- ehea_update_rq1a(pr->qp, nr_rq1a);
+ ehea_update_rq1a(pr->qp, i);
}
static int ehea_refill_rq_def(struct ehea_port_res *pr,
int vlan_extracted = ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) &&
pr->port->vgrp);
- if (use_lro) {
+ if (skb->dev->features & NETIF_F_LRO) {
if (vlan_extracted)
lro_vlan_hwaccel_receive_skb(&pr->lro_mgr, skb,
pr->port->vgrp,
skb = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
- if (!skb)
+ if (!skb) {
+ ehea_info("Not enough memory to allocate skb\n");
break;
+ }
}
skb_copy_to_linear_data(skb, ((char *)cqe) + 64,
cqe->num_bytes_transfered - 4);
}
cqe = ehea_poll_rq1(qp, &wqe_index);
}
- if (use_lro)
+ if (dev->features & NETIF_F_LRO)
lro_flush_all(&pr->lro_mgr);
pr->rx_packets += processed;
| NETIF_F_LLTX;
dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
+ if (use_lro)
+ dev->features |= NETIF_F_LRO;
+
INIT_WORK(&port->reset_task, ehea_reset_port);
ret = register_netdev(dev);
case VNIC_DEV_INTR_MODE_MSIX:
for (i = 0; i < enic->rq_count; i++) {
intr = enic_msix_rq_intr(enic, i);
- enic_isr_msix_rq(enic->msix_entry[intr].vector, enic);
+ enic_isr_msix_rq(enic->msix_entry[intr].vector,
+ &enic->napi[i]);
}
intr = enic_msix_wq_intr(enic, i);
enic_isr_msix_wq(enic->msix_entry[intr].vector, enic);
irq_of_parse_and_map(np, 1);
priv->gfargrp[priv->num_grps].interruptError =
irq_of_parse_and_map(np,2);
- if (priv->gfargrp[priv->num_grps].interruptTransmit < 0 ||
- priv->gfargrp[priv->num_grps].interruptReceive < 0 ||
- priv->gfargrp[priv->num_grps].interruptError < 0) {
+ if (priv->gfargrp[priv->num_grps].interruptTransmit == NO_IRQ ||
+ priv->gfargrp[priv->num_grps].interruptReceive == NO_IRQ ||
+ priv->gfargrp[priv->num_grps].interruptError == NO_IRQ)
return -EINVAL;
- }
}
priv->gfargrp[priv->num_grps].grp_id = priv->num_grps;
rcu_read_unlock();
dev_kfree_skb(skb);
stats->tx_dropped++;
+ if (skb_queue_len(&dp->tq) != 0)
+ goto resched;
break;
}
rcu_read_unlock();
"IC PLUS IP1000 1000/100/10 based NIC",
"Sundance Technology ST2021 based NIC",
"Tamarack Microelectronics TC9020/9021 based NIC",
- "Tamarack Microelectronics TC9020/9021 based NIC",
"D-Link NIC IP1000A"
};
static DEFINE_PCI_DEVICE_TABLE(ipg_pci_tbl) = {
{ PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
{ PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
- { PCI_VDEVICE(SUNDANCE, 0x1021), 2 },
- { PCI_VDEVICE(DLINK, 0x9021), 3 },
- { PCI_VDEVICE(DLINK, 0x4020), 4 },
+ { PCI_VDEVICE(DLINK, 0x9021), 2 },
+ { PCI_VDEVICE(DLINK, 0x4020), 3 },
{ 0, }
};
/* Baud Rate Error Correction x 10000 */
u32 rate_err_array[] = {
- 0000, 0625, 1250, 1875,
+ 0, 625, 1250, 1875,
2500, 3125, 3750, 4375,
5000, 5625, 6250, 6875,
7500, 8125, 8750, 9375,
adapter->rx_ring[i] = NULL;
}
+ adapter->num_tx_queues = 0;
+ adapter->num_rx_queues = 0;
+
ixgbe_free_q_vectors(adapter);
ixgbe_reset_interrupt_capability(adapter);
}
MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET);
dev_cap->bf_reg_size = 1 << (field & 0x1f);
MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET);
+ if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size)) {
+ mlx4_warn(dev, "firmware bug: log2 # of blue flame regs is invalid (%d), forcing 3\n", field & 0x1f);
+ field = 3;
+ }
dev_cap->bf_regs_per_page = 1 << (field & 0x3f);
mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n",
dev_cap->bf_reg_size, dev_cap->bf_regs_per_page);
/*
* Copyright (C) 1999 - 2010 Intel Corporation.
- * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
*
* This code was derived from the Intel e1000e Linux driver.
*
module_init(pch_gbe_init_module);
module_exit(pch_gbe_exit_module);
-MODULE_DESCRIPTION("OKI semiconductor PCH Gigabit ethernet Driver");
-MODULE_AUTHOR("OKI semiconductor, <masa-korg@dsn.okisemi.com>");
+MODULE_DESCRIPTION("EG20T PCH Gigabit ethernet Driver");
+MODULE_AUTHOR("OKI SEMICONDUCTOR, <toshiharu-linux@dsn.okisemi.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
MODULE_DEVICE_TABLE(pci, pch_gbe_pcidev_id);
.err = "using default of "
__MODULE_STRING(PCH_GBE_DEFAULT_TXD),
.def = PCH_GBE_DEFAULT_TXD,
- .arg = { .r = { .min = PCH_GBE_MIN_TXD } },
- .arg = { .r = { .max = PCH_GBE_MAX_TXD } }
+ .arg = { .r = { .min = PCH_GBE_MIN_TXD,
+ .max = PCH_GBE_MAX_TXD } }
};
struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring;
tx_ring->count = TxDescriptors;
.err = "using default of "
__MODULE_STRING(PCH_GBE_DEFAULT_RXD),
.def = PCH_GBE_DEFAULT_RXD,
- .arg = { .r = { .min = PCH_GBE_MIN_RXD } },
- .arg = { .r = { .max = PCH_GBE_MAX_RXD } }
+ .arg = { .r = { .min = PCH_GBE_MIN_RXD,
+ .max = PCH_GBE_MAX_RXD } }
};
struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
rx_ring->count = RxDescriptors;
config ICPLUS_PHY
tristate "Drivers for ICPlus PHYs"
---help---
- Currently supports the IP175C PHY.
+ Currently supports the IP175C and IP1001 PHYs.
config REALTEK_PHY
tristate "Drivers for Realtek PHYs"
#include <asm/irq.h>
#include <asm/uaccess.h>
-MODULE_DESCRIPTION("ICPlus IP175C PHY driver");
+MODULE_DESCRIPTION("ICPlus IP175C/IC1001 PHY drivers");
MODULE_AUTHOR("Michael Barkowski");
MODULE_LICENSE("GPL");
return 0;
}
+static int ip1001_config_init(struct phy_device *phydev)
+{
+ int err, value;
+
+ /* Software Reset PHY */
+ value = phy_read(phydev, MII_BMCR);
+ value |= BMCR_RESET;
+ err = phy_write(phydev, MII_BMCR, value);
+ if (err < 0)
+ return err;
+
+ do {
+ value = phy_read(phydev, MII_BMCR);
+ } while (value & BMCR_RESET);
+
+ /* Additional delay (2ns) used to adjust RX clock phase
+ * at GMII/ RGMII interface */
+ value = phy_read(phydev, 16);
+ value |= 0x3;
+
+ err = phy_write(phydev, 16, value);
+ if (err < 0)
+ return err;
+
+ return err;
+}
+
static int ip175c_read_status(struct phy_device *phydev)
{
if (phydev->addr == 4) /* WAN port */
.driver = { .owner = THIS_MODULE,},
};
-static int __init ip175c_init(void)
+static struct phy_driver ip1001_driver = {
+ .phy_id = 0x02430d90,
+ .name = "ICPlus IP1001",
+ .phy_id_mask = 0x0ffffff0,
+ .features = PHY_GBIT_FEATURES | SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause,
+ .config_init = &ip1001_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+static int __init icplus_init(void)
{
+ int ret = 0;
+
+ ret = phy_driver_register(&ip1001_driver);
+ if (ret < 0)
+ return -ENODEV;
+
return phy_driver_register(&ip175c_driver);
}
-static void __exit ip175c_exit(void)
+static void __exit icplus_exit(void)
{
+ phy_driver_unregister(&ip1001_driver);
phy_driver_unregister(&ip175c_driver);
}
-module_init(ip175c_init);
-module_exit(ip175c_exit);
+module_init(icplus_init);
+module_exit(icplus_exit);
static struct mdio_device_id __maybe_unused icplus_tbl[] = {
{ 0x02430d80, 0x0ffffff0 },
+ { 0x02430d90, 0x0ffffff0 },
{ }
};
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/marvell_phy.h>
+#include <linux/of.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
+#define MII_MARVELL_PHY_PAGE 22
+
#define MII_M1011_IEVENT 0x13
#define MII_M1011_IEVENT_CLEAR 0x0000
#define MII_88E1121_PHY_LED_CTRL 16
#define MII_88E1121_PHY_LED_PAGE 3
#define MII_88E1121_PHY_LED_DEF 0x0030
-#define MII_88E1121_PHY_PAGE 22
#define MII_M1011_PHY_STATUS 0x11
#define MII_M1011_PHY_STATUS_1000 0x8000
return 0;
}
+#ifdef CONFIG_OF_MDIO
+/*
+ * Set and/or override some configuration registers based on the
+ * marvell,reg-init property stored in the of_node for the phydev.
+ *
+ * marvell,reg-init = <reg-page reg mask value>,...;
+ *
+ * There may be one or more sets of <reg-page reg mask value>:
+ *
+ * reg-page: which register bank to use.
+ * reg: the register.
+ * mask: if non-zero, ANDed with existing register value.
+ * value: ORed with the masked value and written to the regiser.
+ *
+ */
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+ const __be32 *paddr;
+ int len, i, saved_page, current_page, page_changed, ret;
+
+ if (!phydev->dev.of_node)
+ return 0;
+
+ paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len);
+ if (!paddr || len < (4 * sizeof(*paddr)))
+ return 0;
+
+ saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
+ if (saved_page < 0)
+ return saved_page;
+ page_changed = 0;
+ current_page = saved_page;
+
+ ret = 0;
+ len /= sizeof(*paddr);
+ for (i = 0; i < len - 3; i += 4) {
+ u16 reg_page = be32_to_cpup(paddr + i);
+ u16 reg = be32_to_cpup(paddr + i + 1);
+ u16 mask = be32_to_cpup(paddr + i + 2);
+ u16 val_bits = be32_to_cpup(paddr + i + 3);
+ int val;
+
+ if (reg_page != current_page) {
+ current_page = reg_page;
+ page_changed = 1;
+ ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
+ if (ret < 0)
+ goto err;
+ }
+
+ val = 0;
+ if (mask) {
+ val = phy_read(phydev, reg);
+ if (val < 0) {
+ ret = val;
+ goto err;
+ }
+ val &= mask;
+ }
+ val |= val_bits;
+
+ ret = phy_write(phydev, reg, val);
+ if (ret < 0)
+ goto err;
+
+ }
+err:
+ if (page_changed) {
+ i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
+ if (ret == 0)
+ ret = i;
+ }
+ return ret;
+}
+#else
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+ return 0;
+}
+#endif /* CONFIG_OF_MDIO */
+
static int m88e1121_config_aneg(struct phy_device *phydev)
{
int err, oldpage, mscr;
- oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+ oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
- err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
MII_88E1121_PHY_MSCR_PAGE);
if (err < 0)
return err;
return err;
}
- phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+ phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
if (err < 0)
if (err < 0)
return err;
- oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+ oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
- phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
+ phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
- phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+ phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
err = genphy_config_aneg(phydev);
{
int err, oldpage, mscr;
- oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+ oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
- err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
MII_88E1121_PHY_MSCR_PAGE);
if (err < 0)
return err;
if (err < 0)
return err;
- err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
if (err < 0)
return err;
return err;
}
+ err = marvell_of_reg_init(phydev);
+ if (err < 0)
+ return err;
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
if (err < 0)
int err;
/* Change address */
- err = phy_write(phydev, 0x16, 0x0002);
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
if (err < 0)
return err;
return err;
/* Change address */
- err = phy_write(phydev, 0x16, 0x0003);
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003);
if (err < 0)
return err;
if (err < 0)
return err;
+ err = marvell_of_reg_init(phydev);
+ if (err < 0)
+ return err;
+
/* Reset address */
- err = phy_write(phydev, 0x16, 0x0);
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int m88e1149_config_init(struct phy_device *phydev)
+{
+ int err;
+
+ /* Change address */
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
+ if (err < 0)
+ return err;
+
+ /* Enable 1000 Mbit */
+ err = phy_write(phydev, 0x15, 0x1048);
+ if (err < 0)
+ return err;
+
+ err = marvell_of_reg_init(phydev);
+ if (err < 0)
+ return err;
+
+ /* Reset address */
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
if (err < 0)
return err;
}
}
+ err = marvell_of_reg_init(phydev);
+ if (err < 0)
+ return err;
+
return 0;
}
.config_intr = &marvell_config_intr,
.driver = { .owner = THIS_MODULE },
},
+ {
+ .phy_id = MARVELL_PHY_ID_88E1149R,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "Marvell 88E1149R",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &m88e1149_config_init,
+ .config_aneg = &m88e1118_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .driver = { .owner = THIS_MODULE },
+ },
{
.phy_id = MARVELL_PHY_ID_88E1240,
.phy_id_mask = MARVELL_PHY_ID_MASK,
{ 0x01410e10, 0xfffffff0 },
{ 0x01410cb0, 0xfffffff0 },
{ 0x01410cd0, 0xfffffff0 },
+ { 0x01410e50, 0xfffffff0 },
{ 0x01410e30, 0xfffffff0 },
{ 0x01410e90, 0xfffffff0 },
{ }
*/
dev_net_set(dev, net);
- ret = -EEXIST;
mutex_lock(&pn->all_ppp_mutex);
if (unit < 0) {
unit = unit_get(&pn->units_idr, ppp);
if (unit < 0) {
- *retp = unit;
+ ret = unit;
goto out2;
}
} else {
+ ret = -EEXIST;
if (unit_find(&pn->units_idr, unit))
goto out2; /* unit already exists */
/*
ppp->closing = 1;
ppp_unlock(ppp);
unregister_netdev(ppp->dev);
+ unit_put(&pn->units_idr, ppp->file.index);
} else
ppp_unlock(ppp);
- unit_put(&pn->units_idr, ppp->file.index);
ppp->file.dead = 1;
ppp->owner = NULL;
wake_up_interruptible(&ppp->file.rwait);
* by holding all_ppp_mutex
*/
-/* associate pointer with specified number */
-static int unit_set(struct idr *p, void *ptr, int n)
+static int __unit_alloc(struct idr *p, void *ptr, int n)
{
int unit, err;
}
err = idr_get_new_above(p, ptr, n, &unit);
- if (err == -EAGAIN)
- goto again;
+ if (err < 0) {
+ if (err == -EAGAIN)
+ goto again;
+ return err;
+ }
+
+ return unit;
+}
+
+/* associate pointer with specified number */
+static int unit_set(struct idr *p, void *ptr, int n)
+{
+ int unit;
- if (unit != n) {
+ unit = __unit_alloc(p, ptr, n);
+ if (unit < 0)
+ return unit;
+ else if (unit != n) {
idr_remove(p, unit);
return -EINVAL;
}
/* get new free unit number and associate pointer with it */
static int unit_get(struct idr *p, void *ptr)
{
- int unit, err;
-
-again:
- if (!idr_pre_get(p, GFP_KERNEL)) {
- printk(KERN_ERR "PPP: No free memory for idr\n");
- return -ENOMEM;
- }
-
- err = idr_get_new_above(p, ptr, 0, &unit);
- if (err == -EAGAIN)
- goto again;
-
- return unit;
+ return __unit_alloc(p, ptr, 0);
}
/* put unit number back to a pool */
abort:
kfree_skb(skb);
- return 0;
+ return 1;
}
/************************************************************************
u32 mailbox_in;
u32 mailbox_out;
struct mbox_params idc_mbc;
+ struct mutex mpi_mutex;
int tx_ring_size;
int rx_ring_size;
/* NETIF_MSG_PKTDATA | */
NETIF_MSG_HW | NETIF_MSG_WOL | 0;
-static int debug = 0x00007fff; /* defaults above */
-module_param(debug, int, 0);
+static int debug = -1; /* defaults above */
+module_param(debug, int, 0664);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
#define MSIX_IRQ 0
#define MSI_IRQ 1
#define LEG_IRQ 2
static int qlge_irq_type = MSIX_IRQ;
-module_param(qlge_irq_type, int, MSIX_IRQ);
+module_param(qlge_irq_type, int, 0664);
MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
static int qlge_mpi_coredump;
INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log);
init_completion(&qdev->ide_completion);
+ mutex_init(&qdev->mpi_mutex);
if (!cards_found) {
dev_info(&pdev->dev, "%s\n", DRV_STRING);
int status;
unsigned long count;
+ mutex_lock(&qdev->mpi_mutex);
/* Begin polled mode for MPI */
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
end:
/* End polled mode for MPI */
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
+ mutex_unlock(&qdev->mpi_mutex);
return status;
}
static int ql_set_port_cfg(struct ql_adapter *qdev)
{
int status;
- rtnl_lock();
status = ql_mb_set_port_cfg(qdev);
- rtnl_unlock();
if (status)
return status;
status = ql_idc_wait(qdev);
container_of(work, struct ql_adapter, mpi_port_cfg_work.work);
int status;
- rtnl_lock();
status = ql_mb_get_port_cfg(qdev);
- rtnl_unlock();
if (status) {
netif_err(qdev, drv, qdev->ndev,
"Bug: Failed to get port config data.\n");
u32 aen;
int timeout;
- rtnl_lock();
aen = mbcp->mbox_out[1] >> 16;
timeout = (mbcp->mbox_out[1] >> 8) & 0xf;
}
break;
}
- rtnl_unlock();
}
void ql_mpi_work(struct work_struct *work)
struct mbox_params *mbcp = &mbc;
int err = 0;
- rtnl_lock();
+ mutex_lock(&qdev->mpi_mutex);
/* Begin polled mode for MPI */
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
/* End polled mode for MPI */
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
- rtnl_unlock();
+ mutex_unlock(&qdev->mpi_mutex);
ql_enable_completion_interrupt(qdev, 0);
}
mdio_write(ioaddr, MII_BMCR, val & 0xffff);
}
-static void rtl8169_check_link_status(struct net_device *dev,
+static void __rtl8169_check_link_status(struct net_device *dev,
struct rtl8169_private *tp,
- void __iomem *ioaddr)
+ void __iomem *ioaddr,
+ bool pm)
{
unsigned long flags;
spin_lock_irqsave(&tp->lock, flags);
if (tp->link_ok(ioaddr)) {
/* This is to cancel a scheduled suspend if there's one. */
- pm_request_resume(&tp->pci_dev->dev);
+ if (pm)
+ pm_request_resume(&tp->pci_dev->dev);
netif_carrier_on(dev);
netif_info(tp, ifup, dev, "link up\n");
} else {
netif_carrier_off(dev);
netif_info(tp, ifdown, dev, "link down\n");
- pm_schedule_suspend(&tp->pci_dev->dev, 100);
+ if (pm)
+ pm_schedule_suspend(&tp->pci_dev->dev, 100);
}
spin_unlock_irqrestore(&tp->lock, flags);
}
+static void rtl8169_check_link_status(struct net_device *dev,
+ struct rtl8169_private *tp,
+ void __iomem *ioaddr)
+{
+ __rtl8169_check_link_status(dev, tp, ioaddr, false);
+}
+
#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
u32 status = opts1 & RxProtoMask;
if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
- ((status == RxProtoUDP) && !(opts1 & UDPFail)) ||
- ((status == RxProtoIP) && !(opts1 & IPFail)))
+ ((status == RxProtoUDP) && !(opts1 & UDPFail)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb_checksum_none_assert(skb);
}
if (status & LinkChg)
- rtl8169_check_link_status(dev, tp, ioaddr);
+ __rtl8169_check_link_status(dev, tp, ioaddr, true);
/* We need to see the lastest version of tp->intr_mask to
* avoid ignoring an MSI interrupt and having to wait for
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);
- if (!tp->TxDescArray)
- return 0;
-
- rtl8169_check_link_status(dev, tp, tp->mmio_addr);
- return -EBUSY;
+ return tp->TxDescArray ? -EBUSY : 0;
}
static const struct dev_pm_ops rtl8169_pm_ops = {
static void efx_remove_channels(struct efx_nic *efx);
static void efx_remove_port(struct efx_nic *efx);
+static void efx_init_napi(struct efx_nic *efx);
static void efx_fini_napi(struct efx_nic *efx);
+static void efx_fini_napi_channel(struct efx_channel *channel);
static void efx_fini_struct(struct efx_nic *efx);
static void efx_start_all(struct efx_nic *efx);
static void efx_stop_all(struct efx_nic *efx);
/* Disable interrupts and wait for ISRs to complete */
efx_nic_disable_interrupts(efx);
- if (efx->legacy_irq)
+ if (efx->legacy_irq) {
synchronize_irq(efx->legacy_irq);
+ efx->legacy_irq_enabled = false;
+ }
if (channel->irq)
synchronize_irq(channel->irq);
efx_channel_processed(channel);
napi_enable(&channel->napi_str);
+ if (efx->legacy_irq)
+ efx->legacy_irq_enabled = true;
efx_nic_enable_interrupts(efx);
}
*channel = *old_channel;
+ channel->napi_dev = NULL;
memset(&channel->eventq, 0, sizeof(channel->eventq));
rx_queue = &channel->rx_queue;
if (rc)
goto rollback;
+ efx_init_napi(efx);
+
/* Destroy old channels */
- for (i = 0; i < efx->n_channels; i++)
+ for (i = 0; i < efx->n_channels; i++) {
+ efx_fini_napi_channel(other_channel[i]);
efx_remove_channel(other_channel[i]);
+ }
out:
/* Free unused channel structures */
for (i = 0; i < efx->n_channels; i++)
efx_start_channel(channel);
}
+ if (efx->legacy_irq)
+ efx->legacy_irq_enabled = true;
efx_nic_enable_interrupts(efx);
/* Switch to event based MCDI completions after enabling interrupts.
/* Disable interrupts and wait for ISR to complete */
efx_nic_disable_interrupts(efx);
- if (efx->legacy_irq)
+ if (efx->legacy_irq) {
synchronize_irq(efx->legacy_irq);
+ efx->legacy_irq_enabled = false;
+ }
efx_for_each_channel(channel, efx) {
if (channel->irq)
synchronize_irq(channel->irq);
*
**************************************************************************/
-static int efx_init_napi(struct efx_nic *efx)
+static void efx_init_napi(struct efx_nic *efx)
{
struct efx_channel *channel;
netif_napi_add(channel->napi_dev, &channel->napi_str,
efx_poll, napi_weight);
}
- return 0;
+}
+
+static void efx_fini_napi_channel(struct efx_channel *channel)
+{
+ if (channel->napi_dev)
+ netif_napi_del(&channel->napi_str);
+ channel->napi_dev = NULL;
}
static void efx_fini_napi(struct efx_nic *efx)
{
struct efx_channel *channel;
- efx_for_each_channel(channel, efx) {
- if (channel->napi_dev)
- netif_napi_del(&channel->napi_str);
- channel->napi_dev = NULL;
- }
+ efx_for_each_channel(channel, efx)
+ efx_fini_napi_channel(channel);
}
/**************************************************************************
if (rc)
goto fail1;
- rc = efx_init_napi(efx);
- if (rc)
- goto fail2;
+ efx_init_napi(efx);
rc = efx->type->init(efx);
if (rc) {
efx->type->fini(efx);
fail3:
efx_fini_napi(efx);
- fail2:
efx_remove_all(efx);
fail1:
return rc;
* @pci_dev: The PCI device
* @type: Controller type attributes
* @legacy_irq: IRQ number
+ * @legacy_irq_enabled: Are IRQs enabled on NIC (INT_EN_KER register)?
* @workqueue: Workqueue for port reconfigures and the HW monitor.
* Work items do not hold and must not acquire RTNL.
* @workqueue_name: Name of workqueue
struct pci_dev *pci_dev;
const struct efx_nic_type *type;
int legacy_irq;
+ bool legacy_irq_enabled;
struct workqueue_struct *workqueue;
char workqueue_name[16];
struct work_struct reset_work;
u32 queues;
int syserr;
+ /* Could this be ours? If interrupts are disabled then the
+ * channel state may not be valid.
+ */
+ if (!efx->legacy_irq_enabled)
+ return result;
+
/* Read the ISR which also ACKs the interrupts */
efx_readd(efx, ®, FR_BZ_INT_ISR0);
queues = EFX_EXTRACT_DWORD(reg, 0, 31);
pr_warning("\tno valid MAC address;"
"please, use ifconfig or nwhwconfig!\n");
+ spin_lock_init(&priv->lock);
+
ret = register_netdev(dev);
if (ret) {
pr_err("%s: ERROR %i registering the device\n",
dev->name, (dev->features & NETIF_F_SG) ? "on" : "off",
(dev->features & NETIF_F_HW_CSUM) ? "on" : "off");
- spin_lock_init(&priv->lock);
-
return ret;
}
--- /dev/null
+#
+# Makefile for the TILE on-chip networking support.
+#
+
+obj-$(CONFIG_TILE_NET) += tile_net.o
+ifdef CONFIG_TILEGX
+tile_net-objs := tilegx.o mpipe.o iorpc_mpipe.o dma_queue.o
+else
+tile_net-objs := tilepro.o
+endif
--- /dev/null
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/kernel.h> /* printk() */
+#include <linux/slab.h> /* kmalloc() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/skbuff.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/hugetlb.h>
+#include <linux/in6.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <asm/checksum.h>
+#include <asm/homecache.h>
+
+#include <hv/drv_xgbe_intf.h>
+#include <hv/drv_xgbe_impl.h>
+#include <hv/hypervisor.h>
+#include <hv/netio_intf.h>
+
+/* For TSO */
+#include <linux/ip.h>
+#include <linux/tcp.h>
+
+
+/* There is no singlethread_cpu, so schedule work on the current cpu. */
+#define singlethread_cpu -1
+
+
+/*
+ * First, "tile_net_init_module()" initializes all four "devices" which
+ * can be used by linux.
+ *
+ * Then, "ifconfig DEVICE up" calls "tile_net_open()", which analyzes
+ * the network cpus, then uses "tile_net_open_aux()" to initialize
+ * LIPP/LEPP, and then uses "tile_net_open_inner()" to register all
+ * the tiles, provide buffers to LIPP, allow ingress to start, and
+ * turn on hypervisor interrupt handling (and NAPI) on all tiles.
+ *
+ * If registration fails due to the link being down, then "retry_work"
+ * is used to keep calling "tile_net_open_inner()" until it succeeds.
+ *
+ * If "ifconfig DEVICE down" is called, it uses "tile_net_stop()" to
+ * stop egress, drain the LIPP buffers, unregister all the tiles, stop
+ * LIPP/LEPP, and wipe the LEPP queue.
+ *
+ * We start out with the ingress interrupt enabled on each CPU. When
+ * this interrupt fires, we disable it, and call "napi_schedule()".
+ * This will cause "tile_net_poll()" to be called, which will pull
+ * packets from the netio queue, filtering them out, or passing them
+ * to "netif_receive_skb()". If our budget is exhausted, we will
+ * return, knowing we will be called again later. Otherwise, we
+ * reenable the ingress interrupt, and call "napi_complete()".
+ *
+ *
+ * NOTE: The use of "native_driver" ensures that EPP exists, and that
+ * "epp_sendv" is legal, and that "LIPP" is being used.
+ *
+ * NOTE: Failing to free completions for an arbitrarily long time
+ * (which is defined to be illegal) does in fact cause bizarre
+ * problems. The "egress_timer" helps prevent this from happening.
+ *
+ * NOTE: The egress code can be interrupted by the interrupt handler.
+ */
+
+
+/* HACK: Allow use of "jumbo" packets. */
+/* This should be 1500 if "jumbo" is not set in LIPP. */
+/* This should be at most 10226 (10240 - 14) if "jumbo" is set in LIPP. */
+/* ISSUE: This has not been thoroughly tested (except at 1500). */
+#define TILE_NET_MTU 1500
+
+/* HACK: Define to support GSO. */
+/* ISSUE: This may actually hurt performance of the TCP blaster. */
+/* #define TILE_NET_GSO */
+
+/* Define this to collapse "duplicate" acks. */
+/* #define IGNORE_DUP_ACKS */
+
+/* HACK: Define this to verify incoming packets. */
+/* #define TILE_NET_VERIFY_INGRESS */
+
+/* Use 3000 to enable the Linux Traffic Control (QoS) layer, else 0. */
+#define TILE_NET_TX_QUEUE_LEN 0
+
+/* Define to dump packets (prints out the whole packet on tx and rx). */
+/* #define TILE_NET_DUMP_PACKETS */
+
+/* Define to enable debug spew (all PDEBUG's are enabled). */
+/* #define TILE_NET_DEBUG */
+
+
+/* Define to activate paranoia checks. */
+/* #define TILE_NET_PARANOIA */
+
+/* Default transmit lockup timeout period, in jiffies. */
+#define TILE_NET_TIMEOUT (5 * HZ)
+
+/* Default retry interval for bringing up the NetIO interface, in jiffies. */
+#define TILE_NET_RETRY_INTERVAL (5 * HZ)
+
+/* Number of ports (xgbe0, xgbe1, gbe0, gbe1). */
+#define TILE_NET_DEVS 4
+
+
+
+/* Paranoia. */
+#if NET_IP_ALIGN != LIPP_PACKET_PADDING
+#error "NET_IP_ALIGN must match LIPP_PACKET_PADDING."
+#endif
+
+
+/* Debug print. */
+#ifdef TILE_NET_DEBUG
+#define PDEBUG(fmt, args...) net_printk(fmt, ## args)
+#else
+#define PDEBUG(fmt, args...)
+#endif
+
+
+MODULE_AUTHOR("Tilera");
+MODULE_LICENSE("GPL");
+
+
+#define IS_MULTICAST(mac_addr) \
+ (((u8 *)(mac_addr))[0] & 0x01)
+
+#define IS_BROADCAST(mac_addr) \
+ (((u16 *)(mac_addr))[0] == 0xffff)
+
+
+/*
+ * Queue of incoming packets for a specific cpu and device.
+ *
+ * Includes a pointer to the "system" data, and the actual "user" data.
+ */
+struct tile_netio_queue {
+ netio_queue_impl_t *__system_part;
+ netio_queue_user_impl_t __user_part;
+
+};
+
+
+/*
+ * Statistics counters for a specific cpu and device.
+ */
+struct tile_net_stats_t {
+ u32 rx_packets;
+ u32 rx_bytes;
+ u32 tx_packets;
+ u32 tx_bytes;
+};
+
+
+/*
+ * Info for a specific cpu and device.
+ *
+ * ISSUE: There is a "dev" pointer in "napi" as well.
+ */
+struct tile_net_cpu {
+ /* The NAPI struct. */
+ struct napi_struct napi;
+ /* Packet queue. */
+ struct tile_netio_queue queue;
+ /* Statistics. */
+ struct tile_net_stats_t stats;
+ /* ISSUE: Is this needed? */
+ bool napi_enabled;
+ /* True if this tile has succcessfully registered with the IPP. */
+ bool registered;
+ /* True if the link was down last time we tried to register. */
+ bool link_down;
+ /* True if "egress_timer" is scheduled. */
+ bool egress_timer_scheduled;
+ /* Number of small sk_buffs which must still be provided. */
+ unsigned int num_needed_small_buffers;
+ /* Number of large sk_buffs which must still be provided. */
+ unsigned int num_needed_large_buffers;
+ /* A timer for handling egress completions. */
+ struct timer_list egress_timer;
+};
+
+
+/*
+ * Info for a specific device.
+ */
+struct tile_net_priv {
+ /* Our network device. */
+ struct net_device *dev;
+ /* The actual egress queue. */
+ lepp_queue_t *epp_queue;
+ /* Protects "epp_queue->cmd_tail" and "epp_queue->comp_tail" */
+ spinlock_t cmd_lock;
+ /* Protects "epp_queue->comp_head". */
+ spinlock_t comp_lock;
+ /* The hypervisor handle for this interface. */
+ int hv_devhdl;
+ /* The intr bit mask that IDs this device. */
+ u32 intr_id;
+ /* True iff "tile_net_open_aux()" has succeeded. */
+ int partly_opened;
+ /* True iff "tile_net_open_inner()" has succeeded. */
+ int fully_opened;
+ /* Effective network cpus. */
+ struct cpumask network_cpus_map;
+ /* Number of network cpus. */
+ int network_cpus_count;
+ /* Credits per network cpu. */
+ int network_cpus_credits;
+ /* Network stats. */
+ struct net_device_stats stats;
+ /* For NetIO bringup retries. */
+ struct delayed_work retry_work;
+ /* Quick access to per cpu data. */
+ struct tile_net_cpu *cpu[NR_CPUS];
+};
+
+
+/*
+ * The actual devices (xgbe0, xgbe1, gbe0, gbe1).
+ */
+static struct net_device *tile_net_devs[TILE_NET_DEVS];
+
+/*
+ * The "tile_net_cpu" structures for each device.
+ */
+static DEFINE_PER_CPU(struct tile_net_cpu, hv_xgbe0);
+static DEFINE_PER_CPU(struct tile_net_cpu, hv_xgbe1);
+static DEFINE_PER_CPU(struct tile_net_cpu, hv_gbe0);
+static DEFINE_PER_CPU(struct tile_net_cpu, hv_gbe1);
+
+
+/*
+ * True if "network_cpus" was specified.
+ */
+static bool network_cpus_used;
+
+/*
+ * The actual cpus in "network_cpus".
+ */
+static struct cpumask network_cpus_map;
+
+
+
+#ifdef TILE_NET_DEBUG
+/*
+ * printk with extra stuff.
+ *
+ * We print the CPU we're running in brackets.
+ */
+static void net_printk(char *fmt, ...)
+{
+ int i;
+ int len;
+ va_list args;
+ static char buf[256];
+
+ len = sprintf(buf, "tile_net[%2.2d]: ", smp_processor_id());
+ va_start(args, fmt);
+ i = vscnprintf(buf + len, sizeof(buf) - len - 1, fmt, args);
+ va_end(args);
+ buf[255] = '\0';
+ pr_notice(buf);
+}
+#endif
+
+
+#ifdef TILE_NET_DUMP_PACKETS
+/*
+ * Dump a packet.
+ */
+static void dump_packet(unsigned char *data, unsigned long length, char *s)
+{
+ unsigned long i;
+ static unsigned int count;
+
+ pr_info("dump_packet(data %p, length 0x%lx s %s count 0x%x)\n",
+ data, length, s, count++);
+
+ pr_info("\n");
+
+ for (i = 0; i < length; i++) {
+ if ((i & 0xf) == 0)
+ sprintf(buf, "%8.8lx:", i);
+ sprintf(buf + strlen(buf), " %2.2x", data[i]);
+ if ((i & 0xf) == 0xf || i == length - 1)
+ pr_info("%s\n", buf);
+ }
+}
+#endif
+
+
+/*
+ * Provide support for the __netio_fastio1() swint
+ * (see <hv/drv_xgbe_intf.h> for how it is used).
+ *
+ * The fastio swint2 call may clobber all the caller-saved registers.
+ * It rarely clobbers memory, but we allow for the possibility in
+ * the signature just to be on the safe side.
+ *
+ * Also, gcc doesn't seem to allow an input operand to be
+ * clobbered, so we fake it with dummy outputs.
+ *
+ * This function can't be static because of the way it is declared
+ * in the netio header.
+ */
+inline int __netio_fastio1(u32 fastio_index, u32 arg0)
+{
+ long result, clobber_r1, clobber_r10;
+ asm volatile("swint2"
+ : "=R00" (result),
+ "=R01" (clobber_r1), "=R10" (clobber_r10)
+ : "R10" (fastio_index), "R01" (arg0)
+ : "memory", "r2", "r3", "r4",
+ "r5", "r6", "r7", "r8", "r9",
+ "r11", "r12", "r13", "r14",
+ "r15", "r16", "r17", "r18", "r19",
+ "r20", "r21", "r22", "r23", "r24",
+ "r25", "r26", "r27", "r28", "r29");
+ return result;
+}
+
+
+/*
+ * Provide a linux buffer to LIPP.
+ */
+static void tile_net_provide_linux_buffer(struct tile_net_cpu *info,
+ void *va, bool small)
+{
+ struct tile_netio_queue *queue = &info->queue;
+
+ /* Convert "va" and "small" to "linux_buffer_t". */
+ unsigned int buffer = ((unsigned int)(__pa(va) >> 7) << 1) + small;
+
+ __netio_fastio_free_buffer(queue->__user_part.__fastio_index, buffer);
+}
+
+
+/*
+ * Provide a linux buffer for LIPP.
+ */
+static bool tile_net_provide_needed_buffer(struct tile_net_cpu *info,
+ bool small)
+{
+ /* ISSUE: What should we use here? */
+ unsigned int large_size = NET_IP_ALIGN + TILE_NET_MTU + 100;
+
+ /* Round up to ensure to avoid "false sharing" with last cache line. */
+ unsigned int buffer_size =
+ (((small ? LIPP_SMALL_PACKET_SIZE : large_size) +
+ CHIP_L2_LINE_SIZE() - 1) & -CHIP_L2_LINE_SIZE());
+
+ /*
+ * ISSUE: Since CPAs are 38 bits, and we can only encode the
+ * high 31 bits in a "linux_buffer_t", the low 7 bits must be
+ * zero, and thus, we must align the actual "va" mod 128.
+ */
+ const unsigned long align = 128;
+
+ struct sk_buff *skb;
+ void *va;
+
+ struct sk_buff **skb_ptr;
+
+ /* Note that "dev_alloc_skb()" adds NET_SKB_PAD more bytes, */
+ /* and also "reserves" that many bytes. */
+ /* ISSUE: Can we "share" the NET_SKB_PAD bytes with "skb_ptr"? */
+ int len = sizeof(*skb_ptr) + align + buffer_size;
+
+ while (1) {
+
+ /* Allocate (or fail). */
+ skb = dev_alloc_skb(len);
+ if (skb == NULL)
+ return false;
+
+ /* Make room for a back-pointer to 'skb'. */
+ skb_reserve(skb, sizeof(*skb_ptr));
+
+ /* Make sure we are aligned. */
+ skb_reserve(skb, -(long)skb->data & (align - 1));
+
+ /* This address is given to IPP. */
+ va = skb->data;
+
+ if (small)
+ break;
+
+ /* ISSUE: This has never been observed! */
+ /* Large buffers must not span a huge page. */
+ if (((((long)va & ~HPAGE_MASK) + 1535) & HPAGE_MASK) == 0)
+ break;
+ pr_err("Leaking unaligned linux buffer at %p.\n", va);
+ }
+
+ /* Skip two bytes to satisfy LIPP assumptions. */
+ /* Note that this aligns IP on a 16 byte boundary. */
+ /* ISSUE: Do this when the packet arrives? */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ /* Save a back-pointer to 'skb'. */
+ skb_ptr = va - sizeof(*skb_ptr);
+ *skb_ptr = skb;
+
+ /* Invalidate the packet buffer. */
+ if (!hash_default)
+ __inv_buffer(skb->data, buffer_size);
+
+ /* Make sure "skb_ptr" has been flushed. */
+ __insn_mf();
+
+#ifdef TILE_NET_PARANOIA
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (hash_default) {
+ HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)va);
+ if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3)
+ panic("Non-coherent ingress buffer!");
+ }
+#endif
+#endif
+
+ /* Provide the new buffer. */
+ tile_net_provide_linux_buffer(info, va, small);
+
+ return true;
+}
+
+
+/*
+ * Provide linux buffers for LIPP.
+ */
+static void tile_net_provide_needed_buffers(struct tile_net_cpu *info)
+{
+ while (info->num_needed_small_buffers != 0) {
+ if (!tile_net_provide_needed_buffer(info, true))
+ goto oops;
+ info->num_needed_small_buffers--;
+ }
+
+ while (info->num_needed_large_buffers != 0) {
+ if (!tile_net_provide_needed_buffer(info, false))
+ goto oops;
+ info->num_needed_large_buffers--;
+ }
+
+ return;
+
+oops:
+
+ /* Add a description to the page allocation failure dump. */
+ pr_notice("Could not provide a linux buffer to LIPP.\n");
+}
+
+
+/*
+ * Grab some LEPP completions, and store them in "comps", of size
+ * "comps_size", and return the number of completions which were
+ * stored, so the caller can free them.
+ *
+ * If "pending" is not NULL, it will be set to true if there might
+ * still be some pending completions caused by this tile, else false.
+ */
+static unsigned int tile_net_lepp_grab_comps(struct net_device *dev,
+ struct sk_buff *comps[],
+ unsigned int comps_size,
+ bool *pending)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ lepp_queue_t *eq = priv->epp_queue;
+
+ unsigned int n = 0;
+
+ unsigned int comp_head;
+ unsigned int comp_busy;
+ unsigned int comp_tail;
+
+ spin_lock(&priv->comp_lock);
+
+ comp_head = eq->comp_head;
+ comp_busy = eq->comp_busy;
+ comp_tail = eq->comp_tail;
+
+ while (comp_head != comp_busy && n < comps_size) {
+ comps[n++] = eq->comps[comp_head];
+ LEPP_QINC(comp_head);
+ }
+
+ if (pending != NULL)
+ *pending = (comp_head != comp_tail);
+
+ eq->comp_head = comp_head;
+
+ spin_unlock(&priv->comp_lock);
+
+ return n;
+}
+
+
+/*
+ * Make sure the egress timer is scheduled.
+ *
+ * Note that we use "schedule if not scheduled" logic instead of the more
+ * obvious "reschedule" logic, because "reschedule" is fairly expensive.
+ */
+static void tile_net_schedule_egress_timer(struct tile_net_cpu *info)
+{
+ if (!info->egress_timer_scheduled) {
+ mod_timer_pinned(&info->egress_timer, jiffies + 1);
+ info->egress_timer_scheduled = true;
+ }
+}
+
+
+/*
+ * The "function" for "info->egress_timer".
+ *
+ * This timer will reschedule itself as long as there are any pending
+ * completions expected (on behalf of any tile).
+ *
+ * ISSUE: Realistically, will the timer ever stop scheduling itself?
+ *
+ * ISSUE: This timer is almost never actually needed, so just use a global
+ * timer that can run on any tile.
+ *
+ * ISSUE: Maybe instead track number of expected completions, and free
+ * only that many, resetting to zero if "pending" is ever false.
+ */
+static void tile_net_handle_egress_timer(unsigned long arg)
+{
+ struct tile_net_cpu *info = (struct tile_net_cpu *)arg;
+ struct net_device *dev = info->napi.dev;
+
+ struct sk_buff *olds[32];
+ unsigned int wanted = 32;
+ unsigned int i, nolds = 0;
+ bool pending;
+
+ /* The timer is no longer scheduled. */
+ info->egress_timer_scheduled = false;
+
+ nolds = tile_net_lepp_grab_comps(dev, olds, wanted, &pending);
+
+ for (i = 0; i < nolds; i++)
+ kfree_skb(olds[i]);
+
+ /* Reschedule timer if needed. */
+ if (pending)
+ tile_net_schedule_egress_timer(info);
+}
+
+
+#ifdef IGNORE_DUP_ACKS
+
+/*
+ * Help detect "duplicate" ACKs. These are sequential packets (for a
+ * given flow) which are exactly 66 bytes long, sharing everything but
+ * ID=2@0x12, Hsum=2@0x18, Ack=4@0x2a, WinSize=2@0x30, Csum=2@0x32,
+ * Tstamps=10@0x38. The ID's are +1, the Hsum's are -1, the Ack's are
+ * +N, and the Tstamps are usually identical.
+ *
+ * NOTE: Apparently truly duplicate acks (with identical "ack" values),
+ * should not be collapsed, as they are used for some kind of flow control.
+ */
+static bool is_dup_ack(char *s1, char *s2, unsigned int len)
+{
+ int i;
+
+ unsigned long long ignorable = 0;
+
+ /* Identification. */
+ ignorable |= (1ULL << 0x12);
+ ignorable |= (1ULL << 0x13);
+
+ /* Header checksum. */
+ ignorable |= (1ULL << 0x18);
+ ignorable |= (1ULL << 0x19);
+
+ /* ACK. */
+ ignorable |= (1ULL << 0x2a);
+ ignorable |= (1ULL << 0x2b);
+ ignorable |= (1ULL << 0x2c);
+ ignorable |= (1ULL << 0x2d);
+
+ /* WinSize. */
+ ignorable |= (1ULL << 0x30);
+ ignorable |= (1ULL << 0x31);
+
+ /* Checksum. */
+ ignorable |= (1ULL << 0x32);
+ ignorable |= (1ULL << 0x33);
+
+ for (i = 0; i < len; i++, ignorable >>= 1) {
+
+ if ((ignorable & 1) || (s1[i] == s2[i]))
+ continue;
+
+#ifdef TILE_NET_DEBUG
+ /* HACK: Mention non-timestamp diffs. */
+ if (i < 0x38 && i != 0x2f &&
+ net_ratelimit())
+ pr_info("Diff at 0x%x\n", i);
+#endif
+
+ return false;
+ }
+
+#ifdef TILE_NET_NO_SUPPRESS_DUP_ACKS
+ /* HACK: Do not suppress truly duplicate ACKs. */
+ /* ISSUE: Is this actually necessary or helpful? */
+ if (s1[0x2a] == s2[0x2a] &&
+ s1[0x2b] == s2[0x2b] &&
+ s1[0x2c] == s2[0x2c] &&
+ s1[0x2d] == s2[0x2d]) {
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+#endif
+
+
+
+/*
+ * Like "tile_net_handle_packets()", but just discard packets.
+ */
+static void tile_net_discard_packets(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+ struct tile_netio_queue *queue = &info->queue;
+ netio_queue_impl_t *qsp = queue->__system_part;
+ netio_queue_user_impl_t *qup = &queue->__user_part;
+
+ while (qup->__packet_receive_read !=
+ qsp->__packet_receive_queue.__packet_write) {
+
+ int index = qup->__packet_receive_read;
+
+ int index2_aux = index + sizeof(netio_pkt_t);
+ int index2 =
+ ((index2_aux ==
+ qsp->__packet_receive_queue.__last_packet_plus_one) ?
+ 0 : index2_aux);
+
+ netio_pkt_t *pkt = (netio_pkt_t *)
+ ((unsigned long) &qsp[1] + index);
+
+ /* Extract the "linux_buffer_t". */
+ unsigned int buffer = pkt->__packet.word;
+
+ /* Convert "linux_buffer_t" to "va". */
+ void *va = __va((phys_addr_t)(buffer >> 1) << 7);
+
+ /* Acquire the associated "skb". */
+ struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
+ struct sk_buff *skb = *skb_ptr;
+
+ kfree_skb(skb);
+
+ /* Consume this packet. */
+ qup->__packet_receive_read = index2;
+ }
+}
+
+
+/*
+ * Handle the next packet. Return true if "processed", false if "filtered".
+ */
+static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
+{
+ struct net_device *dev = info->napi.dev;
+
+ struct tile_netio_queue *queue = &info->queue;
+ netio_queue_impl_t *qsp = queue->__system_part;
+ netio_queue_user_impl_t *qup = &queue->__user_part;
+ struct tile_net_stats_t *stats = &info->stats;
+
+ int filter;
+
+ int index2_aux = index + sizeof(netio_pkt_t);
+ int index2 =
+ ((index2_aux ==
+ qsp->__packet_receive_queue.__last_packet_plus_one) ?
+ 0 : index2_aux);
+
+ netio_pkt_t *pkt = (netio_pkt_t *)((unsigned long) &qsp[1] + index);
+
+ netio_pkt_metadata_t *metadata = NETIO_PKT_METADATA(pkt);
+
+ /* Extract the packet size. */
+ unsigned long len =
+ (NETIO_PKT_CUSTOM_LENGTH(pkt) +
+ NET_IP_ALIGN - NETIO_PACKET_PADDING);
+
+ /* Extract the "linux_buffer_t". */
+ unsigned int buffer = pkt->__packet.word;
+
+ /* Extract "small" (vs "large"). */
+ bool small = ((buffer & 1) != 0);
+
+ /* Convert "linux_buffer_t" to "va". */
+ void *va = __va((phys_addr_t)(buffer >> 1) << 7);
+
+ /* Extract the packet data pointer. */
+ /* Compare to "NETIO_PKT_CUSTOM_DATA(pkt)". */
+ unsigned char *buf = va + NET_IP_ALIGN;
+
+#ifdef IGNORE_DUP_ACKS
+
+ static int other;
+ static int final;
+ static int keep;
+ static int skip;
+
+#endif
+
+ /* Invalidate the packet buffer. */
+ if (!hash_default)
+ __inv_buffer(buf, len);
+
+ /* ISSUE: Is this needed? */
+ dev->last_rx = jiffies;
+
+#ifdef TILE_NET_DUMP_PACKETS
+ dump_packet(buf, len, "rx");
+#endif /* TILE_NET_DUMP_PACKETS */
+
+#ifdef TILE_NET_VERIFY_INGRESS
+ if (!NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt) &&
+ NETIO_PKT_L4_CSUM_CALCULATED_M(metadata, pkt)) {
+ /*
+ * FIXME: This complains about UDP packets
+ * with a "zero" checksum (bug 6624).
+ */
+#ifdef TILE_NET_PANIC_ON_BAD
+ dump_packet(buf, len, "rx");
+ panic("Bad L4 checksum.");
+#else
+ pr_warning("Bad L4 checksum on %d byte packet.\n", len);
+#endif
+ }
+ if (!NETIO_PKT_L3_CSUM_CORRECT_M(metadata, pkt) &&
+ NETIO_PKT_L3_CSUM_CALCULATED_M(metadata, pkt)) {
+ dump_packet(buf, len, "rx");
+ panic("Bad L3 checksum.");
+ }
+ switch (NETIO_PKT_STATUS_M(metadata, pkt)) {
+ case NETIO_PKT_STATUS_OVERSIZE:
+ if (len >= 64) {
+ dump_packet(buf, len, "rx");
+ panic("Unexpected OVERSIZE.");
+ }
+ break;
+ case NETIO_PKT_STATUS_BAD:
+#ifdef TILE_NET_PANIC_ON_BAD
+ dump_packet(buf, len, "rx");
+ panic("Unexpected BAD packet.");
+#else
+ pr_warning("Unexpected BAD %d byte packet.\n", len);
+#endif
+ }
+#endif
+
+ filter = 0;
+
+ if (!(dev->flags & IFF_UP)) {
+ /* Filter packets received before we're up. */
+ filter = 1;
+ } else if (!(dev->flags & IFF_PROMISC)) {
+ /*
+ * FIXME: Implement HW multicast filter.
+ */
+ if (!IS_MULTICAST(buf) && !IS_BROADCAST(buf)) {
+ /* Filter packets not for our address. */
+ const u8 *mine = dev->dev_addr;
+ filter = compare_ether_addr(mine, buf);
+ }
+ }
+
+#ifdef IGNORE_DUP_ACKS
+
+ if (len != 66) {
+ /* FIXME: Must check "is_tcp_ack(buf, len)" somehow. */
+
+ other++;
+
+ } else if (index2 ==
+ qsp->__packet_receive_queue.__packet_write) {
+
+ final++;
+
+ } else {
+
+ netio_pkt_t *pkt2 = (netio_pkt_t *)
+ ((unsigned long) &qsp[1] + index2);
+
+ netio_pkt_metadata_t *metadata2 =
+ NETIO_PKT_METADATA(pkt2);
+
+ /* Extract the packet size. */
+ unsigned long len2 =
+ (NETIO_PKT_CUSTOM_LENGTH(pkt2) +
+ NET_IP_ALIGN - NETIO_PACKET_PADDING);
+
+ if (len2 == 66 &&
+ NETIO_PKT_FLOW_HASH_M(metadata, pkt) ==
+ NETIO_PKT_FLOW_HASH_M(metadata2, pkt2)) {
+
+ /* Extract the "linux_buffer_t". */
+ unsigned int buffer2 = pkt2->__packet.word;
+
+ /* Convert "linux_buffer_t" to "va". */
+ void *va2 =
+ __va((phys_addr_t)(buffer2 >> 1) << 7);
+
+ /* Extract the packet data pointer. */
+ /* Compare to "NETIO_PKT_CUSTOM_DATA(pkt)". */
+ unsigned char *buf2 = va2 + NET_IP_ALIGN;
+
+ /* Invalidate the packet buffer. */
+ if (!hash_default)
+ __inv_buffer(buf2, len2);
+
+ if (is_dup_ack(buf, buf2, len)) {
+ skip++;
+ filter = 1;
+ } else {
+ keep++;
+ }
+ }
+ }
+
+ if (net_ratelimit())
+ pr_info("Other %d Final %d Keep %d Skip %d.\n",
+ other, final, keep, skip);
+
+#endif
+
+ if (filter) {
+
+ /* ISSUE: Update "drop" statistics? */
+
+ tile_net_provide_linux_buffer(info, va, small);
+
+ } else {
+
+ /* Acquire the associated "skb". */
+ struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
+ struct sk_buff *skb = *skb_ptr;
+
+ /* Paranoia. */
+ if (skb->data != buf)
+ panic("Corrupt linux buffer from LIPP! "
+ "VA=%p, skb=%p, skb->data=%p\n",
+ va, skb, skb->data);
+
+ /* Encode the actual packet length. */
+ skb_put(skb, len);
+
+ /* NOTE: This call also sets "skb->dev = dev". */
+ skb->protocol = eth_type_trans(skb, dev);
+
+ /* ISSUE: Discard corrupt packets? */
+ /* ISSUE: Discard packets with bad checksums? */
+
+ /* Avoid recomputing TCP/UDP checksums. */
+ if (NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ netif_receive_skb(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += len;
+
+ if (small)
+ info->num_needed_small_buffers++;
+ else
+ info->num_needed_large_buffers++;
+ }
+
+ /* Return four credits after every fourth packet. */
+ if (--qup->__receive_credit_remaining == 0) {
+ u32 interval = qup->__receive_credit_interval;
+ qup->__receive_credit_remaining = interval;
+ __netio_fastio_return_credits(qup->__fastio_index, interval);
+ }
+
+ /* Consume this packet. */
+ qup->__packet_receive_read = index2;
+
+ return !filter;
+}
+
+
+/*
+ * Handle some packets for the given device on the current CPU.
+ *
+ * ISSUE: The "rotting packet" race condition occurs if a packet
+ * arrives after the queue appears to be empty, and before the
+ * hypervisor interrupt is re-enabled.
+ */
+static int tile_net_poll(struct napi_struct *napi, int budget)
+{
+ struct net_device *dev = napi->dev;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+ struct tile_netio_queue *queue = &info->queue;
+ netio_queue_impl_t *qsp = queue->__system_part;
+ netio_queue_user_impl_t *qup = &queue->__user_part;
+
+ unsigned int work = 0;
+
+ while (1) {
+ int index = qup->__packet_receive_read;
+ if (index == qsp->__packet_receive_queue.__packet_write)
+ break;
+
+ if (tile_net_poll_aux(info, index)) {
+ if (++work >= budget)
+ goto done;
+ }
+ }
+
+ napi_complete(&info->napi);
+
+ /* Re-enable hypervisor interrupts. */
+ enable_percpu_irq(priv->intr_id);
+
+ /* HACK: Avoid the "rotting packet" problem. */
+ if (qup->__packet_receive_read !=
+ qsp->__packet_receive_queue.__packet_write)
+ napi_schedule(&info->napi);
+
+ /* ISSUE: Handle completions? */
+
+done:
+
+ tile_net_provide_needed_buffers(info);
+
+ return work;
+}
+
+
+/*
+ * Handle an ingress interrupt for the given device on the current cpu.
+ */
+static irqreturn_t tile_net_handle_ingress_interrupt(int irq, void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+
+ /* Disable hypervisor interrupt. */
+ disable_percpu_irq(priv->intr_id);
+
+ napi_schedule(&info->napi);
+
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * One time initialization per interface.
+ */
+static int tile_net_open_aux(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ int ret;
+ int dummy;
+ unsigned int epp_lotar;
+
+ /*
+ * Find out where EPP memory should be homed.
+ */
+ ret = hv_dev_pread(priv->hv_devhdl, 0,
+ (HV_VirtAddr)&epp_lotar, sizeof(epp_lotar),
+ NETIO_EPP_SHM_OFF);
+ if (ret < 0) {
+ pr_err("could not read epp_shm_queue lotar.\n");
+ return -EIO;
+ }
+
+ /*
+ * Home the page on the EPP.
+ */
+ {
+ int epp_home = hv_lotar_to_cpu(epp_lotar);
+ struct page *page = virt_to_page(priv->epp_queue);
+ homecache_change_page_home(page, 0, epp_home);
+ }
+
+ /*
+ * Register the EPP shared memory queue.
+ */
+ {
+ netio_ipp_address_t ea = {
+ .va = 0,
+ .pa = __pa(priv->epp_queue),
+ .pte = hv_pte(0),
+ .size = PAGE_SIZE,
+ };
+ ea.pte = hv_pte_set_lotar(ea.pte, epp_lotar);
+ ea.pte = hv_pte_set_mode(ea.pte, HV_PTE_MODE_CACHE_TILE_L3);
+ ret = hv_dev_pwrite(priv->hv_devhdl, 0,
+ (HV_VirtAddr)&ea,
+ sizeof(ea),
+ NETIO_EPP_SHM_OFF);
+ if (ret < 0)
+ return -EIO;
+ }
+
+ /*
+ * Start LIPP/LEPP.
+ */
+ if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
+ sizeof(dummy), NETIO_IPP_START_SHIM_OFF) < 0) {
+ pr_warning("Failed to start LIPP/LEPP.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Register with hypervisor on each CPU.
+ *
+ * Strangely, this function does important things even if it "fails",
+ * which is especially common if the link is not up yet. Hopefully
+ * these things are all "harmless" if done twice!
+ */
+static void tile_net_register(void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info;
+
+ struct tile_netio_queue *queue;
+
+ /* Only network cpus can receive packets. */
+ int queue_id =
+ cpumask_test_cpu(my_cpu, &priv->network_cpus_map) ? 0 : 255;
+
+ netio_input_config_t config = {
+ .flags = 0,
+ .num_receive_packets = priv->network_cpus_credits,
+ .queue_id = queue_id
+ };
+
+ int ret = 0;
+ netio_queue_impl_t *queuep;
+
+ PDEBUG("tile_net_register(queue_id %d)\n", queue_id);
+
+ if (!strcmp(dev->name, "xgbe0"))
+ info = &__get_cpu_var(hv_xgbe0);
+ else if (!strcmp(dev->name, "xgbe1"))
+ info = &__get_cpu_var(hv_xgbe1);
+ else if (!strcmp(dev->name, "gbe0"))
+ info = &__get_cpu_var(hv_gbe0);
+ else if (!strcmp(dev->name, "gbe1"))
+ info = &__get_cpu_var(hv_gbe1);
+ else
+ BUG();
+
+ /* Initialize the egress timer. */
+ init_timer(&info->egress_timer);
+ info->egress_timer.data = (long)info;
+ info->egress_timer.function = tile_net_handle_egress_timer;
+
+ priv->cpu[my_cpu] = info;
+
+ /*
+ * Register ourselves with the IPP.
+ */
+ ret = hv_dev_pwrite(priv->hv_devhdl, 0,
+ (HV_VirtAddr)&config,
+ sizeof(netio_input_config_t),
+ NETIO_IPP_INPUT_REGISTER_OFF);
+ PDEBUG("hv_dev_pwrite(NETIO_IPP_INPUT_REGISTER_OFF) returned %d\n",
+ ret);
+ if (ret < 0) {
+ printk(KERN_DEBUG "hv_dev_pwrite NETIO_IPP_INPUT_REGISTER_OFF"
+ " failure %d\n", ret);
+ info->link_down = (ret == NETIO_LINK_DOWN);
+ return;
+ }
+
+ /*
+ * Get the pointer to our queue's system part.
+ */
+
+ ret = hv_dev_pread(priv->hv_devhdl, 0,
+ (HV_VirtAddr)&queuep,
+ sizeof(netio_queue_impl_t *),
+ NETIO_IPP_INPUT_REGISTER_OFF);
+ PDEBUG("hv_dev_pread(NETIO_IPP_INPUT_REGISTER_OFF) returned %d\n",
+ ret);
+ PDEBUG("queuep %p\n", queuep);
+ if (ret <= 0) {
+ /* ISSUE: Shouldn't this be a fatal error? */
+ pr_err("hv_dev_pread NETIO_IPP_INPUT_REGISTER_OFF failure\n");
+ return;
+ }
+
+ queue = &info->queue;
+
+ queue->__system_part = queuep;
+
+ memset(&queue->__user_part, 0, sizeof(netio_queue_user_impl_t));
+
+ /* This is traditionally "config.num_receive_packets / 2". */
+ queue->__user_part.__receive_credit_interval = 4;
+ queue->__user_part.__receive_credit_remaining =
+ queue->__user_part.__receive_credit_interval;
+
+ /*
+ * Get a fastio index from the hypervisor.
+ * ISSUE: Shouldn't this check the result?
+ */
+ ret = hv_dev_pread(priv->hv_devhdl, 0,
+ (HV_VirtAddr)&queue->__user_part.__fastio_index,
+ sizeof(queue->__user_part.__fastio_index),
+ NETIO_IPP_GET_FASTIO_OFF);
+ PDEBUG("hv_dev_pread(NETIO_IPP_GET_FASTIO_OFF) returned %d\n", ret);
+
+ netif_napi_add(dev, &info->napi, tile_net_poll, 64);
+
+ /* Now we are registered. */
+ info->registered = true;
+}
+
+
+/*
+ * Unregister with hypervisor on each CPU.
+ */
+static void tile_net_unregister(void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+
+ int ret = 0;
+ int dummy = 0;
+
+ /* Do nothing if never registered. */
+ if (info == NULL)
+ return;
+
+ /* Do nothing if already unregistered. */
+ if (!info->registered)
+ return;
+
+ /*
+ * Unregister ourselves with LIPP.
+ */
+ ret = hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
+ sizeof(dummy), NETIO_IPP_INPUT_UNREGISTER_OFF);
+ PDEBUG("hv_dev_pwrite(NETIO_IPP_INPUT_UNREGISTER_OFF) returned %d\n",
+ ret);
+ if (ret < 0) {
+ /* FIXME: Just panic? */
+ pr_err("hv_dev_pwrite NETIO_IPP_INPUT_UNREGISTER_OFF"
+ " failure %d\n", ret);
+ }
+
+ /*
+ * Discard all packets still in our NetIO queue. Hopefully,
+ * once the unregister call is complete, there will be no
+ * packets still in flight on the IDN.
+ */
+ tile_net_discard_packets(dev);
+
+ /* Reset state. */
+ info->num_needed_small_buffers = 0;
+ info->num_needed_large_buffers = 0;
+
+ /* Cancel egress timer. */
+ del_timer(&info->egress_timer);
+ info->egress_timer_scheduled = false;
+
+ netif_napi_del(&info->napi);
+
+ /* Now we are unregistered. */
+ info->registered = false;
+}
+
+
+/*
+ * Helper function for "tile_net_stop()".
+ *
+ * Also used to handle registration failure in "tile_net_open_inner()",
+ * when "fully_opened" is known to be false, and the various extra
+ * steps in "tile_net_stop()" are not necessary. ISSUE: It might be
+ * simpler if we could just call "tile_net_stop()" anyway.
+ */
+static void tile_net_stop_aux(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ int dummy = 0;
+
+ /* Unregister all tiles, so LIPP will stop delivering packets. */
+ on_each_cpu(tile_net_unregister, (void *)dev, 1);
+
+ /* Stop LIPP/LEPP. */
+ if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
+ sizeof(dummy), NETIO_IPP_STOP_SHIM_OFF) < 0)
+ panic("Failed to stop LIPP/LEPP!\n");
+
+ priv->partly_opened = 0;
+}
+
+
+/*
+ * Disable ingress interrupts for the given device on the current cpu.
+ */
+static void tile_net_disable_intr(void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+
+ /* Disable hypervisor interrupt. */
+ disable_percpu_irq(priv->intr_id);
+
+ /* Disable NAPI if needed. */
+ if (info != NULL && info->napi_enabled) {
+ napi_disable(&info->napi);
+ info->napi_enabled = false;
+ }
+}
+
+
+/*
+ * Enable ingress interrupts for the given device on the current cpu.
+ */
+static void tile_net_enable_intr(void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+
+ /* Enable hypervisor interrupt. */
+ enable_percpu_irq(priv->intr_id);
+
+ /* Enable NAPI. */
+ napi_enable(&info->napi);
+ info->napi_enabled = true;
+}
+
+
+/*
+ * tile_net_open_inner does most of the work of bringing up the interface.
+ * It's called from tile_net_open(), and also from tile_net_retry_open().
+ * The return value is 0 if the interface was brought up, < 0 if
+ * tile_net_open() should return the return value as an error, and > 0 if
+ * tile_net_open() should return success and schedule a work item to
+ * periodically retry the bringup.
+ */
+static int tile_net_open_inner(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info;
+ struct tile_netio_queue *queue;
+ unsigned int irq;
+ int i;
+
+ /*
+ * First try to register just on the local CPU, and handle any
+ * semi-expected "link down" failure specially. Note that we
+ * do NOT call "tile_net_stop_aux()", unlike below.
+ */
+ tile_net_register(dev);
+ info = priv->cpu[my_cpu];
+ if (!info->registered) {
+ if (info->link_down)
+ return 1;
+ return -EAGAIN;
+ }
+
+ /*
+ * Now register everywhere else. If any registration fails,
+ * even for "link down" (which might not be possible), we
+ * clean up using "tile_net_stop_aux()".
+ */
+ smp_call_function(tile_net_register, (void *)dev, 1);
+ for_each_online_cpu(i) {
+ if (!priv->cpu[i]->registered) {
+ tile_net_stop_aux(dev);
+ return -EAGAIN;
+ }
+ }
+
+ queue = &info->queue;
+
+ /*
+ * Set the device intr bit mask.
+ * The tile_net_register above sets per tile __intr_id.
+ */
+ priv->intr_id = queue->__system_part->__intr_id;
+ BUG_ON(!priv->intr_id);
+
+ /*
+ * Register the device interrupt handler.
+ * The __ffs() function returns the index into the interrupt handler
+ * table from the interrupt bit mask which should have one bit
+ * and one bit only set.
+ */
+ irq = __ffs(priv->intr_id);
+ tile_irq_activate(irq, TILE_IRQ_PERCPU);
+ BUG_ON(request_irq(irq, tile_net_handle_ingress_interrupt,
+ 0, dev->name, (void *)dev) != 0);
+
+ /* ISSUE: How could "priv->fully_opened" ever be "true" here? */
+
+ if (!priv->fully_opened) {
+
+ int dummy = 0;
+
+ /* Allocate initial buffers. */
+
+ int max_buffers =
+ priv->network_cpus_count * priv->network_cpus_credits;
+
+ info->num_needed_small_buffers =
+ min(LIPP_SMALL_BUFFERS, max_buffers);
+
+ info->num_needed_large_buffers =
+ min(LIPP_LARGE_BUFFERS, max_buffers);
+
+ tile_net_provide_needed_buffers(info);
+
+ if (info->num_needed_small_buffers != 0 ||
+ info->num_needed_large_buffers != 0)
+ panic("Insufficient memory for buffer stack!");
+
+ /* Start LIPP/LEPP and activate "ingress" at the shim. */
+ if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
+ sizeof(dummy), NETIO_IPP_INPUT_INIT_OFF) < 0)
+ panic("Failed to activate the LIPP Shim!\n");
+
+ priv->fully_opened = 1;
+ }
+
+ /* On each tile, enable the hypervisor to trigger interrupts. */
+ /* ISSUE: Do this before starting LIPP/LEPP? */
+ on_each_cpu(tile_net_enable_intr, (void *)dev, 1);
+
+ /* Start our transmit queue. */
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+
+/*
+ * Called periodically to retry bringing up the NetIO interface,
+ * if it doesn't come up cleanly during tile_net_open().
+ */
+static void tile_net_open_retry(struct work_struct *w)
+{
+ struct delayed_work *dw =
+ container_of(w, struct delayed_work, work);
+
+ struct tile_net_priv *priv =
+ container_of(dw, struct tile_net_priv, retry_work);
+
+ /*
+ * Try to bring the NetIO interface up. If it fails, reschedule
+ * ourselves to try again later; otherwise, tell Linux we now have
+ * a working link. ISSUE: What if the return value is negative?
+ */
+ if (tile_net_open_inner(priv->dev))
+ schedule_delayed_work_on(singlethread_cpu, &priv->retry_work,
+ TILE_NET_RETRY_INTERVAL);
+ else
+ netif_carrier_on(priv->dev);
+}
+
+
+/*
+ * Called when a network interface is made active.
+ *
+ * Returns 0 on success, negative value on failure.
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ *
+ * If the actual link is not available yet, then we tell Linux that
+ * we have no carrier, and we keep checking until the link comes up.
+ */
+static int tile_net_open(struct net_device *dev)
+{
+ int ret = 0;
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ /*
+ * We rely on priv->partly_opened to tell us if this is the
+ * first time this interface is being brought up. If it is
+ * set, the IPP was already initialized and should not be
+ * initialized again.
+ */
+ if (!priv->partly_opened) {
+
+ int count;
+ int credits;
+
+ /* Initialize LIPP/LEPP, and start the Shim. */
+ ret = tile_net_open_aux(dev);
+ if (ret < 0) {
+ pr_err("tile_net_open_aux failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Analyze the network cpus. */
+
+ if (network_cpus_used)
+ cpumask_copy(&priv->network_cpus_map,
+ &network_cpus_map);
+ else
+ cpumask_copy(&priv->network_cpus_map, cpu_online_mask);
+
+
+ count = cpumask_weight(&priv->network_cpus_map);
+
+ /* Limit credits to available buffers, and apply min. */
+ credits = max(16, (LIPP_LARGE_BUFFERS / count) & ~1);
+
+ /* Apply "GBE" max limit. */
+ /* ISSUE: Use higher limit for XGBE? */
+ credits = min(NETIO_MAX_RECEIVE_PKTS, credits);
+
+ priv->network_cpus_count = count;
+ priv->network_cpus_credits = credits;
+
+#ifdef TILE_NET_DEBUG
+ pr_info("Using %d network cpus, with %d credits each\n",
+ priv->network_cpus_count, priv->network_cpus_credits);
+#endif
+
+ priv->partly_opened = 1;
+ }
+
+ /*
+ * Attempt to bring up the link.
+ */
+ ret = tile_net_open_inner(dev);
+ if (ret <= 0) {
+ if (ret == 0)
+ netif_carrier_on(dev);
+ return ret;
+ }
+
+ /*
+ * We were unable to bring up the NetIO interface, but we want to
+ * try again in a little bit. Tell Linux that we have no carrier
+ * so it doesn't try to use the interface before the link comes up
+ * and then remember to try again later.
+ */
+ netif_carrier_off(dev);
+ schedule_delayed_work_on(singlethread_cpu, &priv->retry_work,
+ TILE_NET_RETRY_INTERVAL);
+
+ return 0;
+}
+
+
+/*
+ * Disables a network interface.
+ *
+ * Returns 0, this is not allowed to fail.
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ *
+ * ISSUE: Can this can be called while "tile_net_poll()" is running?
+ */
+static int tile_net_stop(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ bool pending = true;
+
+ PDEBUG("tile_net_stop()\n");
+
+ /* ISSUE: Only needed if not yet fully open. */
+ cancel_delayed_work_sync(&priv->retry_work);
+
+ /* Can't transmit any more. */
+ netif_stop_queue(dev);
+
+ /*
+ * Disable hypervisor interrupts on each tile.
+ */
+ on_each_cpu(tile_net_disable_intr, (void *)dev, 1);
+
+ /*
+ * Unregister the interrupt handler.
+ * The __ffs() function returns the index into the interrupt handler
+ * table from the interrupt bit mask which should have one bit
+ * and one bit only set.
+ */
+ if (priv->intr_id)
+ free_irq(__ffs(priv->intr_id), dev);
+
+ /*
+ * Drain all the LIPP buffers.
+ */
+
+ while (true) {
+ int buffer;
+
+ /* NOTE: This should never fail. */
+ if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&buffer,
+ sizeof(buffer), NETIO_IPP_DRAIN_OFF) < 0)
+ break;
+
+ /* Stop when done. */
+ if (buffer == 0)
+ break;
+
+ {
+ /* Convert "linux_buffer_t" to "va". */
+ void *va = __va((phys_addr_t)(buffer >> 1) << 7);
+
+ /* Acquire the associated "skb". */
+ struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
+ struct sk_buff *skb = *skb_ptr;
+
+ kfree_skb(skb);
+ }
+ }
+
+ /* Stop LIPP/LEPP. */
+ tile_net_stop_aux(dev);
+
+
+ priv->fully_opened = 0;
+
+
+ /*
+ * XXX: ISSUE: It appears that, in practice anyway, by the
+ * time we get here, there are no pending completions.
+ */
+ while (pending) {
+
+ struct sk_buff *olds[32];
+ unsigned int wanted = 32;
+ unsigned int i, nolds = 0;
+
+ nolds = tile_net_lepp_grab_comps(dev, olds,
+ wanted, &pending);
+
+ /* ISSUE: We have never actually seen this debug spew. */
+ if (nolds != 0)
+ pr_info("During tile_net_stop(), grabbed %d comps.\n",
+ nolds);
+
+ for (i = 0; i < nolds; i++)
+ kfree_skb(olds[i]);
+ }
+
+
+ /* Wipe the EPP queue. */
+ memset(priv->epp_queue, 0, sizeof(lepp_queue_t));
+
+ /* Evict the EPP queue. */
+ finv_buffer(priv->epp_queue, PAGE_SIZE);
+
+ return 0;
+}
+
+
+/*
+ * Prepare the "frags" info for the resulting LEPP command.
+ *
+ * If needed, flush the memory used by the frags.
+ */
+static unsigned int tile_net_tx_frags(lepp_frag_t *frags,
+ struct sk_buff *skb,
+ void *b_data, unsigned int b_len)
+{
+ unsigned int i, n = 0;
+
+ struct skb_shared_info *sh = skb_shinfo(skb);
+
+ phys_addr_t cpa;
+
+ if (b_len != 0) {
+
+ if (!hash_default)
+ finv_buffer_remote(b_data, b_len);
+
+ cpa = __pa(b_data);
+ frags[n].cpa_lo = cpa;
+ frags[n].cpa_hi = cpa >> 32;
+ frags[n].length = b_len;
+ frags[n].hash_for_home = hash_default;
+ n++;
+ }
+
+ for (i = 0; i < sh->nr_frags; i++) {
+
+ skb_frag_t *f = &sh->frags[i];
+ unsigned long pfn = page_to_pfn(f->page);
+
+ /* FIXME: Compute "hash_for_home" properly. */
+ /* ISSUE: The hypervisor checks CHIP_HAS_REV1_DMA_PACKETS(). */
+ int hash_for_home = hash_default;
+
+ /* FIXME: Hmmm. */
+ if (!hash_default) {
+ void *va = pfn_to_kaddr(pfn) + f->page_offset;
+ BUG_ON(PageHighMem(f->page));
+ finv_buffer_remote(va, f->size);
+ }
+
+ cpa = ((phys_addr_t)pfn << PAGE_SHIFT) + f->page_offset;
+ frags[n].cpa_lo = cpa;
+ frags[n].cpa_hi = cpa >> 32;
+ frags[n].length = f->size;
+ frags[n].hash_for_home = hash_for_home;
+ n++;
+ }
+
+ return n;
+}
+
+
+/*
+ * This function takes "skb", consisting of a header template and a
+ * payload, and hands it to LEPP, to emit as one or more segments,
+ * each consisting of a possibly modified header, plus a piece of the
+ * payload, via a process known as "tcp segmentation offload".
+ *
+ * Usually, "data" will contain the header template, of size "sh_len",
+ * and "sh->frags" will contain "skb->data_len" bytes of payload, and
+ * there will be "sh->gso_segs" segments.
+ *
+ * Sometimes, if "sendfile()" requires copying, we will be called with
+ * "data" containing the header and payload, with "frags" being empty.
+ *
+ * In theory, "sh->nr_frags" could be 3, but in practice, it seems
+ * that this will never actually happen.
+ *
+ * See "emulate_large_send_offload()" for some reference code, which
+ * does not handle checksumming.
+ *
+ * ISSUE: How do we make sure that high memory DMA does not migrate?
+ */
+static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+ struct tile_net_stats_t *stats = &info->stats;
+
+ struct skb_shared_info *sh = skb_shinfo(skb);
+
+ unsigned char *data = skb->data;
+
+ /* The ip header follows the ethernet header. */
+ struct iphdr *ih = ip_hdr(skb);
+ unsigned int ih_len = ih->ihl * 4;
+
+ /* Note that "nh == ih", by definition. */
+ unsigned char *nh = skb_network_header(skb);
+ unsigned int eh_len = nh - data;
+
+ /* The tcp header follows the ip header. */
+ struct tcphdr *th = (struct tcphdr *)(nh + ih_len);
+ unsigned int th_len = th->doff * 4;
+
+ /* The total number of header bytes. */
+ /* NOTE: This may be less than skb_headlen(skb). */
+ unsigned int sh_len = eh_len + ih_len + th_len;
+
+ /* The number of payload bytes at "skb->data + sh_len". */
+ /* This is non-zero for sendfile() without HIGHDMA. */
+ unsigned int b_len = skb_headlen(skb) - sh_len;
+
+ /* The total number of payload bytes. */
+ unsigned int d_len = b_len + skb->data_len;
+
+ /* The maximum payload size. */
+ unsigned int p_len = sh->gso_size;
+
+ /* The total number of segments. */
+ unsigned int num_segs = sh->gso_segs;
+
+ /* The temporary copy of the command. */
+ u32 cmd_body[(LEPP_MAX_CMD_SIZE + 3) / 4];
+ lepp_tso_cmd_t *cmd = (lepp_tso_cmd_t *)cmd_body;
+
+ /* Analyze the "frags". */
+ unsigned int num_frags =
+ tile_net_tx_frags(cmd->frags, skb, data + sh_len, b_len);
+
+ /* The size of the command, including frags and header. */
+ size_t cmd_size = LEPP_TSO_CMD_SIZE(num_frags, sh_len);
+
+ /* The command header. */
+ lepp_tso_cmd_t cmd_init = {
+ .tso = true,
+ .header_size = sh_len,
+ .ip_offset = eh_len,
+ .tcp_offset = eh_len + ih_len,
+ .payload_size = p_len,
+ .num_frags = num_frags,
+ };
+
+ unsigned long irqflags;
+
+ lepp_queue_t *eq = priv->epp_queue;
+
+ struct sk_buff *olds[4];
+ unsigned int wanted = 4;
+ unsigned int i, nolds = 0;
+
+ unsigned int cmd_head, cmd_tail, cmd_next;
+ unsigned int comp_tail;
+
+ unsigned int free_slots;
+
+
+ /* Paranoia. */
+ BUG_ON(skb->protocol != htons(ETH_P_IP));
+ BUG_ON(ih->protocol != IPPROTO_TCP);
+ BUG_ON(skb->ip_summed != CHECKSUM_PARTIAL);
+ BUG_ON(num_frags > LEPP_MAX_FRAGS);
+ /*--BUG_ON(num_segs != (d_len + (p_len - 1)) / p_len); */
+ BUG_ON(num_segs <= 1);
+
+
+ /* Finish preparing the command. */
+
+ /* Copy the command header. */
+ *cmd = cmd_init;
+
+ /* Copy the "header". */
+ memcpy(&cmd->frags[num_frags], data, sh_len);
+
+
+ /* Prefetch and wait, to minimize time spent holding the spinlock. */
+ prefetch_L1(&eq->comp_tail);
+ prefetch_L1(&eq->cmd_tail);
+ mb();
+
+
+ /* Enqueue the command. */
+
+ spin_lock_irqsave(&priv->cmd_lock, irqflags);
+
+ /*
+ * Handle completions if needed to make room.
+ * HACK: Spin until there is sufficient room.
+ */
+ free_slots = lepp_num_free_comp_slots(eq);
+ if (free_slots < 1) {
+spin:
+ nolds += tile_net_lepp_grab_comps(dev, olds + nolds,
+ wanted - nolds, NULL);
+ if (lepp_num_free_comp_slots(eq) < 1)
+ goto spin;
+ }
+
+ cmd_head = eq->cmd_head;
+ cmd_tail = eq->cmd_tail;
+
+ /* NOTE: The "gotos" below are untested. */
+
+ /* Prepare to advance, detecting full queue. */
+ cmd_next = cmd_tail + cmd_size;
+ if (cmd_tail < cmd_head && cmd_next >= cmd_head)
+ goto spin;
+ if (cmd_next > LEPP_CMD_LIMIT) {
+ cmd_next = 0;
+ if (cmd_next == cmd_head)
+ goto spin;
+ }
+
+ /* Copy the command. */
+ memcpy(&eq->cmds[cmd_tail], cmd, cmd_size);
+
+ /* Advance. */
+ cmd_tail = cmd_next;
+
+ /* Record "skb" for eventual freeing. */
+ comp_tail = eq->comp_tail;
+ eq->comps[comp_tail] = skb;
+ LEPP_QINC(comp_tail);
+ eq->comp_tail = comp_tail;
+
+ /* Flush before allowing LEPP to handle the command. */
+ __insn_mf();
+
+ eq->cmd_tail = cmd_tail;
+
+ spin_unlock_irqrestore(&priv->cmd_lock, irqflags);
+
+ if (nolds == 0)
+ nolds = tile_net_lepp_grab_comps(dev, olds, wanted, NULL);
+
+ /* Handle completions. */
+ for (i = 0; i < nolds; i++)
+ kfree_skb(olds[i]);
+
+ /* Update stats. */
+ stats->tx_packets += num_segs;
+ stats->tx_bytes += (num_segs * sh_len) + d_len;
+
+ /* Make sure the egress timer is scheduled. */
+ tile_net_schedule_egress_timer(info);
+
+ return NETDEV_TX_OK;
+}
+
+
+/*
+ * Transmit a packet (called by the kernel via "hard_start_xmit" hook).
+ */
+static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+ struct tile_net_stats_t *stats = &info->stats;
+
+ unsigned long irqflags;
+
+ struct skb_shared_info *sh = skb_shinfo(skb);
+
+ unsigned int len = skb->len;
+ unsigned char *data = skb->data;
+
+ unsigned int csum_start = skb->csum_start - skb_headroom(skb);
+
+ lepp_frag_t frags[LEPP_MAX_FRAGS];
+
+ unsigned int num_frags;
+
+ lepp_queue_t *eq = priv->epp_queue;
+
+ struct sk_buff *olds[4];
+ unsigned int wanted = 4;
+ unsigned int i, nolds = 0;
+
+ unsigned int cmd_size = sizeof(lepp_cmd_t);
+
+ unsigned int cmd_head, cmd_tail, cmd_next;
+ unsigned int comp_tail;
+
+ lepp_cmd_t cmds[LEPP_MAX_FRAGS];
+
+ unsigned int free_slots;
+
+
+ /*
+ * This is paranoia, since we think that if the link doesn't come
+ * up, telling Linux we have no carrier will keep it from trying
+ * to transmit. If it does, though, we can't execute this routine,
+ * since data structures we depend on aren't set up yet.
+ */
+ if (!info->registered)
+ return NETDEV_TX_BUSY;
+
+
+ /* Save the timestamp. */
+ dev->trans_start = jiffies;
+
+
+#ifdef TILE_NET_PARANOIA
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (hash_default) {
+ HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)data);
+ if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3)
+ panic("Non-coherent egress buffer!");
+ }
+#endif
+#endif
+
+
+#ifdef TILE_NET_DUMP_PACKETS
+ /* ISSUE: Does not dump the "frags". */
+ dump_packet(data, skb_headlen(skb), "tx");
+#endif /* TILE_NET_DUMP_PACKETS */
+
+
+ if (sh->gso_size != 0)
+ return tile_net_tx_tso(skb, dev);
+
+
+ /* Prepare the commands. */
+
+ num_frags = tile_net_tx_frags(frags, skb, data, skb_headlen(skb));
+
+ for (i = 0; i < num_frags; i++) {
+
+ bool final = (i == num_frags - 1);
+
+ lepp_cmd_t cmd = {
+ .cpa_lo = frags[i].cpa_lo,
+ .cpa_hi = frags[i].cpa_hi,
+ .length = frags[i].length,
+ .hash_for_home = frags[i].hash_for_home,
+ .send_completion = final,
+ .end_of_packet = final
+ };
+
+ if (i == 0 && skb->ip_summed == CHECKSUM_PARTIAL) {
+ cmd.compute_checksum = 1;
+ cmd.checksum_data.bits.start_byte = csum_start;
+ cmd.checksum_data.bits.count = len - csum_start;
+ cmd.checksum_data.bits.destination_byte =
+ csum_start + skb->csum_offset;
+ }
+
+ cmds[i] = cmd;
+ }
+
+
+ /* Prefetch and wait, to minimize time spent holding the spinlock. */
+ prefetch_L1(&eq->comp_tail);
+ prefetch_L1(&eq->cmd_tail);
+ mb();
+
+
+ /* Enqueue the commands. */
+
+ spin_lock_irqsave(&priv->cmd_lock, irqflags);
+
+ /*
+ * Handle completions if needed to make room.
+ * HACK: Spin until there is sufficient room.
+ */
+ free_slots = lepp_num_free_comp_slots(eq);
+ if (free_slots < 1) {
+spin:
+ nolds += tile_net_lepp_grab_comps(dev, olds + nolds,
+ wanted - nolds, NULL);
+ if (lepp_num_free_comp_slots(eq) < 1)
+ goto spin;
+ }
+
+ cmd_head = eq->cmd_head;
+ cmd_tail = eq->cmd_tail;
+
+ /* NOTE: The "gotos" below are untested. */
+
+ /* Copy the commands, or fail. */
+ for (i = 0; i < num_frags; i++) {
+
+ /* Prepare to advance, detecting full queue. */
+ cmd_next = cmd_tail + cmd_size;
+ if (cmd_tail < cmd_head && cmd_next >= cmd_head)
+ goto spin;
+ if (cmd_next > LEPP_CMD_LIMIT) {
+ cmd_next = 0;
+ if (cmd_next == cmd_head)
+ goto spin;
+ }
+
+ /* Copy the command. */
+ *(lepp_cmd_t *)&eq->cmds[cmd_tail] = cmds[i];
+
+ /* Advance. */
+ cmd_tail = cmd_next;
+ }
+
+ /* Record "skb" for eventual freeing. */
+ comp_tail = eq->comp_tail;
+ eq->comps[comp_tail] = skb;
+ LEPP_QINC(comp_tail);
+ eq->comp_tail = comp_tail;
+
+ /* Flush before allowing LEPP to handle the command. */
+ __insn_mf();
+
+ eq->cmd_tail = cmd_tail;
+
+ spin_unlock_irqrestore(&priv->cmd_lock, irqflags);
+
+ if (nolds == 0)
+ nolds = tile_net_lepp_grab_comps(dev, olds, wanted, NULL);
+
+ /* Handle completions. */
+ for (i = 0; i < nolds; i++)
+ kfree_skb(olds[i]);
+
+ /* HACK: Track "expanded" size for short packets (e.g. 42 < 60). */
+ stats->tx_packets++;
+ stats->tx_bytes += ((len >= ETH_ZLEN) ? len : ETH_ZLEN);
+
+ /* Make sure the egress timer is scheduled. */
+ tile_net_schedule_egress_timer(info);
+
+ return NETDEV_TX_OK;
+}
+
+
+/*
+ * Deal with a transmit timeout.
+ */
+static void tile_net_tx_timeout(struct net_device *dev)
+{
+ PDEBUG("tile_net_tx_timeout()\n");
+ PDEBUG("Transmit timeout at %ld, latency %ld\n", jiffies,
+ jiffies - dev->trans_start);
+
+ /* XXX: ISSUE: This doesn't seem useful for us. */
+ netif_wake_queue(dev);
+}
+
+
+/*
+ * Ioctl commands.
+ */
+static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ return -EOPNOTSUPP;
+}
+
+
+/*
+ * Get System Network Statistics.
+ *
+ * Returns the address of the device statistics structure.
+ */
+static struct net_device_stats *tile_net_get_stats(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ u32 rx_packets = 0;
+ u32 tx_packets = 0;
+ u32 rx_bytes = 0;
+ u32 tx_bytes = 0;
+ int i;
+
+ for_each_online_cpu(i) {
+ if (priv->cpu[i]) {
+ rx_packets += priv->cpu[i]->stats.rx_packets;
+ rx_bytes += priv->cpu[i]->stats.rx_bytes;
+ tx_packets += priv->cpu[i]->stats.tx_packets;
+ tx_bytes += priv->cpu[i]->stats.tx_bytes;
+ }
+ }
+
+ priv->stats.rx_packets = rx_packets;
+ priv->stats.rx_bytes = rx_bytes;
+ priv->stats.tx_packets = tx_packets;
+ priv->stats.tx_bytes = tx_bytes;
+
+ return &priv->stats;
+}
+
+
+/*
+ * Change the "mtu".
+ *
+ * The "change_mtu" method is usually not needed.
+ * If you need it, it must be like this.
+ */
+static int tile_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+ PDEBUG("tile_net_change_mtu()\n");
+
+ /* Check ranges. */
+ if ((new_mtu < 68) || (new_mtu > 1500))
+ return -EINVAL;
+
+ /* Accept the value. */
+ dev->mtu = new_mtu;
+
+ return 0;
+}
+
+
+/*
+ * Change the Ethernet Address of the NIC.
+ *
+ * The hypervisor driver does not support changing MAC address. However,
+ * the IPP does not do anything with the MAC address, so the address which
+ * gets used on outgoing packets, and which is accepted on incoming packets,
+ * is completely up to the NetIO program or kernel driver which is actually
+ * handling them.
+ *
+ * Returns 0 on success, negative on failure.
+ */
+static int tile_net_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ /* ISSUE: Note that "dev_addr" is now a pointer. */
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ return 0;
+}
+
+
+/*
+ * Obtain the MAC address from the hypervisor.
+ * This must be done before opening the device.
+ */
+static int tile_net_get_mac(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ char hv_dev_name[32];
+ int len;
+
+ __netio_getset_offset_t offset = { .word = NETIO_IPP_PARAM_OFF };
+
+ int ret;
+
+ /* For example, "xgbe0". */
+ strcpy(hv_dev_name, dev->name);
+ len = strlen(hv_dev_name);
+
+ /* For example, "xgbe/0". */
+ hv_dev_name[len] = hv_dev_name[len - 1];
+ hv_dev_name[len - 1] = '/';
+ len++;
+
+ /* For example, "xgbe/0/native_hash". */
+ strcpy(hv_dev_name + len, hash_default ? "/native_hash" : "/native");
+
+ /* Get the hypervisor handle for this device. */
+ priv->hv_devhdl = hv_dev_open((HV_VirtAddr)hv_dev_name, 0);
+ PDEBUG("hv_dev_open(%s) returned %d %p\n",
+ hv_dev_name, priv->hv_devhdl, &priv->hv_devhdl);
+ if (priv->hv_devhdl < 0) {
+ if (priv->hv_devhdl == HV_ENODEV)
+ printk(KERN_DEBUG "Ignoring unconfigured device %s\n",
+ hv_dev_name);
+ else
+ printk(KERN_DEBUG "hv_dev_open(%s) returned %d\n",
+ hv_dev_name, priv->hv_devhdl);
+ return -1;
+ }
+
+ /*
+ * Read the hardware address from the hypervisor.
+ * ISSUE: Note that "dev_addr" is now a pointer.
+ */
+ offset.bits.class = NETIO_PARAM;
+ offset.bits.addr = NETIO_PARAM_MAC;
+ ret = hv_dev_pread(priv->hv_devhdl, 0,
+ (HV_VirtAddr)dev->dev_addr, dev->addr_len,
+ offset.word);
+ PDEBUG("hv_dev_pread(NETIO_PARAM_MAC) returned %d\n", ret);
+ if (ret <= 0) {
+ printk(KERN_DEBUG "hv_dev_pread(NETIO_PARAM_MAC) %s failed\n",
+ dev->name);
+ /*
+ * Since the device is configured by the hypervisor but we
+ * can't get its MAC address, we are most likely running
+ * the simulator, so let's generate a random MAC address.
+ */
+ random_ether_addr(dev->dev_addr);
+ }
+
+ return 0;
+}
+
+
+static struct net_device_ops tile_net_ops = {
+ .ndo_open = tile_net_open,
+ .ndo_stop = tile_net_stop,
+ .ndo_start_xmit = tile_net_tx,
+ .ndo_do_ioctl = tile_net_ioctl,
+ .ndo_get_stats = tile_net_get_stats,
+ .ndo_change_mtu = tile_net_change_mtu,
+ .ndo_tx_timeout = tile_net_tx_timeout,
+ .ndo_set_mac_address = tile_net_set_mac_address
+};
+
+
+/*
+ * The setup function.
+ *
+ * This uses ether_setup() to assign various fields in dev, including
+ * setting IFF_BROADCAST and IFF_MULTICAST, then sets some extra fields.
+ */
+static void tile_net_setup(struct net_device *dev)
+{
+ PDEBUG("tile_net_setup()\n");
+
+ ether_setup(dev);
+
+ dev->netdev_ops = &tile_net_ops;
+
+ dev->watchdog_timeo = TILE_NET_TIMEOUT;
+
+ /* We want lockless xmit. */
+ dev->features |= NETIF_F_LLTX;
+
+ /* We support hardware tx checksums. */
+ dev->features |= NETIF_F_HW_CSUM;
+
+ /* We support scatter/gather. */
+ dev->features |= NETIF_F_SG;
+
+ /* We support TSO. */
+ dev->features |= NETIF_F_TSO;
+
+#ifdef TILE_NET_GSO
+ /* We support GSO. */
+ dev->features |= NETIF_F_GSO;
+#endif
+
+ if (hash_default)
+ dev->features |= NETIF_F_HIGHDMA;
+
+ /* ISSUE: We should support NETIF_F_UFO. */
+
+ dev->tx_queue_len = TILE_NET_TX_QUEUE_LEN;
+
+ dev->mtu = TILE_NET_MTU;
+}
+
+
+/*
+ * Allocate the device structure, register the device, and obtain the
+ * MAC address from the hypervisor.
+ */
+static struct net_device *tile_net_dev_init(const char *name)
+{
+ int ret;
+ struct net_device *dev;
+ struct tile_net_priv *priv;
+ struct page *page;
+
+ /*
+ * Allocate the device structure. This allocates "priv", calls
+ * tile_net_setup(), and saves "name". Normally, "name" is a
+ * template, instantiated by register_netdev(), but not for us.
+ */
+ dev = alloc_netdev(sizeof(*priv), name, tile_net_setup);
+ if (!dev) {
+ pr_err("alloc_netdev(%s) failed\n", name);
+ return NULL;
+ }
+
+ priv = netdev_priv(dev);
+
+ /* Initialize "priv". */
+
+ memset(priv, 0, sizeof(*priv));
+
+ /* Save "dev" for "tile_net_open_retry()". */
+ priv->dev = dev;
+
+ INIT_DELAYED_WORK(&priv->retry_work, tile_net_open_retry);
+
+ spin_lock_init(&priv->cmd_lock);
+ spin_lock_init(&priv->comp_lock);
+
+ /* Allocate "epp_queue". */
+ BUG_ON(get_order(sizeof(lepp_queue_t)) != 0);
+ page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
+ if (!page) {
+ free_netdev(dev);
+ return NULL;
+ }
+ priv->epp_queue = page_address(page);
+
+ /* Register the network device. */
+ ret = register_netdev(dev);
+ if (ret) {
+ pr_err("register_netdev %s failed %d\n", dev->name, ret);
+ free_page((unsigned long)priv->epp_queue);
+ free_netdev(dev);
+ return NULL;
+ }
+
+ /* Get the MAC address. */
+ ret = tile_net_get_mac(dev);
+ if (ret < 0) {
+ unregister_netdev(dev);
+ free_page((unsigned long)priv->epp_queue);
+ free_netdev(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+
+/*
+ * Module cleanup.
+ */
+static void tile_net_cleanup(void)
+{
+ int i;
+
+ for (i = 0; i < TILE_NET_DEVS; i++) {
+ if (tile_net_devs[i]) {
+ struct net_device *dev = tile_net_devs[i];
+ struct tile_net_priv *priv = netdev_priv(dev);
+ unregister_netdev(dev);
+ finv_buffer(priv->epp_queue, PAGE_SIZE);
+ free_page((unsigned long)priv->epp_queue);
+ free_netdev(dev);
+ }
+ }
+}
+
+
+/*
+ * Module initialization.
+ */
+static int tile_net_init_module(void)
+{
+ pr_info("Tilera IPP Net Driver\n");
+
+ tile_net_devs[0] = tile_net_dev_init("xgbe0");
+ tile_net_devs[1] = tile_net_dev_init("xgbe1");
+ tile_net_devs[2] = tile_net_dev_init("gbe0");
+ tile_net_devs[3] = tile_net_dev_init("gbe1");
+
+ return 0;
+}
+
+
+#ifndef MODULE
+/*
+ * The "network_cpus" boot argument specifies the cpus that are dedicated
+ * to handle ingress packets.
+ *
+ * The parameter should be in the form "network_cpus=m-n[,x-y]", where
+ * m, n, x, y are integer numbers that represent the cpus that can be
+ * neither a dedicated cpu nor a dataplane cpu.
+ */
+static int __init network_cpus_setup(char *str)
+{
+ int rc = cpulist_parse_crop(str, &network_cpus_map);
+ if (rc != 0) {
+ pr_warning("network_cpus=%s: malformed cpu list\n",
+ str);
+ } else {
+
+ /* Remove dedicated cpus. */
+ cpumask_and(&network_cpus_map, &network_cpus_map,
+ cpu_possible_mask);
+
+
+ if (cpumask_empty(&network_cpus_map)) {
+ pr_warning("Ignoring network_cpus='%s'.\n",
+ str);
+ } else {
+ char buf[1024];
+ cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map);
+ pr_info("Linux network CPUs: %s\n", buf);
+ network_cpus_used = true;
+ }
+ }
+
+ return 0;
+}
+__setup("network_cpus=", network_cpus_setup);
+#endif
+
+
+module_init(tile_net_init_module);
+module_exit(tile_net_cleanup);
DMFE_DBUG(0, "dmfe_start_xmit", 0);
- /* Resource flag check */
- netif_stop_queue(dev);
-
/* Too large packet check */
if (skb->len > MAX_PACKET_SIZE) {
pr_err("big packet = %d\n", (u16)skb->len);
return NETDEV_TX_OK;
}
+ /* Resource flag check */
+ netif_stop_queue(dev);
+
spin_lock_irqsave(&db->lock, flags);
/* No Tx resource check, it never happen nromally */
#define UCC_GETH_UTFS_INIT 512 /* Tx virtual FIFO size
*/
#define UCC_GETH_UTFET_INIT 256 /* 1/2 utfs */
-#define UCC_GETH_UTFTT_INIT 512
+#define UCC_GETH_UTFTT_INIT 256 /* 1/2 utfs
+ due to errata */
/* Gigabit Ethernet (1000 Mbps) */
#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/ /* Rx virtual
FIFO size */
/* Packet is complete. Inject into stack. */
/* We have IP packet here */
odev->skb_rx_buf->protocol = cpu_to_be16(ETH_P_IP);
- /* don't check it */
- odev->skb_rx_buf->ip_summed =
- CHECKSUM_UNNECESSARY;
-
skb_reset_mac_header(odev->skb_rx_buf);
/* Ship it off to the kernel */
case HSO_INTF_BULK:
/* It's a regular bulk interface */
- if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) &&
- !disable_net)
- hso_dev = hso_create_net_device(interface, port_spec);
- else
+ if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) {
+ if (!disable_net)
+ hso_dev =
+ hso_create_net_device(interface, port_spec);
+ } else {
hso_dev =
hso_create_bulk_serial_device(interface, port_spec);
+ }
if (!hso_dev)
goto exit;
break;
struct net_device *dev = port->netdev;
card_t* card = port->card;
u8 stat;
+ unsigned count = 0;
spin_lock(&port->lock);
dev->stats.tx_bytes += readw(&desc->len);
}
writeb(0, &desc->stat); /* Free descriptor */
+ count++;
port->txlast = (port->txlast + 1) % card->tx_ring_buffers;
}
- netif_wake_queue(dev);
+ if (count)
+ netif_wake_queue(dev);
spin_unlock(&port->lock);
}
static int x25_asy_close(struct net_device *dev)
{
struct x25_asy *sl = netdev_priv(dev);
- int err;
spin_lock(&sl->lock);
if (sl->tty)
netif_stop_queue(dev);
sl->rcount = 0;
sl->xleft = 0;
- err = lapb_unregister(dev);
- if (err != LAPB_OK)
- printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",
- err);
spin_unlock(&sl->lock);
return 0;
}
if (err)
return err;
/* Done. We have linked the TTY line to a channel. */
- return sl->dev->base_addr;
+ return 0;
}
static void x25_asy_close_tty(struct tty_struct *tty)
{
struct x25_asy *sl = tty->disc_data;
+ int err;
/* First make sure we're connected. */
if (!sl || sl->magic != X25_ASY_MAGIC)
dev_close(sl->dev);
rtnl_unlock();
+ err = lapb_unregister(sl->dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",
+ err);
+
tty->disc_data = NULL;
sl->tty = NULL;
x25_asy_free(sl);
sc->bmisscount = 0;
}
- if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) {
+ if ((sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) ||
+ sc->opmode == NL80211_IFTYPE_MESH_POINT) {
u64 tsf = ath5k_hw_get_tsf64(ah);
u32 tsftu = TSF_TO_TU(tsf);
int slot = ((tsftu % sc->bintval) * ATH_BCBUF) / sc->bintval;
/* NB: hw still stops DMA, so proceed */
}
- /* refresh the beacon for AP mode */
- if (sc->opmode == NL80211_IFTYPE_AP)
+ /* refresh the beacon for AP or MESH mode */
+ if (sc->opmode == NL80211_IFTYPE_AP ||
+ sc->opmode == NL80211_IFTYPE_MESH_POINT)
ath5k_beacon_update(sc->hw, vif);
ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
/* Assign the vap/adhoc to a beacon xmit slot. */
if ((avf->opmode == NL80211_IFTYPE_AP) ||
- (avf->opmode == NL80211_IFTYPE_ADHOC)) {
+ (avf->opmode == NL80211_IFTYPE_ADHOC) ||
+ (avf->opmode == NL80211_IFTYPE_MESH_POINT)) {
int slot;
WARN_ON(list_empty(&sc->bcbuf));
sc->bslot[avf->bslot] = vif;
if (avf->opmode == NL80211_IFTYPE_AP)
sc->num_ap_vifs++;
- else
+ else if (avf->opmode == NL80211_IFTYPE_ADHOC)
sc->num_adhoc_vifs++;
}
#define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */
#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */
+#define CTL(_tpower, _flag) ((_tpower) | ((_flag) << 6))
+
static const struct ar9300_eeprom ar9300_default = {
.eepromVersion = 2,
.templateVersion = 2,
}
},
.ctlPowerData_2G = {
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
- { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
- { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+ { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
- { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
- { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
},
.modalHeader5G = {
/* 4 idle,t1,t2,b (4 bits per setting) */
.ctlPowerData_5G = {
{
{
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
- {60, 1}, {60, 1}, {60, 1}, {60, 0},
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
}
},
{
{
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
- {60, 1}, {60, 1}, {60, 1}, {60, 0},
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
}
},
{
{
- {60, 0}, {60, 1}, {60, 0}, {60, 1},
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
+ CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
}
},
{
{
- {60, 0}, {60, 1}, {60, 1}, {60, 0},
- {60, 1}, {60, 0}, {60, 0}, {60, 0},
+ CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
}
},
{
{
- {60, 1}, {60, 1}, {60, 1}, {60, 0},
- {60, 0}, {60, 0}, {60, 0}, {60, 0},
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
}
},
{
{
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
- {60, 1}, {60, 0}, {60, 0}, {60, 0},
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
}
},
{
{
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
}
},
{
{
- {60, 1}, {60, 1}, {60, 0}, {60, 1},
- {60, 1}, {60, 1}, {60, 1}, {60, 0},
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
}
},
{
{
- {60, 1}, {60, 0}, {60, 1}, {60, 1},
- {60, 1}, {60, 1}, {60, 0}, {60, 1},
+ CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
}
},
}
struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G;
if (is2GHz)
- return ctl_2g[idx].ctlEdges[edge].tPower;
+ return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge]);
else
- return ctl_5g[idx].ctlEdges[edge].tPower;
+ return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge]);
}
static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
if (is2GHz) {
if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq &&
- ctl_2g[idx].ctlEdges[edge - 1].flag)
- return ctl_2g[idx].ctlEdges[edge - 1].tPower;
+ CTL_EDGE_FLAGS(ctl_2g[idx].ctlEdges[edge - 1]))
+ return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge - 1]);
} else {
if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq &&
- ctl_5g[idx].ctlEdges[edge - 1].flag)
- return ctl_5g[idx].ctlEdges[edge - 1].tPower;
+ CTL_EDGE_FLAGS(ctl_5g[idx].ctlEdges[edge - 1]))
+ return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge - 1]);
}
return AR9300_MAX_RATE_POWER;
u8 tPow2x[14];
} __packed;
-struct cal_ctl_edge_pwr {
- u8 tPower:6,
- flag:2;
-} __packed;
-
struct cal_ctl_data_2g {
- struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_2G];
+ u8 ctlEdges[AR9300_NUM_BAND_EDGES_2G];
} __packed;
struct cal_ctl_data_5g {
- struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_5G];
+ u8 ctlEdges[AR9300_NUM_BAND_EDGES_5G];
} __packed;
struct ar9300_eeprom {
#include <linux/device.h>
#include <linux/leds.h>
#include <linux/completion.h>
+#include <linux/pm_qos_params.h>
#include "debug.h"
#include "common.h"
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
int ath_tx_setup(struct ath_softc *sc, int haltype);
-void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
+bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
void ath_draintxq(struct ath_softc *sc,
struct ath_txq *txq, bool retry_tx);
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
struct ath_descdma txsdma;
struct ath_ant_comb ant_comb;
+
+ struct pm_qos_request_list pm_qos_req;
};
struct ath_wiphy {
}
extern struct ieee80211_ops ath9k_ops;
-extern struct pm_qos_request_list ath9k_pm_qos_req;
extern int modparam_nohwcrypt;
extern int led_blink;
for (i = 0; (i < num_band_edges) &&
(pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
- twiceMaxEdgePower = pRdEdgesPower[i].tPower;
+ twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
break;
} else if ((i > 0) &&
(freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
is2GHz))) {
if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
is2GHz) < freq &&
- pRdEdgesPower[i - 1].flag) {
+ CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
twiceMaxEdgePower =
- pRdEdgesPower[i - 1].tPower;
+ CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
}
break;
}
#define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1)
+#define CTL_EDGE_TPOWER(_ctl) ((_ctl) & 0x3f)
+#define CTL_EDGE_FLAGS(_ctl) (((_ctl) >> 6) & 0x03)
+
+#define LNA_CTL_BUF_MODE BIT(0)
+#define LNA_CTL_ISEL_LO BIT(1)
+#define LNA_CTL_ISEL_HI BIT(2)
+#define LNA_CTL_BUF_IN BIT(3)
+#define LNA_CTL_FEM_BAND BIT(4)
+#define LNA_CTL_LOCAL_BIAS BIT(5)
+#define LNA_CTL_FORCE_XPA BIT(6)
+#define LNA_CTL_USE_ANT1 BIT(7)
+
enum eeprom_param {
EEP_NFTHRESH_5,
EEP_NFTHRESH_2,
u8 xatten2Margin[AR5416_MAX_CHAINS];
u8 ob_ch1;
u8 db_ch1;
- u8 useAnt1:1,
- force_xpaon:1,
- local_bias:1,
- femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1;
+ u8 lna_ctl;
u8 miscBits;
u16 xpaBiasLvlFreq[3];
u8 futureModal[6];
u8 tPow2x[8];
} __packed;
-
-#ifdef __BIG_ENDIAN_BITFIELD
-struct cal_ctl_edges {
- u8 bChannel;
- u8 flag:2, tPower:6;
-} __packed;
-#else
struct cal_ctl_edges {
u8 bChannel;
- u8 tPower:6, flag:2;
+ u8 ctl;
} __packed;
-#endif
struct cal_data_op_loop_ar9287 {
u8 pwrPdg[2][5];
int addr, eep_start_loc;
eep_data = (u16 *)eep;
- if (ah->hw_version.devid == 0x7015)
+ if (AR9287_HTC_DEVID(ah))
eep_start_loc = AR9287_HTC_EEP_START_LOC;
else
eep_start_loc = AR9287_EEP_START_LOC;
ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
AR_AN_TOP2_LOCALBIAS,
AR_AN_TOP2_LOCALBIAS_S,
- pModal->local_bias);
+ !!(pModal->lna_ctl &
+ LNA_CTL_LOCAL_BIAS));
REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
- pModal->force_xpaon);
+ !!(pModal->lna_ctl & LNA_CTL_FORCE_XPA));
}
REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
case 1:
break;
case 2:
- scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+ if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
+ scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+ else
+ scaledPower = 0;
break;
case 3:
- scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+ if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
+ scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+ else
+ scaledPower = 0;
break;
}
- scaledPower = max((u16)0, scaledPower);
-
if (IS_CHAN_2GHZ(chan)) {
numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
SUB_NUM_CTL_MODES_AT_2G_40;
num_ant_config = 1;
- if (pBase->version >= 0x0E0D)
- if (pModal->useAnt1)
- num_ant_config += 1;
+ if (pBase->version >= 0x0E0D &&
+ (pModal->lna_ctl & LNA_CTL_USE_ANT1))
+ num_ant_config += 1;
return num_ant_config;
}
{ USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */
{ USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */
{ USB_DEVICE(0x13D3, 0x3346) }, /* IMC Networks */
+ { USB_DEVICE(0x13D3, 0x3348) }, /* Azurewave */
+ { USB_DEVICE(0x13D3, 0x3349) }, /* Azurewave */
+ { USB_DEVICE(0x13D3, 0x3350) }, /* Azurewave */
{ USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
{ USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */
+ { USB_DEVICE(0x040D, 0x3801) }, /* VIA */
+ { USB_DEVICE(0x1668, 0x1200) }, /* Verizon */
{ },
};
case 0x7010:
case 0x7015:
case 0x9018:
+ case 0xA704:
+ case 0x1200:
firm_offset = AR7010_FIRMWARE_TEXT;
break;
default:
case 0x7010:
case 0x7015:
case 0x9018:
+ case 0xA704:
+ case 0x1200:
if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
hif_dev->fw_name = FIRMWARE_AR7010_1_1;
else
struct hif_device_usb *hif_dev =
(struct hif_device_usb *) usb_get_intfdata(interface);
+ /*
+ * The device has to be set to FULLSLEEP mode in case no
+ * interface is up.
+ */
+ if (!(hif_dev->flags & HIF_USB_START))
+ ath9k_htc_suspend(hif_dev->htc_handle);
+
ath9k_hif_usb_dealloc_urbs(hif_dev);
return 0;
void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv);
void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv);
void ath9k_ps_work(struct work_struct *work);
+bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
+ enum ath9k_power_mode mode);
void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
void ath9k_init_leds(struct ath9k_htc_priv *priv);
u16 devid, char *product);
void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug);
#ifdef CONFIG_PM
+void ath9k_htc_suspend(struct htc_target *htc_handle);
int ath9k_htc_resume(struct htc_target *htc_handle);
#endif
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
case 0x7010:
case 0x7015:
case 0x9018:
+ case 0xA704:
+ case 0x1200:
priv->htc->credits = 45;
break;
default:
}
#ifdef CONFIG_PM
+
+void ath9k_htc_suspend(struct htc_target *htc_handle)
+{
+ ath9k_htc_setpower(htc_handle->drv_priv, ATH9K_PM_FULL_SLEEP);
+}
+
int ath9k_htc_resume(struct htc_target *htc_handle)
{
int ret;
return mode;
}
-static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
- enum ath9k_power_mode mode)
+bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
+ enum ath9k_power_mode mode)
{
bool ret;
tx_hdr.data_type = ATH9K_HTC_NORMAL;
}
- if (ieee80211_is_data(fc)) {
+ if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
}
val = REG_READ(ah, AR7010_GPIO_IN);
return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0;
} else if (AR_SREV_9300_20_OR_LATER(ah))
- return MS_REG_READ(AR9300, gpio) != 0;
+ return (MS(REG_READ(ah, AR_GPIO_IN), AR9300_GPIO_IN_VAL) &
+ AR_GPIO_BIT(gpio)) != 0;
else if (AR_SREV_9271(ah))
return MS_REG_READ(AR9271, gpio) != 0;
else if (AR_SREV_9287_11_OR_LATER(ah))
*/
#include <linux/slab.h>
-#include <linux/pm_qos_params.h>
#include "ath9k.h"
.write = ath9k_iowrite32,
};
-struct pm_qos_request_list ath9k_pm_qos_req;
-
/**************************/
/* Initialization */
/**************************/
hw->flags |= IEEE80211_HW_MFP_CAPABLE;
hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_WDS) |
BIT(NL80211_IFTYPE_STATION) |
ath_init_leds(sc);
ath_start_rfkill_poll(sc);
- pm_qos_add_request(&ath9k_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+ pm_qos_add_request(&sc->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
return 0;
ath9k_ps_wakeup(sc);
- pm_qos_remove_request(&ath9k_pm_qos_req);
-
wiphy_rfkill_stop_polling(sc->hw->wiphy);
ath_deinit_leds(sc);
}
ieee80211_unregister_hw(hw);
+ pm_qos_remove_request(&sc->pm_qos_req);
ath_rx_cleanup(sc);
ath_tx_cleanup(sc);
ath9k_deinit_softc(sc);
rs->rs_phyerr = phyerr;
} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
rs->rs_status |= ATH9K_RXERR_DECRYPT;
- else if ((ads.ds_rxstatus8 & AR_MichaelErr) &&
- rs->rs_keyix != ATH9K_RXKEYIX_INVALID)
+ else if (ads.ds_rxstatus8 & AR_MichaelErr)
rs->rs_status |= ATH9K_RXERR_MIC;
else if (ads.ds_rxstatus8 & AR_KeyMiss)
rs->rs_status |= ATH9K_RXERR_DECRYPT;
*/
#include <linux/nl80211.h>
-#include <linux/pm_qos_params.h>
#include "ath9k.h"
#include "btcoex.h"
* the relevant bits of the h/w.
*/
ath9k_hw_set_interrupts(ah, 0);
- ath_drain_all_txq(sc, false);
+ stopped = ath_drain_all_txq(sc, false);
spin_lock_bh(&sc->rx.pcu_lock);
- stopped = ath_stoprecv(sc);
+ if (!ath_stoprecv(sc))
+ stopped = false;
/* XXX: do not flush receive queue here. We don't want
* to flush data frames already in queue because of
ath9k_btcoex_timer_resume(sc);
}
- pm_qos_update_request(&ath9k_pm_qos_req, 55);
+ pm_qos_update_request(&sc->pm_qos_req, 55);
mutex_unlock:
mutex_unlock(&sc->mutex);
sc->sc_flags |= SC_OP_INVALID;
- pm_qos_update_request(&ath9k_pm_qos_req, PM_QOS_DEFAULT_VALUE);
+ pm_qos_update_request(&sc->pm_qos_req, PM_QOS_DEFAULT_VALUE);
mutex_unlock(&sc->mutex);
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
- int i;
ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
(sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
(sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) {
+ /* Disable SWBA interrupt */
+ sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
ath9k_ps_wakeup(sc);
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
ath9k_ps_restore(sc);
+ tasklet_kill(&sc->bcon_tasklet);
}
ath_beacon_return(sc, avp);
sc->sc_flags &= ~SC_OP_BEACONS;
- for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
- if (sc->beacon.bslot[i] == vif) {
- printk(KERN_DEBUG "%s: vif had allocated beacon "
- "slot\n", __func__);
- sc->beacon.bslot[i] = NULL;
- sc->beacon.bslot_aphy[i] = NULL;
- }
+ if (sc->nbcnvifs) {
+ /* Re-enable SWBA interrupt */
+ sc->sc_ah->imask |= ATH9K_INT_SWBA;
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
+ ath9k_ps_restore(sc);
}
sc->nvifs--;
bool stopped;
spin_lock_bh(&sc->rx.rxbuflock);
- ath9k_hw_stoppcurecv(ah);
+ ath9k_hw_abortpcurecv(ah);
ath9k_hw_setrxfilter(ah, 0);
stopped = ath9k_hw_stopdmarecv(ah);
struct ath_rx_status *rx_stats,
bool *decrypt_error)
{
+#define is_mc_or_valid_tkip_keyix ((is_mc || \
+ (rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && \
+ test_bit(rx_stats->rs_keyix, common->tkip_keymap))))
+
struct ath_hw *ah = common->ah;
__le16 fc;
u8 rx_status_len = ah->caps.rx_status_len;
if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
*decrypt_error = true;
} else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
+ bool is_mc;
/*
* The MIC error bit is only valid if the frame
* is not a control frame or fragment, and it was
* decrypted using a valid TKIP key.
*/
+ is_mc = !!is_multicast_ether_addr(hdr->addr1);
+
if (!ieee80211_is_ctl(fc) &&
!ieee80211_has_morefrags(fc) &&
!(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
- test_bit(rx_stats->rs_keyix, common->tkip_keymap))
+ is_mc_or_valid_tkip_keyix)
rxs->flag |= RX_FLAG_MMIC_ERROR;
else
rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
#define AR_DEVID_7010(_ah) \
(((_ah)->hw_version.devid == 0x7010) || \
((_ah)->hw_version.devid == 0x7015) || \
- ((_ah)->hw_version.devid == 0x9018))
+ ((_ah)->hw_version.devid == 0x9018) || \
+ ((_ah)->hw_version.devid == 0xA704) || \
+ ((_ah)->hw_version.devid == 0x1200))
+
+#define AR9287_HTC_DEVID(_ah) \
+ (((_ah)->hw_version.devid == 0x7015) || \
+ ((_ah)->hw_version.devid == 0x1200))
#define AR_RADIO_SREV_MAJOR 0xf0
#define AR_RAD5133_SREV_MAJOR 0xc0
#define AR9287_GPIO_IN_VAL_S 11
#define AR9271_GPIO_IN_VAL 0xFFFF0000
#define AR9271_GPIO_IN_VAL_S 16
-#define AR9300_GPIO_IN_VAL 0x0001FFFF
-#define AR9300_GPIO_IN_VAL_S 0
#define AR7010_GPIO_IN_VAL 0x0000FFFF
#define AR7010_GPIO_IN_VAL_S 0
+#define AR_GPIO_IN 0x404c
+#define AR9300_GPIO_IN_VAL 0x0001FFFF
+#define AR9300_GPIO_IN_VAL_S 0
+
#define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)
#define AR_GPIO_OE_OUT_DRV 0x3
#define AR_GPIO_OE_OUT_DRV_NO 0x0
}
}
-void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
+bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int i, npend = 0;
if (sc->sc_flags & SC_OP_INVALID)
- return;
+ return true;
/* Stop beacon queue */
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
}
}
- if (npend) {
- int r;
-
- ath_print(common, ATH_DBG_FATAL,
- "Failed to stop TX DMA. Resetting hardware!\n");
-
- spin_lock_bh(&sc->sc_resetlock);
- r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
- if (r)
- ath_print(common, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d\n",
- r);
- spin_unlock_bh(&sc->sc_resetlock);
- }
+ if (npend)
+ ath_print(common, ATH_DBG_FATAL, "Failed to stop TX DMA!\n");
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i))
ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
}
+
+ return !npend;
}
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
if (SUPP(CARL9170FW_WLANTX_CAB)) {
ar->hw->wiphy->interface_modes |=
- BIT(NL80211_IFTYPE_AP);
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO);
}
}
}
unlock:
- if (err && (vif_id != -1)) {
+ if (err && (vif_id >= 0)) {
vif_priv->active = false;
bitmap_release_region(&ar->vif_bitmap, vif_id, 0);
ar->vifs--;
* supports these modes. The code which will add the
* additional interface_modes is in fw.c.
*/
- hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT);
hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
mac_tmp = cpu_to_le16(AR9170_TX_MAC_HW_DURATION |
AR9170_TX_MAC_BACKOFF);
- mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) &&
+ mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) &
AR9170_TX_MAC_QOS);
no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK);
usb_free_urb(urb);
}
- ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, HZ);
+ ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, 1000);
if (ret == 0)
err = -ETIMEDOUT;
/* lets wait a while until the tx - queues are dried out */
- ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, HZ);
+ ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, 1000);
if (ret == 0)
err = -ETIMEDOUT;
err_free_ssb:
kfree(sdio);
err_disable_func:
+ sdio_claim_host(func);
sdio_disable_func(func);
err_release_host:
sdio_release_host(func);
lbs_deb_sdio("call remove card\n");
lbs_stop_card(card->priv);
lbs_remove_card(card->priv);
- card->priv->surpriseremoved = 1;
flush_workqueue(card->workqueue);
destroy_workqueue(card->workqueue);
lbs_stop_card(priv);
lbs_remove_card(priv); /* will call free_netdev */
- priv->surpriseremoved = 1;
free_irq(spi->irq, card);
if_spi_terminate_spi_thread(card);
if (card->pdata->teardown)
lbs_free_adapter(priv);
lbs_cfg_free(priv);
-
- priv->dev = NULL;
free_netdev(dev);
lbs_deb_leave(LBS_DEB_MAIN);
orinoco_add_hostscan_results(priv, buf, len);
kfree(buf);
- } else if (priv->scan_request) {
+ } else {
/* Either abort or complete the scan */
- cfg80211_scan_done(priv->scan_request, (len < 0));
- priv->scan_request = NULL;
+ orinoco_scan_done(priv, (len < 0));
}
spin_lock_irqsave(&priv->scan_lock, flags);
hermes_write_regn(hw, EVACK, 0xffff);
}
+ orinoco_scan_done(priv, true);
+
/* firmware will have to reassociate */
netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
orinoco_unlock(priv, &flags);
/* Scanning support: Notify scan cancellation */
- if (priv->scan_request) {
- cfg80211_scan_done(priv->scan_request, 1);
- priv->scan_request = NULL;
- }
+ orinoco_scan_done(priv, true);
if (priv->hard_reset) {
err = (*priv->hard_reset)(priv);
struct net_device *dev = priv->ndev;
int err = 0;
+ /* If we've called commit, we are reconfiguring or bringing the
+ * interface up. Maintaining countermeasures across this would
+ * be confusing, so note that we've disabled them. The port will
+ * be enabled later in orinoco_commit or __orinoco_up. */
+ priv->tkip_cm_active = 0;
+
err = orinoco_hw_program_rids(priv);
/* FIXME: what about netif_tx_lock */
goto failed;
}
- ret = pcmcia_request_irq(link, orinoco_interrupt);
- if (ret)
- goto failed;
-
- /* We initialize the hermes structure before completing PCMCIA
- * configuration just in case the interrupt handler gets
- * called. */
mem = ioport_map(link->resource[0]->start,
resource_size(link->resource[0]));
if (!mem)
goto failed;
+ /* We initialize the hermes structure before completing PCMCIA
+ * configuration just in case the interrupt handler gets
+ * called. */
hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+ ret = pcmcia_request_irq(link, orinoco_interrupt);
+ if (ret)
+ goto failed;
+
ret = pcmcia_enable_device(link);
if (ret)
goto failed;
#include <linux/fcntl.h>
#include <linux/spinlock.h>
#include <linux/list.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/timer.h>
priv->scan_request = NULL;
}
}
+
+void orinoco_scan_done(struct orinoco_private *priv, bool abort)
+{
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, abort);
+ priv->scan_request = NULL;
+ }
+}
void orinoco_add_hostscan_results(struct orinoco_private *dev,
unsigned char *buf,
size_t len);
+void orinoco_scan_done(struct orinoco_private *priv, bool abort);
#endif /* _ORINOCO_SCAN_H_ */
goto failed;
}
- ret = pcmcia_request_irq(link, orinoco_interrupt);
- if (ret)
- goto failed;
-
- /* We initialize the hermes structure before completing PCMCIA
- * configuration just in case the interrupt handler gets
- * called. */
mem = ioport_map(link->resource[0]->start,
resource_size(link->resource[0]));
if (!mem)
goto failed;
+ /* We initialize the hermes structure before completing PCMCIA
+ * configuration just in case the interrupt handler gets
+ * called. */
hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
hw->eeprom_pda = true;
+ ret = pcmcia_request_irq(link, orinoco_interrupt);
+ if (ret)
+ goto failed;
+
ret = pcmcia_enable_device(link);
if (ret)
goto failed;
*/
if (param->value) {
priv->tkip_cm_active = 1;
- ret = hermes_enable_port(hw, 0);
+ ret = hermes_disable_port(hw, 0);
} else {
priv->tkip_cm_active = 0;
- ret = hermes_disable_port(hw, 0);
+ ret = hermes_enable_port(hw, 0);
}
break;
#define GRANT_INVALID_REF 0
-#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
-#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+#define NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE)
+#define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE)
#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
struct netfront_info {
.name = "GSC-PCI",
.unmask = dino_unmask_irq,
.mask = dino_mask_irq,
- .ack = no_ack_irq,
};
.name = "EISA",
.unmask = eisa_unmask_irq,
.mask = eisa_mask_irq,
- .ack = no_ack_irq,
};
static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
setup_irq(2, &irq2_action);
for (i = 0; i < 16; i++) {
set_irq_chip_and_handler(i, &eisa_interrupt_type,
- handle_level_irq);
+ handle_simple_irq);
}
EISA_bus = 1;
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
.name = "GSC-ASIC",
.unmask = gsc_asic_unmask_irq,
.mask = gsc_asic_mask_irq,
- .ack = no_ack_irq,
};
int gsc_assign_irq(struct irq_chip *type, void *data)
if (irq > GSC_IRQ_MAX)
return NO_IRQ;
- set_irq_chip_and_handler(irq, type, handle_level_irq);
+ set_irq_chip_and_handler(irq, type, handle_simple_irq);
set_irq_chip_data(irq, data);
return irq++;
DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", irq,
vi->eoi_addr, vi->eoi_data);
iosapic_eoi(vi->eoi_addr, vi->eoi_data);
+}
+
+static void iosapic_eoi_irq(unsigned int irq)
+{
+ struct vector_info *vi = get_irq_chip_data(irq);
+
+ iosapic_eoi(vi->eoi_addr, vi->eoi_data);
cpu_eoi_irq(irq);
}
.unmask = iosapic_unmask_irq,
.mask = iosapic_mask_irq,
.ack = cpu_ack_irq,
+ .eoi = iosapic_eoi_irq,
#ifdef CONFIG_SMP
.set_affinity = iosapic_set_affinity_irq,
#endif
static unsigned int led_lanrxtx __read_mostly = 1;
static char lcd_text[32] __read_mostly;
static char lcd_text_default[32] __read_mostly;
+static int lcd_no_led_support __read_mostly = 0; /* KittyHawk doesn't support LED on its LCD */
static struct workqueue_struct *led_wq;
.lcd_width = 16,
.lcd_cmd_reg_addr = KITTYHAWK_LCD_CMD,
.lcd_data_reg_addr = KITTYHAWK_LCD_DATA,
- .min_cmd_delay = 40,
+ .min_cmd_delay = 80,
.reset_cmd1 = 0x80,
.reset_cmd2 = 0xc0,
};
/* Display the default text now */
if (led_type == LED_HASLCD) lcd_print( lcd_text_default );
+ /* KittyHawk has no LED support on its LCD */
+ if (lcd_no_led_support) return 0;
+
/* Create the work queue and queue the LED task */
led_wq = create_singlethread_workqueue("led_wq");
queue_delayed_work(led_wq, &led_task, 0);
proc_pdc_root = proc_mkdir("pdc", 0);
if (!proc_pdc_root) return -1;
- ent = proc_create_data("led", S_IRUGO|S_IWUSR, proc_pdc_root,
- &led_proc_fops, (void *)LED_NOLCD); /* LED */
- if (!ent) return -1;
+
+ if (!lcd_no_led_support)
+ {
+ ent = proc_create_data("led", S_IRUGO|S_IWUSR, proc_pdc_root,
+ &led_proc_fops, (void *)LED_NOLCD); /* LED */
+ if (!ent) return -1;
+ }
if (led_type == LED_HASLCD)
{
case 0x58B: /* KittyHawk DC2 100 (K200) */
printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, "
"LED detection skipped.\n", __FILE__, CPU_HVERSION);
+ lcd_no_led_support = 1;
goto found; /* use the preinitialized values of lcd_info */
}
.name = SUPERIO,
.unmask = superio_unmask_irq,
.mask = superio_mask_irq,
- .ack = no_ack_irq,
};
#ifdef DEBUG_SUPERIO_INIT
#endif
for (i = 0; i < 16; i++) {
- set_irq_chip_and_handler(i, &superio_interrupt_type, handle_level_irq);
+ set_irq_chip_and_handler(i, &superio_interrupt_type, handle_simple_irq);
}
/*
obj-$(CONFIG_X86_VISWS) += setup-irq.o
obj-$(CONFIG_MN10300) += setup-bus.o
obj-$(CONFIG_MICROBLAZE) += setup-bus.o
+obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o
#
# ACPI Related PCI FW Functions
nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
start = vma->vm_pgoff;
size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
- pci_start = (mmap_api == PCI_MMAP_SYSFS) ?
+ pci_start = (mmap_api == PCI_MMAP_PROCFS) ?
pci_resource_start(pdev, resno) >> PAGE_SHIFT : 0;
if (start >= pci_start && start < pci_start + size &&
start + nr <= pci_start + size)
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/capability.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB,
quirk_unhide_mch_dev6);
+#ifdef CONFIG_TILE
+/*
+ * The Tilera TILEmpower platform needs to set the link speed
+ * to 2.5GT(Giga-Transfers)/s (Gen 1). The default link speed
+ * setting is 5GT/s (Gen 2). 0x98 is the Link Control2 PCIe
+ * capability register of the PEX8624 PCIe switch. The switch
+ * supports link speed auto negotiation, but falsely sets
+ * the link speed to 5GT/s.
+ */
+static void __devinit quirk_tile_plx_gen1(struct pci_dev *dev)
+{
+ if (tile_plx_gen1) {
+ pci_write_config_dword(dev, 0x98, 0x1);
+ mdelay(50);
+ }
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8624, quirk_tile_plx_gen1);
+#endif /* CONFIG_TILE */
#ifdef CONFIG_PCI_MSI
/* Some chipsets do not support MSI. We cannot easily rely on setting
va_end(args);
}
}
+EXPORT_SYMBOL(soc_pcmcia_debug);
#endif
static int wlan_status = 1;
static int bluetooth_status = 1;
+static int wimax_status = -1;
+static int wwan_status = -1;
module_param(wlan_status, int, 0444);
MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
"default is 1");
+module_param(wimax_status, int, 0444);
+MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot "
+ "(0 = disabled, 1 = enabled, -1 = don't do anything). "
+ "default is 1");
+
+module_param(wwan_status, int, 0444);
+MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
+ "(0 = disabled, 1 = enabled, -1 = don't do anything). "
+ "default is 1");
+
/*
* Some events we use, same for all Asus
*/
*/
#define WL_RSTS 0x01 /* internal Wifi */
#define BT_RSTS 0x02 /* internal Bluetooth */
+#define WM_RSTS 0x08 /* internal wimax */
+#define WW_RSTS 0x20 /* internal wwan */
/* LED */
#define METHOD_MLED "MLED"
*/
#define METHOD_WLAN "WLED"
#define METHOD_BLUETOOTH "BLED"
+
+/* WWAN and WIMAX */
+#define METHOD_WWAN "GSMC"
+#define METHOD_WIMAX "WMXC"
+
#define METHOD_WL_STATUS "RSTS"
/* Brightness */
return sysfs_acpi_set(asus, buf, count, METHOD_BLUETOOTH);
}
+/*
+ * Wimax
+ */
+static int asus_wimax_set(struct asus_laptop *asus, int status)
+{
+ if (write_acpi_int(asus->handle, METHOD_WIMAX, !!status)) {
+ pr_warning("Error setting wimax status to %d", status);
+ return -EIO;
+ }
+ return 0;
+}
+
+static ssize_t show_wimax(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS));
+}
+
+static ssize_t store_wimax(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sysfs_acpi_set(asus, buf, count, METHOD_WIMAX);
+}
+
+/*
+ * Wwan
+ */
+static int asus_wwan_set(struct asus_laptop *asus, int status)
+{
+ if (write_acpi_int(asus->handle, METHOD_WWAN, !!status)) {
+ pr_warning("Error setting wwan status to %d", status);
+ return -EIO;
+ }
+ return 0;
+}
+
+static ssize_t show_wwan(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS));
+}
+
+static ssize_t store_wwan(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sysfs_acpi_set(asus, buf, count, METHOD_WWAN);
+}
+
/*
* Display
*/
static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan);
static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
show_bluetooth, store_bluetooth);
+static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
+static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp);
static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
&dev_attr_infos.attr,
&dev_attr_wlan.attr,
&dev_attr_bluetooth.attr,
+ &dev_attr_wimax.attr,
+ &dev_attr_wwan.attr,
&dev_attr_display.attr,
&dev_attr_ledd.attr,
&dev_attr_ls_level.attr,
} else if (attr == &dev_attr_display.attr) {
supported = !acpi_check_handle(handle, METHOD_SWITCH_DISPLAY, NULL);
+ } else if (attr == &dev_attr_wimax.attr) {
+ supported =
+ !acpi_check_handle(asus->handle, METHOD_WIMAX, NULL);
+
+ } else if (attr == &dev_attr_wwan.attr) {
+ supported = !acpi_check_handle(asus->handle, METHOD_WWAN, NULL);
+
} else if (attr == &dev_attr_ledd.attr) {
supported = !acpi_check_handle(handle, METHOD_LEDD, NULL);
/*
* The HWRS method return informations about the hardware.
- * 0x80 bit is for WLAN, 0x100 for Bluetooth.
+ * 0x80 bit is for WLAN, 0x100 for Bluetooth,
+ * 0x40 for WWAN, 0x10 for WIMAX.
* The significance of others is yet to be found.
*/
status =
if (wlan_status >= 0)
asus_wlan_set(asus, !!wlan_status);
+ if (wimax_status >= 0)
+ asus_wimax_set(asus, !!wimax_status);
+
+ if (wwan_status >= 0)
+ asus_wwan_set(asus, !!wwan_status);
+
/* Keyboard Backlight is on by default */
if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL))
asus_kled_set(asus, 1);
kfree(obj);
}
-static int store_cpufv(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
int value;
struct acpi_buffer input = { (acpi_size)sizeof(value), &value };
bios_return = *((struct bios_return *)obj->buffer.pointer);
memcpy(buffer, &bios_return.value, sizeof(bios_return.value));
+
+ kfree(obj);
return 0;
}
#include <linux/io.h>
#include <linux/sysdev.h>
#include <linux/dmi.h>
+#include <linux/efi.h>
#include <linux/mutex.h>
#include <asm/bios_ebda.h>
sysdev_class_unregister(&class_rtl);
}
-static int dmi_check_cb(const struct dmi_system_id *id)
-{
- RTL_DEBUG("found IBM server '%s'\n", id->ident);
- return 0;
-}
-
-#define ibm_dmi_entry(NAME, TYPE) \
-{ \
- .ident = NAME, \
- .matches = { \
- DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
- DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \
- }, \
- .callback = dmi_check_cb \
-}
static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
- ibm_dmi_entry("BladeCenter LS21", "7971"),
- ibm_dmi_entry("BladeCenter LS22", "7901"),
- ibm_dmi_entry("BladeCenter HS21 XM", "7995"),
- ibm_dmi_entry("BladeCenter HS22", "7870"),
- ibm_dmi_entry("BladeCenter HS22V", "7871"),
- ibm_dmi_entry("System x3550 M2", "7946"),
- ibm_dmi_entry("System x3650 M2", "7947"),
- ibm_dmi_entry("System x3550 M3", "7944"),
- ibm_dmi_entry("System x3650 M3", "7945"),
+ { \
+ .matches = { \
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
+ }, \
+ },
{ }
};
if (force)
pr_warning("ibm-rtl: module loaded by force\n");
/* first ensure that we are running on IBM HW */
- else if (!dmi_check_system(ibm_rtl_dmi_table))
+ else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table))
return -ENODEV;
/* Get the address for the Extended BIOS Data Area */
RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
rtl_cmd_width, rtl_cmd_type);
addr = ioread32(&rtl_table->cmd_port_address);
- RTL_DEBUG("addr = %#llx\n", addr);
+ RTL_DEBUG("addr = %#llx\n", (unsigned long long)addr);
plen = rtl_cmd_width/sizeof(char);
rtl_cmd_addr = rtl_port_map(addr, plen);
RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
#define dprintk(msg...) pr_debug(DRV_PFX msg)
-#define KEYCODE_BASE 0xD0
-#define MSI_WMI_BRIGHTNESSUP KEYCODE_BASE
-#define MSI_WMI_BRIGHTNESSDOWN (KEYCODE_BASE + 1)
-#define MSI_WMI_VOLUMEUP (KEYCODE_BASE + 2)
-#define MSI_WMI_VOLUMEDOWN (KEYCODE_BASE + 3)
+#define SCANCODE_BASE 0xD0
+#define MSI_WMI_BRIGHTNESSUP SCANCODE_BASE
+#define MSI_WMI_BRIGHTNESSDOWN (SCANCODE_BASE + 1)
+#define MSI_WMI_VOLUMEUP (SCANCODE_BASE + 2)
+#define MSI_WMI_VOLUMEDOWN (SCANCODE_BASE + 3)
+#define MSI_WMI_MUTE (SCANCODE_BASE + 4)
static struct key_entry msi_wmi_keymap[] = {
{ KE_KEY, MSI_WMI_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} },
{ KE_KEY, MSI_WMI_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} },
{ KE_KEY, MSI_WMI_VOLUMEUP, {KEY_VOLUMEUP} },
{ KE_KEY, MSI_WMI_VOLUMEDOWN, {KEY_VOLUMEDOWN} },
+ { KE_KEY, MSI_WMI_MUTE, {KEY_MUTE} },
{ KE_END, 0}
};
static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1];
ktime_t diff;
cur = ktime_get_real();
diff = ktime_sub(cur, last_pressed[key->code -
- KEYCODE_BASE]);
+ SCANCODE_BASE]);
/* Ignore event if the same event happened in a 50 ms
timeframe -> Key press may result in 10-20 GPEs */
if (ktime_to_us(diff) < 1000 * 50) {
key->code, ktime_to_us(diff));
return;
}
- last_pressed[key->code - KEYCODE_BASE] = cur;
+ last_pressed[key->code - SCANCODE_BASE] = cur;
if (key->type == KE_KEY &&
/* Brightness is served via acpi video driver */
ibm->acpi->type,
dispatch_acpi_notify);
ibm->flags.acpi_notify_installed = 0;
- ibm->flags.acpi_notify_installed = 0;
}
if (ibm->flags.proc_created) {
{ KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
{ KE_KEY, 0x142, { KEY_WLAN } },
{ KE_KEY, 0x143, { KEY_PROG1 } },
+ { KE_KEY, 0x17f, { KEY_FN } },
{ KE_KEY, 0xb05, { KEY_PROG2 } },
{ KE_KEY, 0xb06, { KEY_WWW } },
{ KE_KEY, 0xb07, { KEY_MAIL } },
struct wmi_block *wblock;
list_for_each_entry(wblock, &wmi_block_list, list)
- if (strncmp(wblock->gblock.guid, guid_string, 16) == 0)
+ if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
return true;
return false;
#include <linux/isapnp.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
extern struct pnp_protocol isapnp_protocol;
};
EXPORT_SYMBOL(pnpacpi_protocol);
-static char *pnpacpi_get_id(struct acpi_device *device)
+static char *__init pnpacpi_get_id(struct acpi_device *device)
{
struct acpi_hardware_id *id;
}
/**
- * set_consumer_device_supply: Bind a regulator to a symbolic supply
+ * set_consumer_device_supply - Bind a regulator to a symbolic supply
* @rdev: regulator source
* @consumer_dev: device the supply applies to
* @consumer_dev_name: dev_name() string for device supply applies to
printk(KERN_WARNING
"%s: could not add device link %s err %d\n",
__func__, dev->kobj.name, err);
- device_remove_file(dev, ®ulator->dev_attr);
goto link_name_err;
}
}
{
int ret, delay;
- /* do we need to enable the supply regulator first */
- if (rdev->supply) {
- ret = _regulator_enable(rdev->supply);
- if (ret < 0) {
- printk(KERN_ERR "%s: failed to enable %s: %d\n",
- __func__, rdev_get_name(rdev), ret);
- return ret;
+ if (rdev->use_count == 0) {
+ /* do we need to enable the supply regulator first */
+ if (rdev->supply) {
+ mutex_lock(&rdev->supply->mutex);
+ ret = _regulator_enable(rdev->supply);
+ mutex_unlock(&rdev->supply->mutex);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to enable %s: %d\n",
+ __func__, rdev_get_name(rdev), ret);
+ return ret;
+ }
}
}
if (ret < 0)
return ret;
- if (delay >= 1000)
+ if (delay >= 1000) {
mdelay(delay / 1000);
- else if (delay)
+ udelay(delay % 1000);
+ } else if (delay) {
udelay(delay);
+ }
} else if (ret < 0) {
printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",
struct regulator_dev **supply_rdev_ptr)
{
int ret = 0;
+ *supply_rdev_ptr = NULL;
if (WARN(rdev->use_count <= 0,
"unbalanced disables for %s\n",
if (init_data->supply_regulator && init_data->supply_regulator_dev) {
dev_err(dev,
"Supply regulator specified by both name and dev\n");
+ ret = -EINVAL;
goto scrub;
}
if (!found) {
dev_err(dev, "Failed to find supply %s\n",
init_data->supply_regulator);
+ ret = -ENODEV;
goto scrub;
}
.get_voltage = mc13783_fixed_regulator_get_voltage,
};
-int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask,
- u32 val)
+static int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask,
+ u32 val)
{
struct mc13783 *mc13783 = priv->mc13783;
int ret;
};
#define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
-{ \
+ ereg0, ebit0, ereg1, ebit1) \
.desc = { \
.name = "REG-" #_id, \
.ops = &tps6586x_regulator_##_ops, \
.enable_bit[0] = (ebit0), \
.enable_reg[1] = TPS6586X_SUPPLY##ereg1, \
.enable_bit[1] = (ebit1), \
- .voltages = tps6586x_##vdata##_voltages, \
-}
+ .voltages = tps6586x_##vdata##_voltages,
+
+#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
+ .go_reg = TPS6586X_##goreg, \
+ .go_bit = (gobit),
#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
+{ \
TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1, 0, 0)
+ ereg0, ebit0, ereg1, ebit1) \
+}
#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
+{ \
TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1, goreg, gobit)
+ ereg0, ebit0, ereg1, ebit1) \
+ TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
+}
static struct tps6586x_regulator tps6586x_regulator[] = {
TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0),
TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
- TPS6586X_LDO(LDO_8, ldo, SUPPLYV1, 5, 3, ENC, 6, END, 6),
+ TPS6586X_LDO(LDO_8, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6),
TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
- TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, ENE, 7, ENE, 7),
+ TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
- TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 1, END, 1),
+ TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6),
TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6),
uint8_t val1, val2;
int ret;
+ if (ri->enable_reg[0] == ri->enable_reg[1] &&
+ ri->enable_bit[0] == ri->enable_bit[1])
+ return 0;
+
ret = tps6586x_read(parent, ri->enable_reg[0], &val1);
if (ret)
return ret;
if (ret)
return ret;
- if (!(val2 & ri->enable_bit[1]))
+ if (!(val2 & (1 << ri->enable_bit[1])))
return 0;
/*
* The regulator is on, but it's enabled with the bit we don't
* want to use, so we switch the enable bits
*/
- if (!(val1 & ri->enable_bit[0])) {
+ if (!(val1 & (1 << ri->enable_bit[0]))) {
ret = tps6586x_set_bits(parent, ri->enable_reg[0],
1 << ri->enable_bit[0]);
if (ret)
return -EACCES;
status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
- message >> 8, 0x15 /* PB_WORD_MSB */ );
- if (status >= 0)
+ message >> 8, TWL4030_PM_MASTER_PB_WORD_MSB);
+ if (status < 0)
return status;
return twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
- message, 0x16 /* PB_WORD_LSB */ );
+ message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB);
}
/*----------------------------------------------------------------------*/
#include <linux/device.h>
#include <linux/poll.h>
#include <linux/mutex.h>
-#include <linux/smp_lock.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/smp_lock.h>
#include <asm/compat.h>
#include <asm/ccwdev.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/mtio.h>
-#include <linux/smp_lock.h>
#include <linux/compat.h>
#include <asm/uaccess.h>
wake_up(&device->state_change_wq);
}
+struct tape_med_state_work_data {
+ struct tape_device *device;
+ enum tape_medium_state state;
+ struct work_struct work;
+};
+
+static void
+tape_med_state_work_handler(struct work_struct *work)
+{
+ static char env_state_loaded[] = "MEDIUM_STATE=LOADED";
+ static char env_state_unloaded[] = "MEDIUM_STATE=UNLOADED";
+ struct tape_med_state_work_data *p =
+ container_of(work, struct tape_med_state_work_data, work);
+ struct tape_device *device = p->device;
+ char *envp[] = { NULL, NULL };
+
+ switch (p->state) {
+ case MS_UNLOADED:
+ pr_info("%s: The tape cartridge has been successfully "
+ "unloaded\n", dev_name(&device->cdev->dev));
+ envp[0] = env_state_unloaded;
+ kobject_uevent_env(&device->cdev->dev.kobj, KOBJ_CHANGE, envp);
+ break;
+ case MS_LOADED:
+ pr_info("%s: A tape cartridge has been mounted\n",
+ dev_name(&device->cdev->dev));
+ envp[0] = env_state_loaded;
+ kobject_uevent_env(&device->cdev->dev.kobj, KOBJ_CHANGE, envp);
+ break;
+ default:
+ break;
+ }
+ tape_put_device(device);
+ kfree(p);
+}
+
+static void
+tape_med_state_work(struct tape_device *device, enum tape_medium_state state)
+{
+ struct tape_med_state_work_data *p;
+
+ p = kzalloc(sizeof(*p), GFP_ATOMIC);
+ if (p) {
+ INIT_WORK(&p->work, tape_med_state_work_handler);
+ p->device = tape_get_device(device);
+ p->state = state;
+ schedule_work(&p->work);
+ }
+}
+
void
tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)
{
- if (device->medium_state == newstate)
+ enum tape_medium_state oldstate;
+
+ oldstate = device->medium_state;
+ if (oldstate == newstate)
return;
+ device->medium_state = newstate;
switch(newstate){
case MS_UNLOADED:
device->tape_generic_status |= GMT_DR_OPEN(~0);
- if (device->medium_state == MS_LOADED)
- pr_info("%s: The tape cartridge has been successfully "
- "unloaded\n", dev_name(&device->cdev->dev));
+ if (oldstate == MS_LOADED)
+ tape_med_state_work(device, MS_UNLOADED);
break;
case MS_LOADED:
device->tape_generic_status &= ~GMT_DR_OPEN(~0);
- if (device->medium_state == MS_UNLOADED)
- pr_info("%s: A tape cartridge has been mounted\n",
- dev_name(&device->cdev->dev));
+ if (oldstate == MS_UNLOADED)
+ tape_med_state_work(device, MS_LOADED);
break;
default:
- // print nothing
break;
}
- device->medium_state = newstate;
wake_up(&device->state_change_wq);
}
#include <linux/kmod.h>
#include <linux/cdev.h>
#include <linux/device.h>
-#include <linux/smp_lock.h>
#include <linux/string.h>
MODULE_AUTHOR
char cp_command[80];
char cp_response[160];
char *onoff, *qid_string;
+ int rc;
- memset(cp_command, 0x00, sizeof(cp_command));
- memset(cp_response, 0x00, sizeof(cp_response));
-
- onoff = ((action == 1) ? "ON" : "OFF");
+ onoff = ((action == 1) ? "ON" : "OFF");
qid_string = ((recording_class_AB == 1) ? " QID * " : "");
- /*
+ /*
* The recording commands needs to be called with option QID
* for guests that have previlege classes A or B.
* Purging has to be done as separate step, because recording
* can't be switched on as long as records are on the queue.
* Doing both at the same time doesn't work.
*/
-
- if (purge) {
+ if (purge && (action == 1)) {
+ memset(cp_command, 0x00, sizeof(cp_command));
+ memset(cp_response, 0x00, sizeof(cp_response));
snprintf(cp_command, sizeof(cp_command),
"RECORDING %s PURGE %s",
logptr->recording_name,
qid_string);
-
cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
}
logptr->recording_name,
onoff,
qid_string);
-
cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
/* The recording command will usually answer with 'Command complete'
* on success, but when the specific service was never connected
* before then there might be an additional informational message
* 'HCPCRC8072I Recording entry not found' before the
- * 'Command complete'. So I use strstr rather then the strncmp.
+ * 'Command complete'. So I use strstr rather then the strncmp.
*/
if (strstr(cp_response,"Command complete"))
- return 0;
+ rc = 0;
else
- return -EIO;
+ rc = -EIO;
+ /*
+ * If we turn recording off, we have to purge any remaining records
+ * afterwards, as a large number of queued records may impact z/VM
+ * performance.
+ */
+ if (purge && (action == 0)) {
+ memset(cp_command, 0x00, sizeof(cp_command));
+ memset(cp_response, 0x00, sizeof(cp_response));
+ snprintf(cp_command, sizeof(cp_command),
+ "RECORDING %s PURGE %s",
+ logptr->recording_name,
+ qid_string);
+ cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
+ }
+ return rc;
}
#include <linux/cdev.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/cio.h>
init_subchannel_id(&mchk_schid);
mchk_schid.sch_no = crw0->rsid;
if (crw1)
- mchk_schid.ssid = (crw1->rsid >> 8) & 3;
+ mchk_schid.ssid = (crw1->rsid >> 4) & 3;
/*
* Since we are always presented with IPI in the CRW, we have to
break;
case IO_SCH_UNREG_ATTACH:
case IO_SCH_UNREG:
- if (cdev)
+ if (!cdev)
+ break;
+ if (cdev->private->state == DEV_STATE_SENSE_ID) {
+ /*
+ * Note: delayed work triggered by this event
+ * and repeated calls to sch_event are synchronized
+ * by the above check for work_pending(cdev).
+ */
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ } else
ccw_device_set_notoper(cdev);
break;
case IO_SCH_NOP:
return;
/* reset adapter interrupt indicators */
- put_indicator(irq_ptr->dsci);
set_subchannel_ind(irq_ptr, 1);
+ put_indicator(irq_ptr->dsci);
}
void __exit tiqdio_unregister_thinints(void)
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/compat.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
module_param_named(device, init_device, charp, 0400);
MODULE_PARM_DESC(device, "specify initial device");
-static struct kmem_cache *zfcp_cache_hw_align(const char *name,
- unsigned long size)
+static struct kmem_cache * __init zfcp_cache_hw_align(const char *name,
+ unsigned long size)
{
return kmem_cache_create(name, size, roundup_pow_of_two(size), 0, NULL);
}
if (zfcp_fsf_status_read(adapter->qdio)) {
if (atomic_read(&adapter->stat_miss) >=
adapter->stat_read_buf_num) {
- zfcp_erp_adapter_reopen(adapter, 0, "axsref1",
- NULL);
+ zfcp_erp_adapter_reopen(adapter, 0, "axsref1");
return 1;
}
break;
sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs);
zfcp_erp_thread_kill(adapter);
- zfcp_dbf_adapter_unregister(adapter->dbf);
+ zfcp_dbf_adapter_unregister(adapter);
zfcp_qdio_destroy(adapter->qdio);
zfcp_ccw_adapter_put(adapter); /* final put to release */
zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
- "ccresu2", NULL);
+ "ccresu2");
zfcp_erp_wait(adapter);
flush_work(&adapter->scan_work);
if (!adapter)
return 0;
- zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1");
zfcp_erp_wait(adapter);
zfcp_ccw_adapter_put(adapter);
switch (event) {
case CIO_GONE:
dev_warn(&cdev->dev, "The FCP device has been detached\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1");
break;
case CIO_NO_PATH:
dev_warn(&cdev->dev,
"The CHPID for the FCP device is offline\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2");
break;
case CIO_OPER:
dev_info(&cdev->dev, "The FCP device is operational again\n");
zfcp_erp_set_adapter_status(adapter,
ZFCP_STATUS_COMMON_RUNNING);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
- "ccnoti4", NULL);
+ "ccnoti4");
break;
case CIO_BOXED:
dev_warn(&cdev->dev, "The FCP device did not respond within "
"the specified time\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5");
break;
}
if (!adapter)
return;
- zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1");
zfcp_erp_wait(adapter);
zfcp_erp_thread_kill(adapter);
(status & ZFCP_STATUS_COMMON_ACCESS_BOXED))
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "cfaac_1", NULL);
+ "cfaac_1");
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
(status & ZFCP_STATUS_COMMON_ACCESS_BOXED))
zfcp_erp_lun_reopen(sdev,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "cfaac_2", NULL);
+ "cfaac_2");
}
}
zfcp_scsi_dev_lun(sdev),
(unsigned long long)zfcp_sdev->port->wwpn);
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED);
- zfcp_erp_lun_shutdown(sdev, 0, "fsouh_6", NULL);
+ zfcp_erp_lun_shutdown(sdev, 0, "fsouh_6");
return -EACCES;
}
zfcp_scsi_dev_lun(sdev),
(unsigned long long)zfcp_sdev->port->wwpn);
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED);
- zfcp_erp_lun_shutdown(sdev, 0, "fsosh_8", NULL);
+ zfcp_erp_lun_shutdown(sdev, 0, "fsosh_8");
return -EACCES;
}
*
* Debug traces for zfcp.
*
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
*/
#define KMSG_COMPONENT "zfcp"
MODULE_PARM_DESC(dbfsize,
"number of pages for each debug feature area (default 4)");
-static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len,
- int level, char *from, int from_len)
+static inline unsigned int zfcp_dbf_plen(unsigned int offset)
{
- int offset;
- struct zfcp_dbf_dump *dump = to;
- int room = to_len - sizeof(*dump);
-
- for (offset = 0; offset < from_len; offset += dump->size) {
- memset(to, 0, to_len);
- strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE);
- dump->total_size = from_len;
- dump->offset = offset;
- dump->size = min(from_len - offset, room);
- memcpy(dump->data, from + offset, dump->size);
- debug_event(dbf, level, dump, dump->size + sizeof(*dump));
- }
+ return sizeof(struct zfcp_dbf_pay) + offset - ZFCP_DBF_PAY_MAX_REC;
}
-static void zfcp_dbf_tag(char **p, const char *label, const char *tag)
+static inline
+void zfcp_dbf_pl_write(struct zfcp_dbf *dbf, void *data, u16 length, char *area,
+ u64 req_id)
{
- int i;
-
- *p += sprintf(*p, "%-24s", label);
- for (i = 0; i < ZFCP_DBF_TAG_SIZE; i++)
- *p += sprintf(*p, "%c", tag[i]);
- *p += sprintf(*p, "\n");
-}
+ struct zfcp_dbf_pay *pl = &dbf->pay_buf;
+ u16 offset = 0, rec_length;
-static void zfcp_dbf_outs(char **buf, const char *s1, const char *s2)
-{
- *buf += sprintf(*buf, "%-24s%s\n", s1, s2);
-}
+ spin_lock(&dbf->pay_lock);
+ memset(pl, 0, sizeof(*pl));
+ pl->fsf_req_id = req_id;
+ memcpy(pl->area, area, ZFCP_DBF_TAG_LEN);
-static void zfcp_dbf_out(char **buf, const char *s, const char *format, ...)
-{
- va_list arg;
+ while (offset < length) {
+ rec_length = min((u16) ZFCP_DBF_PAY_MAX_REC,
+ (u16) (length - offset));
+ memcpy(pl->data, data + offset, rec_length);
+ debug_event(dbf->pay, 1, pl, zfcp_dbf_plen(rec_length));
- *buf += sprintf(*buf, "%-24s", s);
- va_start(arg, format);
- *buf += vsprintf(*buf, format, arg);
- va_end(arg);
- *buf += sprintf(*buf, "\n");
-}
-
-static void zfcp_dbf_outd(char **p, const char *label, char *buffer,
- int buflen, int offset, int total_size)
-{
- if (!offset)
- *p += sprintf(*p, "%-24s ", label);
- while (buflen--) {
- if (offset > 0) {
- if ((offset % 32) == 0)
- *p += sprintf(*p, "\n%-24c ", ' ');
- else if ((offset % 4) == 0)
- *p += sprintf(*p, " ");
- }
- *p += sprintf(*p, "%02x", *buffer++);
- if (++offset == total_size) {
- *p += sprintf(*p, "\n");
- break;
- }
+ offset += rec_length;
+ pl->counter++;
}
- if (!total_size)
- *p += sprintf(*p, "\n");
-}
-static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view,
- int area, debug_entry_t *entry, char *out_buf)
-{
- struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)DEBUG_DATA(entry);
- struct timespec t;
- char *p = out_buf;
-
- if (strncmp(dump->tag, "dump", ZFCP_DBF_TAG_SIZE) != 0) {
- stck_to_timespec(entry->id.stck, &t);
- zfcp_dbf_out(&p, "timestamp", "%011lu:%06lu",
- t.tv_sec, t.tv_nsec);
- zfcp_dbf_out(&p, "cpu", "%02i", entry->id.fields.cpuid);
- } else {
- zfcp_dbf_outd(&p, "", dump->data, dump->size, dump->offset,
- dump->total_size);
- if ((dump->offset + dump->size) == dump->total_size)
- p += sprintf(p, "\n");
- }
- return p - out_buf;
+ spin_unlock(&dbf->pay_lock);
}
-void _zfcp_dbf_hba_fsf_response(const char *tag2, int level,
- struct zfcp_fsf_req *fsf_req,
- struct zfcp_dbf *dbf)
+/**
+ * zfcp_dbf_hba_fsf_res - trace event for fsf responses
+ * @tag: tag indicating which kind of unsolicited status has been received
+ * @req: request for which a response was received
+ */
+void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req)
{
- struct fsf_qtcb *qtcb = fsf_req->qtcb;
- union fsf_prot_status_qual *prot_status_qual =
- &qtcb->prefix.prot_status_qual;
- union fsf_status_qual *fsf_status_qual = &qtcb->header.fsf_status_qual;
- struct scsi_cmnd *scsi_cmnd;
- struct zfcp_port *port;
- struct zfcp_unit *unit;
- struct zfcp_send_els *send_els;
- struct zfcp_dbf_hba_record *rec = &dbf->hba_buf;
- struct zfcp_dbf_hba_record_response *response = &rec->u.response;
+ struct zfcp_dbf *dbf = req->adapter->dbf;
+ struct fsf_qtcb_prefix *q_pref = &req->qtcb->prefix;
+ struct fsf_qtcb_header *q_head = &req->qtcb->header;
+ struct zfcp_dbf_hba *rec = &dbf->hba_buf;
unsigned long flags;
spin_lock_irqsave(&dbf->hba_lock, flags);
memset(rec, 0, sizeof(*rec));
- strncpy(rec->tag, "resp", ZFCP_DBF_TAG_SIZE);
- strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE);
-
- response->fsf_command = fsf_req->fsf_command;
- response->fsf_reqid = fsf_req->req_id;
- response->fsf_seqno = fsf_req->seq_no;
- response->fsf_issued = fsf_req->issued;
- response->fsf_prot_status = qtcb->prefix.prot_status;
- response->fsf_status = qtcb->header.fsf_status;
- memcpy(response->fsf_prot_status_qual,
- prot_status_qual, FSF_PROT_STATUS_QUAL_SIZE);
- memcpy(response->fsf_status_qual,
- fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE);
- response->fsf_req_status = fsf_req->status;
- response->sbal_first = fsf_req->qdio_req.sbal_first;
- response->sbal_last = fsf_req->qdio_req.sbal_last;
- response->sbal_response = fsf_req->qdio_req.sbal_response;
- response->pool = fsf_req->pool != NULL;
- response->erp_action = (unsigned long)fsf_req->erp_action;
-
- switch (fsf_req->fsf_command) {
- case FSF_QTCB_FCP_CMND:
- if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
- break;
- scsi_cmnd = (struct scsi_cmnd *)fsf_req->data;
- if (scsi_cmnd) {
- response->u.fcp.cmnd = (unsigned long)scsi_cmnd;
- response->u.fcp.data_dir =
- qtcb->bottom.io.data_direction;
- }
- break;
-
- case FSF_QTCB_OPEN_PORT_WITH_DID:
- case FSF_QTCB_CLOSE_PORT:
- case FSF_QTCB_CLOSE_PHYSICAL_PORT:
- port = (struct zfcp_port *)fsf_req->data;
- response->u.port.wwpn = port->wwpn;
- response->u.port.d_id = port->d_id;
- response->u.port.port_handle = qtcb->header.port_handle;
- break;
-
- case FSF_QTCB_OPEN_LUN:
- case FSF_QTCB_CLOSE_LUN:
- unit = (struct zfcp_unit *)fsf_req->data;
- port = unit->port;
- response->u.unit.wwpn = port->wwpn;
- response->u.unit.fcp_lun = unit->fcp_lun;
- response->u.unit.port_handle = qtcb->header.port_handle;
- response->u.unit.lun_handle = qtcb->header.lun_handle;
- break;
-
- case FSF_QTCB_SEND_ELS:
- send_els = (struct zfcp_send_els *)fsf_req->data;
- response->u.els.d_id = ntoh24(qtcb->bottom.support.d_id);
- break;
-
- case FSF_QTCB_ABORT_FCP_CMND:
- case FSF_QTCB_SEND_GENERIC:
- case FSF_QTCB_EXCHANGE_CONFIG_DATA:
- case FSF_QTCB_EXCHANGE_PORT_DATA:
- case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
- case FSF_QTCB_UPLOAD_CONTROL_FILE:
- break;
- }
-
- debug_event(dbf->hba, level, rec, sizeof(*rec));
- /* have fcp channel microcode fixed to use as little as possible */
- if (fsf_req->fsf_command != FSF_QTCB_FCP_CMND) {
- /* adjust length skipping trailing zeros */
- char *buf = (char *)qtcb + qtcb->header.log_start;
- int len = qtcb->header.log_length;
- for (; len && !buf[len - 1]; len--);
- zfcp_dbf_hexdump(dbf->hba, rec, sizeof(*rec), level, buf,
- len);
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ rec->id = ZFCP_DBF_HBA_RES;
+ rec->fsf_req_id = req->req_id;
+ rec->fsf_req_status = req->status;
+ rec->fsf_cmd = req->fsf_command;
+ rec->fsf_seq_no = req->seq_no;
+ rec->u.res.req_issued = req->issued;
+ rec->u.res.prot_status = q_pref->prot_status;
+ rec->u.res.fsf_status = q_head->fsf_status;
+
+ memcpy(rec->u.res.prot_status_qual, &q_pref->prot_status_qual,
+ FSF_PROT_STATUS_QUAL_SIZE);
+ memcpy(rec->u.res.fsf_status_qual, &q_head->fsf_status_qual,
+ FSF_STATUS_QUALIFIER_SIZE);
+
+ if (req->fsf_command != FSF_QTCB_FCP_CMND) {
+ rec->pl_len = q_head->log_length;
+ zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start,
+ rec->pl_len, "fsf_res", req->req_id);
}
- spin_unlock_irqrestore(&dbf->hba_lock, flags);
-}
-
-void _zfcp_dbf_hba_fsf_unsol(const char *tag, int level, struct zfcp_dbf *dbf,
- struct fsf_status_read_buffer *status_buffer)
-{
- struct zfcp_dbf_hba_record *rec = &dbf->hba_buf;
- unsigned long flags;
-
- spin_lock_irqsave(&dbf->hba_lock, flags);
- memset(rec, 0, sizeof(*rec));
- strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE);
- strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE);
-
- rec->u.status.failed = atomic_read(&dbf->adapter->stat_miss);
- if (status_buffer != NULL) {
- rec->u.status.status_type = status_buffer->status_type;
- rec->u.status.status_subtype = status_buffer->status_subtype;
- memcpy(&rec->u.status.queue_designator,
- &status_buffer->queue_designator,
- sizeof(struct fsf_queue_designator));
-
- switch (status_buffer->status_type) {
- case FSF_STATUS_READ_SENSE_DATA_AVAIL:
- rec->u.status.payload_size =
- ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL;
- break;
-
- case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
- rec->u.status.payload_size =
- ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD;
- break;
-
- case FSF_STATUS_READ_LINK_DOWN:
- switch (status_buffer->status_subtype) {
- case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
- case FSF_STATUS_READ_SUB_FDISC_FAILED:
- rec->u.status.payload_size =
- sizeof(struct fsf_link_down_info);
- }
- break;
-
- case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
- rec->u.status.payload_size =
- ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT;
- break;
- }
- memcpy(&rec->u.status.payload,
- &status_buffer->payload, rec->u.status.payload_size);
- }
-
- debug_event(dbf->hba, level, rec, sizeof(*rec));
+ debug_event(dbf->hba, 1, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->hba_lock, flags);
}
/**
- * zfcp_dbf_hba_qdio - trace event for QDIO related failure
- * @qdio: qdio structure affected by this QDIO related event
- * @qdio_error: as passed by qdio module
- * @sbal_index: first buffer with error condition, as passed by qdio module
- * @sbal_count: number of buffers affected, as passed by qdio module
+ * zfcp_dbf_hba_fsf_uss - trace event for an unsolicited status buffer
+ * @tag: tag indicating which kind of unsolicited status has been received
+ * @req: request providing the unsolicited status
*/
-void zfcp_dbf_hba_qdio(struct zfcp_dbf *dbf, unsigned int qdio_error,
- int sbal_index, int sbal_count)
+void zfcp_dbf_hba_fsf_uss(char *tag, struct zfcp_fsf_req *req)
{
- struct zfcp_dbf_hba_record *r = &dbf->hba_buf;
+ struct zfcp_dbf *dbf = req->adapter->dbf;
+ struct fsf_status_read_buffer *srb = req->data;
+ struct zfcp_dbf_hba *rec = &dbf->hba_buf;
unsigned long flags;
spin_lock_irqsave(&dbf->hba_lock, flags);
- memset(r, 0, sizeof(*r));
- strncpy(r->tag, "qdio", ZFCP_DBF_TAG_SIZE);
- r->u.qdio.qdio_error = qdio_error;
- r->u.qdio.sbal_index = sbal_index;
- r->u.qdio.sbal_count = sbal_count;
- debug_event(dbf->hba, 0, r, sizeof(*r));
+ memset(rec, 0, sizeof(*rec));
+
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ rec->id = ZFCP_DBF_HBA_USS;
+ rec->fsf_req_id = req->req_id;
+ rec->fsf_req_status = req->status;
+ rec->fsf_cmd = req->fsf_command;
+
+ if (!srb)
+ goto log;
+
+ rec->u.uss.status_type = srb->status_type;
+ rec->u.uss.status_subtype = srb->status_subtype;
+ rec->u.uss.d_id = ntoh24(srb->d_id);
+ rec->u.uss.lun = srb->fcp_lun;
+ memcpy(&rec->u.uss.queue_designator, &srb->queue_designator,
+ sizeof(rec->u.uss.queue_designator));
+
+ /* status read buffer payload length */
+ rec->pl_len = (!srb->length) ? 0 : srb->length -
+ offsetof(struct fsf_status_read_buffer, payload);
+
+ if (rec->pl_len)
+ zfcp_dbf_pl_write(dbf, srb->payload.data, rec->pl_len,
+ "fsf_uss", req->req_id);
+log:
+ debug_event(dbf->hba, 2, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->hba_lock, flags);
}
/**
- * zfcp_dbf_hba_berr - trace event for bit error threshold
- * @dbf: dbf structure affected by this QDIO related event
- * @req: fsf request
+ * zfcp_dbf_hba_bit_err - trace event for bit error conditions
+ * @tag: tag indicating which kind of unsolicited status has been received
+ * @req: request which caused the bit_error condition
*/
-void zfcp_dbf_hba_berr(struct zfcp_dbf *dbf, struct zfcp_fsf_req *req)
+void zfcp_dbf_hba_bit_err(char *tag, struct zfcp_fsf_req *req)
{
- struct zfcp_dbf_hba_record *r = &dbf->hba_buf;
+ struct zfcp_dbf *dbf = req->adapter->dbf;
+ struct zfcp_dbf_hba *rec = &dbf->hba_buf;
struct fsf_status_read_buffer *sr_buf = req->data;
- struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error;
unsigned long flags;
spin_lock_irqsave(&dbf->hba_lock, flags);
- memset(r, 0, sizeof(*r));
- strncpy(r->tag, "berr", ZFCP_DBF_TAG_SIZE);
- memcpy(&r->u.berr, err, sizeof(struct fsf_bit_error_payload));
- debug_event(dbf->hba, 0, r, sizeof(*r));
- spin_unlock_irqrestore(&dbf->hba_lock, flags);
-}
-static void zfcp_dbf_hba_view_response(char **p,
- struct zfcp_dbf_hba_record_response *r)
-{
- struct timespec t;
-
- zfcp_dbf_out(p, "fsf_command", "0x%08x", r->fsf_command);
- zfcp_dbf_out(p, "fsf_reqid", "0x%0Lx", r->fsf_reqid);
- zfcp_dbf_out(p, "fsf_seqno", "0x%08x", r->fsf_seqno);
- stck_to_timespec(r->fsf_issued, &t);
- zfcp_dbf_out(p, "fsf_issued", "%011lu:%06lu", t.tv_sec, t.tv_nsec);
- zfcp_dbf_out(p, "fsf_prot_status", "0x%08x", r->fsf_prot_status);
- zfcp_dbf_out(p, "fsf_status", "0x%08x", r->fsf_status);
- zfcp_dbf_outd(p, "fsf_prot_status_qual", r->fsf_prot_status_qual,
- FSF_PROT_STATUS_QUAL_SIZE, 0, FSF_PROT_STATUS_QUAL_SIZE);
- zfcp_dbf_outd(p, "fsf_status_qual", r->fsf_status_qual,
- FSF_STATUS_QUALIFIER_SIZE, 0, FSF_STATUS_QUALIFIER_SIZE);
- zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status);
- zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first);
- zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last);
- zfcp_dbf_out(p, "sbal_response", "0x%02x", r->sbal_response);
- zfcp_dbf_out(p, "pool", "0x%02x", r->pool);
-
- switch (r->fsf_command) {
- case FSF_QTCB_FCP_CMND:
- if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
- break;
- zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir);
- zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd);
- *p += sprintf(*p, "\n");
- break;
-
- case FSF_QTCB_OPEN_PORT_WITH_DID:
- case FSF_QTCB_CLOSE_PORT:
- case FSF_QTCB_CLOSE_PHYSICAL_PORT:
- zfcp_dbf_out(p, "wwpn", "0x%016Lx", r->u.port.wwpn);
- zfcp_dbf_out(p, "d_id", "0x%06x", r->u.port.d_id);
- zfcp_dbf_out(p, "port_handle", "0x%08x", r->u.port.port_handle);
- break;
-
- case FSF_QTCB_OPEN_LUN:
- case FSF_QTCB_CLOSE_LUN:
- zfcp_dbf_out(p, "wwpn", "0x%016Lx", r->u.unit.wwpn);
- zfcp_dbf_out(p, "fcp_lun", "0x%016Lx", r->u.unit.fcp_lun);
- zfcp_dbf_out(p, "port_handle", "0x%08x", r->u.unit.port_handle);
- zfcp_dbf_out(p, "lun_handle", "0x%08x", r->u.unit.lun_handle);
- break;
-
- case FSF_QTCB_SEND_ELS:
- zfcp_dbf_out(p, "d_id", "0x%06x", r->u.els.d_id);
- break;
-
- case FSF_QTCB_ABORT_FCP_CMND:
- case FSF_QTCB_SEND_GENERIC:
- case FSF_QTCB_EXCHANGE_CONFIG_DATA:
- case FSF_QTCB_EXCHANGE_PORT_DATA:
- case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
- case FSF_QTCB_UPLOAD_CONTROL_FILE:
- break;
- }
-}
-
-static void zfcp_dbf_hba_view_status(char **p,
- struct zfcp_dbf_hba_record_status *r)
-{
- zfcp_dbf_out(p, "failed", "0x%02x", r->failed);
- zfcp_dbf_out(p, "status_type", "0x%08x", r->status_type);
- zfcp_dbf_out(p, "status_subtype", "0x%08x", r->status_subtype);
- zfcp_dbf_outd(p, "queue_designator", (char *)&r->queue_designator,
- sizeof(struct fsf_queue_designator), 0,
- sizeof(struct fsf_queue_designator));
- zfcp_dbf_outd(p, "payload", (char *)&r->payload, r->payload_size, 0,
- r->payload_size);
-}
-
-static void zfcp_dbf_hba_view_qdio(char **p, struct zfcp_dbf_hba_record_qdio *r)
-{
- zfcp_dbf_out(p, "qdio_error", "0x%08x", r->qdio_error);
- zfcp_dbf_out(p, "sbal_index", "0x%02x", r->sbal_index);
- zfcp_dbf_out(p, "sbal_count", "0x%02x", r->sbal_count);
-}
+ memset(rec, 0, sizeof(*rec));
-static void zfcp_dbf_hba_view_berr(char **p, struct fsf_bit_error_payload *r)
-{
- zfcp_dbf_out(p, "link_failures", "%d", r->link_failure_error_count);
- zfcp_dbf_out(p, "loss_of_sync_err", "%d", r->loss_of_sync_error_count);
- zfcp_dbf_out(p, "loss_of_sig_err", "%d", r->loss_of_signal_error_count);
- zfcp_dbf_out(p, "prim_seq_err", "%d",
- r->primitive_sequence_error_count);
- zfcp_dbf_out(p, "inval_trans_word_err", "%d",
- r->invalid_transmission_word_error_count);
- zfcp_dbf_out(p, "CRC_errors", "%d", r->crc_error_count);
- zfcp_dbf_out(p, "prim_seq_event_to", "%d",
- r->primitive_sequence_event_timeout_count);
- zfcp_dbf_out(p, "elast_buf_overrun_err", "%d",
- r->elastic_buffer_overrun_error_count);
- zfcp_dbf_out(p, "adv_rec_buf2buf_cred", "%d",
- r->advertised_receive_b2b_credit);
- zfcp_dbf_out(p, "curr_rec_buf2buf_cred", "%d",
- r->current_receive_b2b_credit);
- zfcp_dbf_out(p, "adv_trans_buf2buf_cred", "%d",
- r->advertised_transmit_b2b_credit);
- zfcp_dbf_out(p, "curr_trans_buf2buf_cred", "%d",
- r->current_transmit_b2b_credit);
-}
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ rec->id = ZFCP_DBF_HBA_BIT;
+ rec->fsf_req_id = req->req_id;
+ rec->fsf_req_status = req->status;
+ rec->fsf_cmd = req->fsf_command;
+ memcpy(&rec->u.be, &sr_buf->payload.bit_error,
+ sizeof(struct fsf_bit_error_payload));
-static int zfcp_dbf_hba_view_format(debug_info_t *id, struct debug_view *view,
- char *out_buf, const char *in_buf)
-{
- struct zfcp_dbf_hba_record *r = (struct zfcp_dbf_hba_record *)in_buf;
- char *p = out_buf;
-
- if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
- return 0;
-
- zfcp_dbf_tag(&p, "tag", r->tag);
- if (isalpha(r->tag2[0]))
- zfcp_dbf_tag(&p, "tag2", r->tag2);
-
- if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) == 0)
- zfcp_dbf_hba_view_response(&p, &r->u.response);
- else if (strncmp(r->tag, "stat", ZFCP_DBF_TAG_SIZE) == 0)
- zfcp_dbf_hba_view_status(&p, &r->u.status);
- else if (strncmp(r->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0)
- zfcp_dbf_hba_view_qdio(&p, &r->u.qdio);
- else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0)
- zfcp_dbf_hba_view_berr(&p, &r->u.berr);
-
- if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) != 0)
- p += sprintf(p, "\n");
- return p - out_buf;
+ debug_event(dbf->hba, 1, rec, sizeof(*rec));
+ spin_unlock_irqrestore(&dbf->hba_lock, flags);
}
-static struct debug_view zfcp_dbf_hba_view = {
- .name = "structured",
- .header_proc = zfcp_dbf_view_header,
- .format_proc = zfcp_dbf_hba_view_format,
-};
-
-static const char *zfcp_dbf_rec_tags[] = {
- [ZFCP_REC_DBF_ID_THREAD] = "thread",
- [ZFCP_REC_DBF_ID_TARGET] = "target",
- [ZFCP_REC_DBF_ID_TRIGGER] = "trigger",
- [ZFCP_REC_DBF_ID_ACTION] = "action",
-};
-
-static int zfcp_dbf_rec_view_format(debug_info_t *id, struct debug_view *view,
- char *buf, const char *_rec)
+static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec,
+ struct zfcp_adapter *adapter,
+ struct zfcp_port *port,
+ struct scsi_device *sdev)
{
- struct zfcp_dbf_rec_record *r = (struct zfcp_dbf_rec_record *)_rec;
- char *p = buf;
- char hint[ZFCP_DBF_ID_SIZE + 1];
-
- memcpy(hint, r->id2, ZFCP_DBF_ID_SIZE);
- hint[ZFCP_DBF_ID_SIZE] = 0;
- zfcp_dbf_outs(&p, "tag", zfcp_dbf_rec_tags[r->id]);
- zfcp_dbf_outs(&p, "hint", hint);
- switch (r->id) {
- case ZFCP_REC_DBF_ID_THREAD:
- zfcp_dbf_out(&p, "total", "%d", r->u.thread.total);
- zfcp_dbf_out(&p, "ready", "%d", r->u.thread.ready);
- zfcp_dbf_out(&p, "running", "%d", r->u.thread.running);
- break;
- case ZFCP_REC_DBF_ID_TARGET:
- zfcp_dbf_out(&p, "reference", "0x%016Lx", r->u.target.ref);
- zfcp_dbf_out(&p, "status", "0x%08x", r->u.target.status);
- zfcp_dbf_out(&p, "erp_count", "%d", r->u.target.erp_count);
- zfcp_dbf_out(&p, "d_id", "0x%06x", r->u.target.d_id);
- zfcp_dbf_out(&p, "wwpn", "0x%016Lx", r->u.target.wwpn);
- zfcp_dbf_out(&p, "fcp_lun", "0x%016Lx", r->u.target.fcp_lun);
- break;
- case ZFCP_REC_DBF_ID_TRIGGER:
- zfcp_dbf_out(&p, "reference", "0x%016Lx", r->u.trigger.ref);
- zfcp_dbf_out(&p, "erp_action", "0x%016Lx", r->u.trigger.action);
- zfcp_dbf_out(&p, "requested", "%d", r->u.trigger.want);
- zfcp_dbf_out(&p, "executed", "%d", r->u.trigger.need);
- zfcp_dbf_out(&p, "wwpn", "0x%016Lx", r->u.trigger.wwpn);
- zfcp_dbf_out(&p, "fcp_lun", "0x%016Lx", r->u.trigger.fcp_lun);
- zfcp_dbf_out(&p, "adapter_status", "0x%08x", r->u.trigger.as);
- zfcp_dbf_out(&p, "port_status", "0x%08x", r->u.trigger.ps);
- zfcp_dbf_out(&p, "lun_status", "0x%08x", r->u.trigger.ls);
- break;
- case ZFCP_REC_DBF_ID_ACTION:
- zfcp_dbf_out(&p, "erp_action", "0x%016Lx", r->u.action.action);
- zfcp_dbf_out(&p, "fsf_req", "0x%016Lx", r->u.action.fsf_req);
- zfcp_dbf_out(&p, "status", "0x%08Lx", r->u.action.status);
- zfcp_dbf_out(&p, "step", "0x%08Lx", r->u.action.step);
- break;
+ rec->adapter_status = atomic_read(&adapter->status);
+ if (port) {
+ rec->port_status = atomic_read(&port->status);
+ rec->wwpn = port->wwpn;
+ rec->d_id = port->d_id;
+ }
+ if (sdev) {
+ rec->lun_status = atomic_read(&sdev_to_zfcp(sdev)->status);
+ rec->lun = zfcp_scsi_dev_lun(sdev);
}
- p += sprintf(p, "\n");
- return p - buf;
}
-static struct debug_view zfcp_dbf_rec_view = {
- .name = "structured",
- .header_proc = zfcp_dbf_view_header,
- .format_proc = zfcp_dbf_rec_view_format,
-};
-
/**
- * zfcp_dbf_rec_thread - trace event related to recovery thread operation
- * @id2: identifier for event
- * @dbf: reference to dbf structure
- * This function assumes that the caller is holding erp_lock.
+ * zfcp_dbf_rec_trig - trace event related to triggered recovery
+ * @tag: identifier for event
+ * @adapter: adapter on which the erp_action should run
+ * @port: remote port involved in the erp_action
+ * @sdev: scsi device involved in the erp_action
+ * @want: wanted erp_action
+ * @need: required erp_action
+ *
+ * The adapter->erp_lock has to be held.
*/
-void zfcp_dbf_rec_thread(char *id2, struct zfcp_dbf *dbf)
+void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter,
+ struct zfcp_port *port, struct scsi_device *sdev,
+ u8 want, u8 need)
{
- struct zfcp_adapter *adapter = dbf->adapter;
- struct zfcp_dbf_rec_record *r = &dbf->rec_buf;
- unsigned long flags = 0;
+ struct zfcp_dbf *dbf = adapter->dbf;
+ struct zfcp_dbf_rec *rec = &dbf->rec_buf;
struct list_head *entry;
- unsigned ready = 0, running = 0, total;
-
- list_for_each(entry, &adapter->erp_ready_head)
- ready++;
- list_for_each(entry, &adapter->erp_running_head)
- running++;
- total = adapter->erp_total_count;
-
- spin_lock_irqsave(&dbf->rec_lock, flags);
- memset(r, 0, sizeof(*r));
- r->id = ZFCP_REC_DBF_ID_THREAD;
- memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
- r->u.thread.total = total;
- r->u.thread.ready = ready;
- r->u.thread.running = running;
- debug_event(dbf->rec, 6, r, sizeof(*r));
- spin_unlock_irqrestore(&dbf->rec_lock, flags);
-}
-
-/**
- * zfcp_dbf_rec_thread - trace event related to recovery thread operation
- * @id2: identifier for event
- * @adapter: adapter
- * This function assumes that the caller does not hold erp_lock.
- */
-void zfcp_dbf_rec_thread_lock(char *id2, struct zfcp_dbf *dbf)
-{
- struct zfcp_adapter *adapter = dbf->adapter;
- unsigned long flags;
-
- read_lock_irqsave(&adapter->erp_lock, flags);
- zfcp_dbf_rec_thread(id2, dbf);
- read_unlock_irqrestore(&adapter->erp_lock, flags);
-}
-
-static void zfcp_dbf_rec_target(char *id2, void *ref, struct zfcp_dbf *dbf,
- atomic_t *status, atomic_t *erp_count, u64 wwpn,
- u32 d_id, u64 fcp_lun)
-{
- struct zfcp_dbf_rec_record *r = &dbf->rec_buf;
unsigned long flags;
spin_lock_irqsave(&dbf->rec_lock, flags);
- memset(r, 0, sizeof(*r));
- r->id = ZFCP_REC_DBF_ID_TARGET;
- memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
- r->u.target.ref = (unsigned long)ref;
- r->u.target.status = atomic_read(status);
- r->u.target.wwpn = wwpn;
- r->u.target.d_id = d_id;
- r->u.target.fcp_lun = fcp_lun;
- r->u.target.erp_count = atomic_read(erp_count);
- debug_event(dbf->rec, 3, r, sizeof(*r));
- spin_unlock_irqrestore(&dbf->rec_lock, flags);
-}
-
-/**
- * zfcp_dbf_rec_adapter - trace event for adapter state change
- * @id: identifier for trigger of state change
- * @ref: additional reference (e.g. request)
- * @dbf: reference to dbf structure
- */
-void zfcp_dbf_rec_adapter(char *id, void *ref, struct zfcp_dbf *dbf)
-{
- struct zfcp_adapter *adapter = dbf->adapter;
-
- zfcp_dbf_rec_target(id, ref, dbf, &adapter->status,
- &adapter->erp_counter, 0, 0,
- ZFCP_DBF_INVALID_LUN);
-}
-
-/**
- * zfcp_dbf_rec_port - trace event for port state change
- * @id: identifier for trigger of state change
- * @ref: additional reference (e.g. request)
- * @port: port
- */
-void zfcp_dbf_rec_port(char *id, void *ref, struct zfcp_port *port)
-{
- struct zfcp_dbf *dbf = port->adapter->dbf;
+ memset(rec, 0, sizeof(*rec));
- zfcp_dbf_rec_target(id, ref, dbf, &port->status,
- &port->erp_counter, port->wwpn, port->d_id,
- ZFCP_DBF_INVALID_LUN);
-}
+ rec->id = ZFCP_DBF_REC_TRIG;
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ zfcp_dbf_set_common(rec, adapter, port, sdev);
-/**
- * zfcp_dbf_rec_lun - trace event for LUN state change
- * @id: identifier for trigger of state change
- * @ref: additional reference (e.g. request)
- * @sdev: SCSI device
- */
-void zfcp_dbf_rec_lun(char *id, void *ref, struct scsi_device *sdev)
-{
- struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
- struct zfcp_port *port = zfcp_sdev->port;
- struct zfcp_dbf *dbf = port->adapter->dbf;
+ list_for_each(entry, &adapter->erp_ready_head)
+ rec->u.trig.ready++;
- zfcp_dbf_rec_target(id, ref, dbf, &zfcp_sdev->status,
- &zfcp_sdev->erp_counter, port->wwpn, port->d_id,
- zfcp_scsi_dev_lun(sdev));
-}
+ list_for_each(entry, &adapter->erp_running_head)
+ rec->u.trig.running++;
-/**
- * zfcp_dbf_rec_trigger - trace event for triggered error recovery
- * @id2: identifier for error recovery trigger
- * @ref: additional reference (e.g. request)
- * @want: originally requested error recovery action
- * @need: error recovery action actually initiated
- * @action: address of error recovery action struct
- * @adapter: adapter
- * @port: port
- * @sdev: SCSI device
- */
-void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action,
- struct zfcp_adapter *adapter, struct zfcp_port *port,
- struct scsi_device *sdev)
-{
- struct zfcp_dbf *dbf = adapter->dbf;
- struct zfcp_dbf_rec_record *r = &dbf->rec_buf;
- unsigned long flags;
+ rec->u.trig.want = want;
+ rec->u.trig.need = need;
- spin_lock_irqsave(&dbf->rec_lock, flags);
- memset(r, 0, sizeof(*r));
- r->id = ZFCP_REC_DBF_ID_TRIGGER;
- memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
- r->u.trigger.ref = (unsigned long)ref;
- r->u.trigger.want = want;
- r->u.trigger.need = need;
- r->u.trigger.action = (unsigned long)action;
- r->u.trigger.as = atomic_read(&adapter->status);
- if (port) {
- r->u.trigger.ps = atomic_read(&port->status);
- r->u.trigger.wwpn = port->wwpn;
- }
- if (sdev)
- r->u.trigger.ls = atomic_read(&sdev_to_zfcp(sdev)->status);
- r->u.trigger.fcp_lun = sdev ? zfcp_scsi_dev_lun(sdev) :
- ZFCP_DBF_INVALID_LUN;
- debug_event(dbf->rec, action ? 1 : 4, r, sizeof(*r));
+ debug_event(dbf->rec, 1, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->rec_lock, flags);
}
+
/**
- * zfcp_dbf_rec_action - trace event showing progress of recovery action
- * @id2: identifier
- * @erp_action: error recovery action struct pointer
+ * zfcp_dbf_rec_run - trace event related to running recovery
+ * @tag: identifier for event
+ * @erp: erp_action running
*/
-void zfcp_dbf_rec_action(char *id2, struct zfcp_erp_action *erp_action)
+void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)
{
- struct zfcp_dbf *dbf = erp_action->adapter->dbf;
- struct zfcp_dbf_rec_record *r = &dbf->rec_buf;
+ struct zfcp_dbf *dbf = erp->adapter->dbf;
+ struct zfcp_dbf_rec *rec = &dbf->rec_buf;
unsigned long flags;
spin_lock_irqsave(&dbf->rec_lock, flags);
- memset(r, 0, sizeof(*r));
- r->id = ZFCP_REC_DBF_ID_ACTION;
- memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
- r->u.action.action = (unsigned long)erp_action;
- r->u.action.status = erp_action->status;
- r->u.action.step = erp_action->step;
- r->u.action.fsf_req = erp_action->fsf_req_id;
- debug_event(dbf->rec, 5, r, sizeof(*r));
- spin_unlock_irqrestore(&dbf->rec_lock, flags);
-}
+ memset(rec, 0, sizeof(*rec));
-/**
- * zfcp_dbf_san_ct_request - trace event for issued CT request
- * @fsf_req: request containing issued CT data
- * @d_id: destination id where ct request is sent to
- */
-void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req, u32 d_id)
-{
- struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data;
- struct zfcp_adapter *adapter = fsf_req->adapter;
- struct zfcp_dbf *dbf = adapter->dbf;
- struct fc_ct_hdr *hdr = sg_virt(ct->req);
- struct zfcp_dbf_san_record *r = &dbf->san_buf;
- struct zfcp_dbf_san_record_ct_request *oct = &r->u.ct_req;
- int level = 3;
- unsigned long flags;
+ rec->id = ZFCP_DBF_REC_RUN;
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ zfcp_dbf_set_common(rec, erp->adapter, erp->port, erp->sdev);
- spin_lock_irqsave(&dbf->san_lock, flags);
- memset(r, 0, sizeof(*r));
- strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE);
- r->fsf_reqid = fsf_req->req_id;
- r->fsf_seqno = fsf_req->seq_no;
- oct->d_id = d_id;
- oct->cmd_req_code = hdr->ct_cmd;
- oct->revision = hdr->ct_rev;
- oct->gs_type = hdr->ct_fs_type;
- oct->gs_subtype = hdr->ct_fs_subtype;
- oct->options = hdr->ct_options;
- oct->max_res_size = hdr->ct_mr_size;
- oct->len = min((int)ct->req->length - (int)sizeof(struct fc_ct_hdr),
- ZFCP_DBF_SAN_MAX_PAYLOAD);
- debug_event(dbf->san, level, r, sizeof(*r));
- zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level,
- (void *)hdr + sizeof(struct fc_ct_hdr), oct->len);
- spin_unlock_irqrestore(&dbf->san_lock, flags);
-}
+ rec->u.run.fsf_req_id = erp->fsf_req_id;
+ rec->u.run.rec_status = erp->status;
+ rec->u.run.rec_step = erp->step;
+ rec->u.run.rec_action = erp->action;
-/**
- * zfcp_dbf_san_ct_response - trace event for completion of CT request
- * @fsf_req: request containing CT response
- */
-void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req)
-{
- struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data;
- struct zfcp_adapter *adapter = fsf_req->adapter;
- struct fc_ct_hdr *hdr = sg_virt(ct->resp);
- struct zfcp_dbf *dbf = adapter->dbf;
- struct zfcp_dbf_san_record *r = &dbf->san_buf;
- struct zfcp_dbf_san_record_ct_response *rct = &r->u.ct_resp;
- int level = 3;
- unsigned long flags;
+ if (erp->sdev)
+ rec->u.run.rec_count =
+ atomic_read(&sdev_to_zfcp(erp->sdev)->erp_counter);
+ else if (erp->port)
+ rec->u.run.rec_count = atomic_read(&erp->port->erp_counter);
+ else
+ rec->u.run.rec_count = atomic_read(&erp->adapter->erp_counter);
- spin_lock_irqsave(&dbf->san_lock, flags);
- memset(r, 0, sizeof(*r));
- strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE);
- r->fsf_reqid = fsf_req->req_id;
- r->fsf_seqno = fsf_req->seq_no;
- rct->cmd_rsp_code = hdr->ct_cmd;
- rct->revision = hdr->ct_rev;
- rct->reason_code = hdr->ct_reason;
- rct->expl = hdr->ct_explan;
- rct->vendor_unique = hdr->ct_vendor;
- rct->max_res_size = hdr->ct_mr_size;
- rct->len = min((int)ct->resp->length - (int)sizeof(struct fc_ct_hdr),
- ZFCP_DBF_SAN_MAX_PAYLOAD);
- debug_event(dbf->san, level, r, sizeof(*r));
- zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level,
- (void *)hdr + sizeof(struct fc_ct_hdr), rct->len);
- spin_unlock_irqrestore(&dbf->san_lock, flags);
+ debug_event(dbf->rec, 1, rec, sizeof(*rec));
+ spin_unlock_irqrestore(&dbf->rec_lock, flags);
}
-static void zfcp_dbf_san_els(const char *tag, int level,
- struct zfcp_fsf_req *fsf_req, u32 d_id,
- void *buffer, int buflen)
+static inline
+void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf, void *data, u8 id, u16 len,
+ u64 req_id, u32 d_id)
{
- struct zfcp_adapter *adapter = fsf_req->adapter;
- struct zfcp_dbf *dbf = adapter->dbf;
- struct zfcp_dbf_san_record *rec = &dbf->san_buf;
+ struct zfcp_dbf_san *rec = &dbf->san_buf;
+ u16 rec_len;
unsigned long flags;
spin_lock_irqsave(&dbf->san_lock, flags);
memset(rec, 0, sizeof(*rec));
- strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
- rec->fsf_reqid = fsf_req->req_id;
- rec->fsf_seqno = fsf_req->seq_no;
- rec->u.els.d_id = d_id;
- debug_event(dbf->san, level, rec, sizeof(*rec));
- zfcp_dbf_hexdump(dbf->san, rec, sizeof(*rec), level,
- buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD));
+
+ rec->id = id;
+ rec->fsf_req_id = req_id;
+ rec->d_id = d_id;
+ rec_len = min(len, (u16)ZFCP_DBF_SAN_MAX_PAYLOAD);
+ memcpy(rec->payload, data, rec_len);
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+
+ debug_event(dbf->san, 1, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->san_lock, flags);
}
/**
- * zfcp_dbf_san_els_request - trace event for issued ELS
- * @fsf_req: request containing issued ELS
+ * zfcp_dbf_san_req - trace event for issued SAN request
+ * @tag: indentifier for event
+ * @fsf_req: request containing issued CT data
+ * d_id: destination ID
*/
-void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_dbf_san_req(char *tag, struct zfcp_fsf_req *fsf, u32 d_id)
{
- struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data;
- u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id);
+ struct zfcp_dbf *dbf = fsf->adapter->dbf;
+ struct zfcp_fsf_ct_els *ct_els = fsf->data;
+ u16 length;
- zfcp_dbf_san_els("oels", 2, fsf_req, d_id,
- sg_virt(els->req), els->req->length);
+ length = (u16)(ct_els->req->length + FC_CT_HDR_LEN);
+ zfcp_dbf_san(tag, dbf, sg_virt(ct_els->req), ZFCP_DBF_SAN_REQ, length,
+ fsf->req_id, d_id);
}
/**
- * zfcp_dbf_san_els_response - trace event for completed ELS
- * @fsf_req: request containing ELS response
+ * zfcp_dbf_san_res - trace event for received SAN request
+ * @tag: indentifier for event
+ * @fsf_req: request containing issued CT data
*/
-void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_dbf_san_res(char *tag, struct zfcp_fsf_req *fsf)
{
- struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data;
- u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id);
+ struct zfcp_dbf *dbf = fsf->adapter->dbf;
+ struct zfcp_fsf_ct_els *ct_els = fsf->data;
+ u16 length;
- zfcp_dbf_san_els("rels", 2, fsf_req, d_id,
- sg_virt(els->resp), els->resp->length);
+ length = (u16)(ct_els->resp->length + FC_CT_HDR_LEN);
+ zfcp_dbf_san(tag, dbf, sg_virt(ct_els->resp), ZFCP_DBF_SAN_RES, length,
+ fsf->req_id, 0);
}
/**
- * zfcp_dbf_san_incoming_els - trace event for incomig ELS
- * @fsf_req: request containing unsolicited status buffer with incoming ELS
+ * zfcp_dbf_san_in_els - trace event for incoming ELS
+ * @tag: indentifier for event
+ * @fsf_req: request containing issued CT data
*/
-void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *fsf_req)
+void zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf)
{
- struct fsf_status_read_buffer *buf =
- (struct fsf_status_read_buffer *)fsf_req->data;
- int length = (int)buf->length -
- (int)((void *)&buf->payload - (void *)buf);
+ struct zfcp_dbf *dbf = fsf->adapter->dbf;
+ struct fsf_status_read_buffer *srb =
+ (struct fsf_status_read_buffer *) fsf->data;
+ u16 length;
- zfcp_dbf_san_els("iels", 1, fsf_req, ntoh24(buf->d_id),
- (void *)buf->payload.data, length);
-}
-
-static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view,
- char *out_buf, const char *in_buf)
-{
- struct zfcp_dbf_san_record *r = (struct zfcp_dbf_san_record *)in_buf;
- char *p = out_buf;
-
- if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
- return 0;
-
- zfcp_dbf_tag(&p, "tag", r->tag);
- zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid);
- zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno);
-
- if (strncmp(r->tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) {
- struct zfcp_dbf_san_record_ct_request *ct = &r->u.ct_req;
- zfcp_dbf_out(&p, "d_id", "0x%06x", ct->d_id);
- zfcp_dbf_out(&p, "cmd_req_code", "0x%04x", ct->cmd_req_code);
- zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision);
- zfcp_dbf_out(&p, "gs_type", "0x%02x", ct->gs_type);
- zfcp_dbf_out(&p, "gs_subtype", "0x%02x", ct->gs_subtype);
- zfcp_dbf_out(&p, "options", "0x%02x", ct->options);
- zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size);
- } else if (strncmp(r->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) {
- struct zfcp_dbf_san_record_ct_response *ct = &r->u.ct_resp;
- zfcp_dbf_out(&p, "cmd_rsp_code", "0x%04x", ct->cmd_rsp_code);
- zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision);
- zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code);
- zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl);
- zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique);
- zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size);
- } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 ||
- strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 ||
- strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) {
- struct zfcp_dbf_san_record_els *els = &r->u.els;
- zfcp_dbf_out(&p, "d_id", "0x%06x", els->d_id);
- }
- return p - out_buf;
+ length = (u16)(srb->length -
+ offsetof(struct fsf_status_read_buffer, payload));
+ zfcp_dbf_san(tag, dbf, srb->payload.data, ZFCP_DBF_SAN_ELS, length,
+ fsf->req_id, ntoh24(srb->d_id));
}
-static struct debug_view zfcp_dbf_san_view = {
- .name = "structured",
- .header_proc = zfcp_dbf_view_header,
- .format_proc = zfcp_dbf_san_view_format,
-};
-
-void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
- struct zfcp_dbf *dbf, struct scsi_cmnd *scsi_cmnd,
- struct zfcp_fsf_req *fsf_req, unsigned long old_req_id)
+/**
+ * zfcp_dbf_scsi - trace event for scsi commands
+ * @tag: identifier for event
+ * @sc: pointer to struct scsi_cmnd
+ * @fsf: pointer to struct zfcp_fsf_req
+ */
+void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf)
{
- struct zfcp_dbf_scsi_record *rec = &dbf->scsi_buf;
- struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec;
- unsigned long flags;
+ struct zfcp_adapter *adapter =
+ (struct zfcp_adapter *) sc->device->host->hostdata[0];
+ struct zfcp_dbf *dbf = adapter->dbf;
+ struct zfcp_dbf_scsi *rec = &dbf->scsi_buf;
struct fcp_resp_with_ext *fcp_rsp;
- struct fcp_resp_rsp_info *fcp_rsp_info = NULL;
- char *fcp_sns_info = NULL;
- int offset = 0, buflen = 0;
+ struct fcp_resp_rsp_info *fcp_rsp_info;
+ unsigned long flags;
spin_lock_irqsave(&dbf->scsi_lock, flags);
- do {
- memset(rec, 0, sizeof(*rec));
- if (offset == 0) {
- strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
- strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE);
- if (scsi_cmnd != NULL) {
- if (scsi_cmnd->device) {
- rec->scsi_id = scsi_cmnd->device->id;
- rec->scsi_lun = scsi_cmnd->device->lun;
- }
- rec->scsi_result = scsi_cmnd->result;
- rec->scsi_cmnd = (unsigned long)scsi_cmnd;
- memcpy(rec->scsi_opcode, scsi_cmnd->cmnd,
- min((int)scsi_cmnd->cmd_len,
- ZFCP_DBF_SCSI_OPCODE));
- rec->scsi_retries = scsi_cmnd->retries;
- rec->scsi_allowed = scsi_cmnd->allowed;
- }
- if (fsf_req != NULL) {
- fcp_rsp = (struct fcp_resp_with_ext *)
- &(fsf_req->qtcb->bottom.io.fcp_rsp);
- fcp_rsp_info = (struct fcp_resp_rsp_info *)
- &fcp_rsp[1];
- fcp_sns_info = (char *) &fcp_rsp[1];
- if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL)
- fcp_sns_info += fcp_rsp->ext.fr_sns_len;
-
- rec->rsp_validity = fcp_rsp->resp.fr_flags;
- rec->rsp_scsi_status = fcp_rsp->resp.fr_status;
- rec->rsp_resid = fcp_rsp->ext.fr_resid;
- if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL)
- rec->rsp_code = fcp_rsp_info->rsp_code;
- if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) {
- buflen = min(fcp_rsp->ext.fr_sns_len,
- (u32)ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO);
- rec->sns_info_len = buflen;
- memcpy(rec->sns_info, fcp_sns_info,
- min(buflen,
- ZFCP_DBF_SCSI_FCP_SNS_INFO));
- offset += min(buflen,
- ZFCP_DBF_SCSI_FCP_SNS_INFO);
- }
-
- rec->fsf_reqid = fsf_req->req_id;
- rec->fsf_seqno = fsf_req->seq_no;
- rec->fsf_issued = fsf_req->issued;
- }
- rec->old_fsf_reqid = old_req_id;
- } else {
- strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE);
- dump->total_size = buflen;
- dump->offset = offset;
- dump->size = min(buflen - offset,
- (int)sizeof(struct
- zfcp_dbf_scsi_record) -
- (int)sizeof(struct zfcp_dbf_dump));
- memcpy(dump->data, fcp_sns_info + offset, dump->size);
- offset += dump->size;
- }
- debug_event(dbf->scsi, level, rec, sizeof(*rec));
- } while (offset < buflen);
- spin_unlock_irqrestore(&dbf->scsi_lock, flags);
-}
+ memset(rec, 0, sizeof(*rec));
-static int zfcp_dbf_scsi_view_format(debug_info_t *id, struct debug_view *view,
- char *out_buf, const char *in_buf)
-{
- struct zfcp_dbf_scsi_record *r = (struct zfcp_dbf_scsi_record *)in_buf;
- struct timespec t;
- char *p = out_buf;
-
- if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
- return 0;
-
- zfcp_dbf_tag(&p, "tag", r->tag);
- zfcp_dbf_tag(&p, "tag2", r->tag2);
- zfcp_dbf_out(&p, "scsi_id", "0x%08x", r->scsi_id);
- zfcp_dbf_out(&p, "scsi_lun", "0x%08x", r->scsi_lun);
- zfcp_dbf_out(&p, "scsi_result", "0x%08x", r->scsi_result);
- zfcp_dbf_out(&p, "scsi_cmnd", "0x%0Lx", r->scsi_cmnd);
- zfcp_dbf_outd(&p, "scsi_opcode", r->scsi_opcode, ZFCP_DBF_SCSI_OPCODE,
- 0, ZFCP_DBF_SCSI_OPCODE);
- zfcp_dbf_out(&p, "scsi_retries", "0x%02x", r->scsi_retries);
- zfcp_dbf_out(&p, "scsi_allowed", "0x%02x", r->scsi_allowed);
- if (strncmp(r->tag, "abrt", ZFCP_DBF_TAG_SIZE) == 0)
- zfcp_dbf_out(&p, "old_fsf_reqid", "0x%0Lx", r->old_fsf_reqid);
- zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid);
- zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno);
- stck_to_timespec(r->fsf_issued, &t);
- zfcp_dbf_out(&p, "fsf_issued", "%011lu:%06lu", t.tv_sec, t.tv_nsec);
-
- if (strncmp(r->tag, "rslt", ZFCP_DBF_TAG_SIZE) == 0) {
- zfcp_dbf_out(&p, "fcp_rsp_validity", "0x%02x", r->rsp_validity);
- zfcp_dbf_out(&p, "fcp_rsp_scsi_status", "0x%02x",
- r->rsp_scsi_status);
- zfcp_dbf_out(&p, "fcp_rsp_resid", "0x%08x", r->rsp_resid);
- zfcp_dbf_out(&p, "fcp_rsp_code", "0x%08x", r->rsp_code);
- zfcp_dbf_out(&p, "fcp_sns_info_len", "0x%08x", r->sns_info_len);
- zfcp_dbf_outd(&p, "fcp_sns_info", r->sns_info,
- min((int)r->sns_info_len,
- ZFCP_DBF_SCSI_FCP_SNS_INFO), 0,
- r->sns_info_len);
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ rec->id = ZFCP_DBF_SCSI_CMND;
+ rec->scsi_result = sc->result;
+ rec->scsi_retries = sc->retries;
+ rec->scsi_allowed = sc->allowed;
+ rec->scsi_id = sc->device->id;
+ rec->scsi_lun = sc->device->lun;
+ rec->host_scribble = (unsigned long)sc->host_scribble;
+
+ memcpy(rec->scsi_opcode, sc->cmnd,
+ min((int)sc->cmd_len, ZFCP_DBF_SCSI_OPCODE));
+
+ if (fsf) {
+ rec->fsf_req_id = fsf->req_id;
+ fcp_rsp = (struct fcp_resp_with_ext *)
+ &(fsf->qtcb->bottom.io.fcp_rsp);
+ memcpy(&rec->fcp_rsp, fcp_rsp, FCP_RESP_WITH_EXT);
+ if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) {
+ fcp_rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
+ rec->fcp_rsp_info = fcp_rsp_info->rsp_code;
+ }
+ if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) {
+ rec->pl_len = min((u16)SCSI_SENSE_BUFFERSIZE,
+ (u16)ZFCP_DBF_PAY_MAX_REC);
+ zfcp_dbf_pl_write(dbf, sc->sense_buffer, rec->pl_len,
+ "fcp_sns", fsf->req_id);
+ }
}
- p += sprintf(p, "\n");
- return p - out_buf;
-}
-static struct debug_view zfcp_dbf_scsi_view = {
- .name = "structured",
- .header_proc = zfcp_dbf_view_header,
- .format_proc = zfcp_dbf_scsi_view_format,
-};
+ debug_event(dbf->scsi, 1, rec, sizeof(*rec));
+ spin_unlock_irqrestore(&dbf->scsi_lock, flags);
+}
-static debug_info_t *zfcp_dbf_reg(const char *name, int level,
- struct debug_view *view, int size)
+static debug_info_t *zfcp_dbf_reg(const char *name, int size, int rec_size)
{
struct debug_info *d;
- d = debug_register(name, dbfsize, level, size);
+ d = debug_register(name, size, 1, rec_size);
if (!d)
return NULL;
debug_register_view(d, &debug_hex_ascii_view);
- debug_register_view(d, view);
- debug_set_level(d, level);
+ debug_set_level(d, 3);
return d;
}
+static void zfcp_dbf_unregister(struct zfcp_dbf *dbf)
+{
+ if (!dbf)
+ return;
+
+ debug_unregister(dbf->scsi);
+ debug_unregister(dbf->san);
+ debug_unregister(dbf->hba);
+ debug_unregister(dbf->pay);
+ debug_unregister(dbf->rec);
+ kfree(dbf);
+}
+
/**
* zfcp_adapter_debug_register - registers debug feature for an adapter
* @adapter: pointer to adapter for which debug features should be registered
*/
int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter)
{
- char dbf_name[DEBUG_MAX_NAME_LEN];
+ char name[DEBUG_MAX_NAME_LEN];
struct zfcp_dbf *dbf;
dbf = kzalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
if (!dbf)
return -ENOMEM;
- dbf->adapter = adapter;
-
+ spin_lock_init(&dbf->pay_lock);
spin_lock_init(&dbf->hba_lock);
spin_lock_init(&dbf->san_lock);
spin_lock_init(&dbf->scsi_lock);
spin_lock_init(&dbf->rec_lock);
/* debug feature area which records recovery activity */
- sprintf(dbf_name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev));
- dbf->rec = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_rec_view,
- sizeof(struct zfcp_dbf_rec_record));
+ sprintf(name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev));
+ dbf->rec = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_rec));
if (!dbf->rec)
goto err_out;
/* debug feature area which records HBA (FSF and QDIO) conditions */
- sprintf(dbf_name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev));
- dbf->hba = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_hba_view,
- sizeof(struct zfcp_dbf_hba_record));
+ sprintf(name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev));
+ dbf->hba = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_hba));
if (!dbf->hba)
goto err_out;
+ /* debug feature area which records payload info */
+ sprintf(name, "zfcp_%s_pay", dev_name(&adapter->ccw_device->dev));
+ dbf->pay = zfcp_dbf_reg(name, dbfsize * 2, sizeof(struct zfcp_dbf_pay));
+ if (!dbf->pay)
+ goto err_out;
+
/* debug feature area which records SAN command failures and recovery */
- sprintf(dbf_name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev));
- dbf->san = zfcp_dbf_reg(dbf_name, 6, &zfcp_dbf_san_view,
- sizeof(struct zfcp_dbf_san_record));
+ sprintf(name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev));
+ dbf->san = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_san));
if (!dbf->san)
goto err_out;
/* debug feature area which records SCSI command failures and recovery */
- sprintf(dbf_name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev));
- dbf->scsi = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_scsi_view,
- sizeof(struct zfcp_dbf_scsi_record));
+ sprintf(name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev));
+ dbf->scsi = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_scsi));
if (!dbf->scsi)
goto err_out;
adapter->dbf = dbf;
- return 0;
+ return 0;
err_out:
- zfcp_dbf_adapter_unregister(dbf);
+ zfcp_dbf_unregister(dbf);
return -ENOMEM;
}
/**
* zfcp_adapter_debug_unregister - unregisters debug feature for an adapter
- * @dbf: pointer to dbf for which debug features should be unregistered
+ * @adapter: pointer to adapter for which debug features should be unregistered
*/
-void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf)
+void zfcp_dbf_adapter_unregister(struct zfcp_adapter *adapter)
{
- if (!dbf)
- return;
- debug_unregister(dbf->scsi);
- debug_unregister(dbf->san);
- debug_unregister(dbf->hba);
- debug_unregister(dbf->rec);
- dbf->adapter->dbf = NULL;
- kfree(dbf);
+ struct zfcp_dbf *dbf = adapter->dbf;
+
+ adapter->dbf = NULL;
+ zfcp_dbf_unregister(dbf);
}
/*
- * This file is part of the zfcp device driver for
- * FCP adapters for IBM System z9 and zSeries.
+ * zfcp device driver
+ * debug feature declarations
*
- * Copyright IBM Corp. 2008, 2009
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Copyright IBM Corp. 2008, 2010
*/
#ifndef ZFCP_DBF_H
#include "zfcp_fsf.h"
#include "zfcp_def.h"
-#define ZFCP_DBF_TAG_SIZE 4
-#define ZFCP_DBF_ID_SIZE 7
+#define ZFCP_DBF_TAG_LEN 7
#define ZFCP_DBF_INVALID_LUN 0xFFFFFFFFFFFFFFFFull
-struct zfcp_dbf_dump {
- u8 tag[ZFCP_DBF_TAG_SIZE];
- u32 total_size; /* size of total dump data */
- u32 offset; /* how much data has being already dumped */
- u32 size; /* how much data comes with this record */
- u8 data[]; /* dump data */
-} __attribute__ ((packed));
-
-struct zfcp_dbf_rec_record_thread {
- u32 total;
+/**
+ * struct zfcp_dbf_rec_trigger - trace record for triggered recovery action
+ * @ready: number of ready recovery actions
+ * @running: number of running recovery actions
+ * @want: wanted recovery action
+ * @need: needed recovery action
+ */
+struct zfcp_dbf_rec_trigger {
u32 ready;
u32 running;
-};
-
-struct zfcp_dbf_rec_record_target {
- u64 ref;
- u32 status;
- u32 d_id;
- u64 wwpn;
- u64 fcp_lun;
- u32 erp_count;
-};
-
-struct zfcp_dbf_rec_record_trigger {
u8 want;
u8 need;
- u32 as;
- u32 ps;
- u32 ls;
- u64 ref;
- u64 action;
- u64 wwpn;
- u64 fcp_lun;
-};
+} __packed;
-struct zfcp_dbf_rec_record_action {
- u32 status;
- u32 step;
- u64 action;
- u64 fsf_req;
+/**
+ * struct zfcp_dbf_rec_running - trace record for running recovery
+ * @fsf_req_id: request id for fsf requests
+ * @rec_status: status of the fsf request
+ * @rec_step: current step of the recovery action
+ * rec_count: recovery counter
+ */
+struct zfcp_dbf_rec_running {
+ u64 fsf_req_id;
+ u32 rec_status;
+ u16 rec_step;
+ u8 rec_action;
+ u8 rec_count;
+} __packed;
+
+/**
+ * enum zfcp_dbf_rec_id - recovery trace record id
+ * @ZFCP_DBF_REC_TRIG: triggered recovery identifier
+ * @ZFCP_DBF_REC_RUN: running recovery identifier
+ */
+enum zfcp_dbf_rec_id {
+ ZFCP_DBF_REC_TRIG = 1,
+ ZFCP_DBF_REC_RUN = 2,
};
-struct zfcp_dbf_rec_record {
+/**
+ * struct zfcp_dbf_rec - trace record for error recovery actions
+ * @id: unique number of recovery record type
+ * @tag: identifier string specifying the location of initiation
+ * @lun: logical unit number
+ * @wwpn: word wide port number
+ * @d_id: destination ID
+ * @adapter_status: current status of the adapter
+ * @port_status: current status of the port
+ * @lun_status: current status of the lun
+ * @u.trig: structure zfcp_dbf_rec_trigger
+ * @u.run: structure zfcp_dbf_rec_running
+ */
+struct zfcp_dbf_rec {
u8 id;
- char id2[7];
+ char tag[ZFCP_DBF_TAG_LEN];
+ u64 lun;
+ u64 wwpn;
+ u32 d_id;
+ u32 adapter_status;
+ u32 port_status;
+ u32 lun_status;
union {
- struct zfcp_dbf_rec_record_action action;
- struct zfcp_dbf_rec_record_thread thread;
- struct zfcp_dbf_rec_record_target target;
- struct zfcp_dbf_rec_record_trigger trigger;
+ struct zfcp_dbf_rec_trigger trig;
+ struct zfcp_dbf_rec_running run;
} u;
-};
+} __packed;
-enum {
- ZFCP_REC_DBF_ID_ACTION,
- ZFCP_REC_DBF_ID_THREAD,
- ZFCP_REC_DBF_ID_TARGET,
- ZFCP_REC_DBF_ID_TRIGGER,
+/**
+ * enum zfcp_dbf_san_id - SAN trace record identifier
+ * @ZFCP_DBF_SAN_REQ: request trace record id
+ * @ZFCP_DBF_SAN_RES: response trace record id
+ * @ZFCP_DBF_SAN_ELS: extended link service record id
+ */
+enum zfcp_dbf_san_id {
+ ZFCP_DBF_SAN_REQ = 1,
+ ZFCP_DBF_SAN_RES = 2,
+ ZFCP_DBF_SAN_ELS = 3,
};
-struct zfcp_dbf_hba_record_response {
- u32 fsf_command;
- u64 fsf_reqid;
- u32 fsf_seqno;
- u64 fsf_issued;
- u32 fsf_prot_status;
+/** struct zfcp_dbf_san - trace record for SAN requests and responses
+ * @id: unique number of recovery record type
+ * @tag: identifier string specifying the location of initiation
+ * @fsf_req_id: request id for fsf requests
+ * @payload: unformatted information related to request/response
+ * @d_id: destination id
+ */
+struct zfcp_dbf_san {
+ u8 id;
+ char tag[ZFCP_DBF_TAG_LEN];
+ u64 fsf_req_id;
+ u32 d_id;
+#define ZFCP_DBF_SAN_MAX_PAYLOAD (FC_CT_HDR_LEN + 32)
+ char payload[ZFCP_DBF_SAN_MAX_PAYLOAD];
+} __packed;
+
+/**
+ * struct zfcp_dbf_hba_res - trace record for hba responses
+ * @req_issued: timestamp when request was issued
+ * @prot_status: protocol status
+ * @prot_status_qual: protocol status qualifier
+ * @fsf_status: fsf status
+ * @fsf_status_qual: fsf status qualifier
+ */
+struct zfcp_dbf_hba_res {
+ u64 req_issued;
+ u32 prot_status;
+ u8 prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];
u32 fsf_status;
- u8 fsf_prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];
- u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
- u32 fsf_req_status;
- u8 sbal_first;
- u8 sbal_last;
- u8 sbal_response;
- u8 pool;
- u64 erp_action;
- union {
- struct {
- u64 cmnd;
- u32 data_dir;
- } fcp;
- struct {
- u64 wwpn;
- u32 d_id;
- u32 port_handle;
- } port;
- struct {
- u64 wwpn;
- u64 fcp_lun;
- u32 port_handle;
- u32 lun_handle;
- } unit;
- struct {
- u32 d_id;
- } els;
- } u;
-} __attribute__ ((packed));
+ u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
+} __packed;
-struct zfcp_dbf_hba_record_status {
- u8 failed;
+/**
+ * struct zfcp_dbf_hba_uss - trace record for unsolicited status
+ * @status_type: type of unsolicited status
+ * @status_subtype: subtype of unsolicited status
+ * @d_id: destination ID
+ * @lun: logical unit number
+ * @queue_designator: queue designator
+ */
+struct zfcp_dbf_hba_uss {
u32 status_type;
u32 status_subtype;
- struct fsf_queue_designator
- queue_designator;
- u32 payload_size;
-#define ZFCP_DBF_UNSOL_PAYLOAD 80
-#define ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL 32
-#define ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD 56
-#define ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT 2 * sizeof(u32)
- u8 payload[ZFCP_DBF_UNSOL_PAYLOAD];
-} __attribute__ ((packed));
-
-struct zfcp_dbf_hba_record_qdio {
- u32 qdio_error;
- u8 sbal_index;
- u8 sbal_count;
-} __attribute__ ((packed));
-
-struct zfcp_dbf_hba_record {
- u8 tag[ZFCP_DBF_TAG_SIZE];
- u8 tag2[ZFCP_DBF_TAG_SIZE];
- union {
- struct zfcp_dbf_hba_record_response response;
- struct zfcp_dbf_hba_record_status status;
- struct zfcp_dbf_hba_record_qdio qdio;
- struct fsf_bit_error_payload berr;
- } u;
-} __attribute__ ((packed));
-
-struct zfcp_dbf_san_record_ct_request {
- u16 cmd_req_code;
- u8 revision;
- u8 gs_type;
- u8 gs_subtype;
- u8 options;
- u16 max_res_size;
- u32 len;
- u32 d_id;
-} __attribute__ ((packed));
-
-struct zfcp_dbf_san_record_ct_response {
- u16 cmd_rsp_code;
- u8 revision;
- u8 reason_code;
- u8 expl;
- u8 vendor_unique;
- u16 max_res_size;
- u32 len;
-} __attribute__ ((packed));
-
-struct zfcp_dbf_san_record_els {
u32 d_id;
-} __attribute__ ((packed));
+ u64 lun;
+ u64 queue_designator;
+} __packed;
-struct zfcp_dbf_san_record {
- u8 tag[ZFCP_DBF_TAG_SIZE];
- u64 fsf_reqid;
- u32 fsf_seqno;
+/**
+ * enum zfcp_dbf_hba_id - HBA trace record identifier
+ * @ZFCP_DBF_HBA_RES: response trace record
+ * @ZFCP_DBF_HBA_USS: unsolicited status trace record
+ * @ZFCP_DBF_HBA_BIT: bit error trace record
+ */
+enum zfcp_dbf_hba_id {
+ ZFCP_DBF_HBA_RES = 1,
+ ZFCP_DBF_HBA_USS = 2,
+ ZFCP_DBF_HBA_BIT = 3,
+};
+
+/**
+ * struct zfcp_dbf_hba - common trace record for HBA records
+ * @id: unique number of recovery record type
+ * @tag: identifier string specifying the location of initiation
+ * @fsf_req_id: request id for fsf requests
+ * @fsf_req_status: status of fsf request
+ * @fsf_cmd: fsf command
+ * @fsf_seq_no: fsf sequence number
+ * @pl_len: length of payload stored as zfcp_dbf_pay
+ * @u: record type specific data
+ */
+struct zfcp_dbf_hba {
+ u8 id;
+ char tag[ZFCP_DBF_TAG_LEN];
+ u64 fsf_req_id;
+ u32 fsf_req_status;
+ u32 fsf_cmd;
+ u32 fsf_seq_no;
+ u16 pl_len;
union {
- struct zfcp_dbf_san_record_ct_request ct_req;
- struct zfcp_dbf_san_record_ct_response ct_resp;
- struct zfcp_dbf_san_record_els els;
+ struct zfcp_dbf_hba_res res;
+ struct zfcp_dbf_hba_uss uss;
+ struct fsf_bit_error_payload be;
} u;
-} __attribute__ ((packed));
+} __packed;
-#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024
+/**
+ * enum zfcp_dbf_scsi_id - scsi trace record identifier
+ * @ZFCP_DBF_SCSI_CMND: scsi command trace record
+ */
+enum zfcp_dbf_scsi_id {
+ ZFCP_DBF_SCSI_CMND = 1,
+};
-struct zfcp_dbf_scsi_record {
- u8 tag[ZFCP_DBF_TAG_SIZE];
- u8 tag2[ZFCP_DBF_TAG_SIZE];
+/**
+ * struct zfcp_dbf_scsi - common trace record for SCSI records
+ * @id: unique number of recovery record type
+ * @tag: identifier string specifying the location of initiation
+ * @scsi_id: scsi device id
+ * @scsi_lun: scsi device logical unit number
+ * @scsi_result: scsi result
+ * @scsi_retries: current retry number of scsi request
+ * @scsi_allowed: allowed retries
+ * @fcp_rsp_info: FCP response info
+ * @scsi_opcode: scsi opcode
+ * @fsf_req_id: request id of fsf request
+ * @host_scribble: LLD specific data attached to SCSI request
+ * @pl_len: length of paload stored as zfcp_dbf_pay
+ * @fsf_rsp: response for fsf request
+ */
+struct zfcp_dbf_scsi {
+ u8 id;
+ char tag[ZFCP_DBF_TAG_LEN];
u32 scsi_id;
u32 scsi_lun;
u32 scsi_result;
- u64 scsi_cmnd;
-#define ZFCP_DBF_SCSI_OPCODE 16
- u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE];
u8 scsi_retries;
u8 scsi_allowed;
- u64 fsf_reqid;
- u32 fsf_seqno;
- u64 fsf_issued;
- u64 old_fsf_reqid;
- u8 rsp_validity;
- u8 rsp_scsi_status;
- u32 rsp_resid;
- u8 rsp_code;
-#define ZFCP_DBF_SCSI_FCP_SNS_INFO 16
-#define ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO 256
- u32 sns_info_len;
- u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO];
-} __attribute__ ((packed));
+ u8 fcp_rsp_info;
+#define ZFCP_DBF_SCSI_OPCODE 16
+ u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE];
+ u64 fsf_req_id;
+ u64 host_scribble;
+ u16 pl_len;
+ struct fcp_resp_with_ext fcp_rsp;
+} __packed;
+/**
+ * struct zfcp_dbf_pay - trace record for unformatted payload information
+ * @area: area this record is originated from
+ * @counter: ascending record number
+ * @fsf_req_id: request id of fsf request
+ * @data: unformatted data
+ */
+struct zfcp_dbf_pay {
+ u8 counter;
+ char area[ZFCP_DBF_TAG_LEN];
+ u64 fsf_req_id;
+#define ZFCP_DBF_PAY_MAX_REC 0x100
+ char data[ZFCP_DBF_PAY_MAX_REC];
+} __packed;
+
+/**
+ * struct zfcp_dbf - main dbf trace structure
+ * @pay: reference to payload trace area
+ * @rec: reference to recovery trace area
+ * @hba: reference to hba trace area
+ * @san: reference to san trace area
+ * @scsi: reference to scsi trace area
+ * @pay_lock: lock protecting payload trace buffer
+ * @rec_lock: lock protecting recovery trace buffer
+ * @hba_lock: lock protecting hba trace buffer
+ * @san_lock: lock protecting san trace buffer
+ * @scsi_lock: lock protecting scsi trace buffer
+ * @pay_buf: pre-allocated buffer for payload
+ * @rec_buf: pre-allocated buffer for recovery
+ * @hba_buf: pre-allocated buffer for hba
+ * @san_buf: pre-allocated buffer for san
+ * @scsi_buf: pre-allocated buffer for scsi
+ */
struct zfcp_dbf {
+ debug_info_t *pay;
debug_info_t *rec;
debug_info_t *hba;
debug_info_t *san;
debug_info_t *scsi;
+ spinlock_t pay_lock;
spinlock_t rec_lock;
spinlock_t hba_lock;
spinlock_t san_lock;
spinlock_t scsi_lock;
- struct zfcp_dbf_rec_record rec_buf;
- struct zfcp_dbf_hba_record hba_buf;
- struct zfcp_dbf_san_record san_buf;
- struct zfcp_dbf_scsi_record scsi_buf;
- struct zfcp_adapter *adapter;
+ struct zfcp_dbf_pay pay_buf;
+ struct zfcp_dbf_rec rec_buf;
+ struct zfcp_dbf_hba hba_buf;
+ struct zfcp_dbf_san san_buf;
+ struct zfcp_dbf_scsi scsi_buf;
};
static inline
-void zfcp_dbf_hba_fsf_resp(const char *tag2, int level,
- struct zfcp_fsf_req *req, struct zfcp_dbf *dbf)
+void zfcp_dbf_hba_fsf_resp(char *tag, int level, struct zfcp_fsf_req *req)
{
- if (level <= dbf->hba->level)
- _zfcp_dbf_hba_fsf_response(tag2, level, req, dbf);
+ if (level <= req->adapter->dbf->hba->level)
+ zfcp_dbf_hba_fsf_res(tag, req);
}
/**
* zfcp_dbf_hba_fsf_response - trace event for request completion
- * @fsf_req: request that has been completed
+ * @req: request that has been completed
*/
-static inline void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req)
+static inline
+void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req)
{
- struct zfcp_dbf *dbf = req->adapter->dbf;
struct fsf_qtcb *qtcb = req->qtcb;
if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
(qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
- zfcp_dbf_hba_fsf_resp("perr", 1, req, dbf);
+ zfcp_dbf_hba_fsf_resp("fs_perr", 1, req);
} else if (qtcb->header.fsf_status != FSF_GOOD) {
- zfcp_dbf_hba_fsf_resp("ferr", 1, req, dbf);
+ zfcp_dbf_hba_fsf_resp("fs_ferr", 1, req);
} else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) ||
(req->fsf_command == FSF_QTCB_OPEN_LUN)) {
- zfcp_dbf_hba_fsf_resp("open", 4, req, dbf);
+ zfcp_dbf_hba_fsf_resp("fs_open", 4, req);
} else if (qtcb->header.log_length) {
- zfcp_dbf_hba_fsf_resp("qtcb", 5, req, dbf);
+ zfcp_dbf_hba_fsf_resp("fs_qtcb", 5, req);
} else {
- zfcp_dbf_hba_fsf_resp("norm", 6, req, dbf);
+ zfcp_dbf_hba_fsf_resp("fs_norm", 6, req);
}
- }
-
-/**
- * zfcp_dbf_hba_fsf_unsol - trace event for an unsolicited status buffer
- * @tag: tag indicating which kind of unsolicited status has been received
- * @dbf: reference to dbf structure
- * @status_buffer: buffer containing payload of unsolicited status
- */
-static inline
-void zfcp_dbf_hba_fsf_unsol(const char *tag, struct zfcp_dbf *dbf,
- struct fsf_status_read_buffer *buf)
-{
- int level = 2;
-
- if (level <= dbf->hba->level)
- _zfcp_dbf_hba_fsf_unsol(tag, level, dbf, buf);
}
static inline
-void zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
- struct zfcp_dbf *dbf, struct scsi_cmnd *scmd,
- struct zfcp_fsf_req *req, unsigned long old_id)
+void _zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *scmd,
+ struct zfcp_fsf_req *req)
{
- if (level <= dbf->scsi->level)
- _zfcp_dbf_scsi(tag, tag2, level, dbf, scmd, req, old_id);
+ struct zfcp_adapter *adapter = (struct zfcp_adapter *)
+ scmd->device->host->hostdata[0];
+
+ if (level <= adapter->dbf->scsi->level)
+ zfcp_dbf_scsi(tag, scmd, req);
}
/**
* zfcp_dbf_scsi_result - trace event for SCSI command completion
- * @dbf: adapter dbf trace
* @scmd: SCSI command pointer
* @req: FSF request used to issue SCSI command
*/
static inline
-void zfcp_dbf_scsi_result(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd,
- struct zfcp_fsf_req *req)
+void zfcp_dbf_scsi_result(struct scsi_cmnd *scmd, struct zfcp_fsf_req *req)
{
if (scmd->result != 0)
- zfcp_dbf_scsi("rslt", "erro", 3, dbf, scmd, req, 0);
+ _zfcp_dbf_scsi("rsl_err", 3, scmd, req);
else if (scmd->retries > 0)
- zfcp_dbf_scsi("rslt", "retr", 4, dbf, scmd, req, 0);
+ _zfcp_dbf_scsi("rsl_ret", 4, scmd, req);
else
- zfcp_dbf_scsi("rslt", "norm", 6, dbf, scmd, req, 0);
+ _zfcp_dbf_scsi("rsl_nor", 6, scmd, req);
}
/**
* zfcp_dbf_scsi_fail_send - trace event for failure to send SCSI command
- * @dbf: adapter dbf trace
* @scmd: SCSI command pointer
*/
static inline
-void zfcp_dbf_scsi_fail_send(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd)
+void zfcp_dbf_scsi_fail_send(struct scsi_cmnd *scmd)
{
- zfcp_dbf_scsi("rslt", "fail", 4, dbf, scmd, NULL, 0);
+ _zfcp_dbf_scsi("rsl_fai", 4, scmd, NULL);
}
/**
* zfcp_dbf_scsi_abort - trace event for SCSI command abort
* @tag: tag indicating success or failure of abort operation
- * @adapter: adapter thas has been used to issue SCSI command to be aborted
* @scmd: SCSI command to be aborted
- * @new_req: request containing abort (might be NULL)
- * @old_id: identifier of request containg SCSI command to be aborted
+ * @fsf_req: request containing abort (might be NULL)
*/
static inline
-void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf,
- struct scsi_cmnd *scmd, struct zfcp_fsf_req *new_req,
- unsigned long old_id)
+void zfcp_dbf_scsi_abort(char *tag, struct scsi_cmnd *scmd,
+ struct zfcp_fsf_req *fsf_req)
{
- zfcp_dbf_scsi("abrt", tag, 1, dbf, scmd, new_req, old_id);
+ _zfcp_dbf_scsi(tag, 1, scmd, fsf_req);
}
/**
* @flag: indicates type of reset (Target Reset, Logical Unit Reset)
*/
static inline
-void zfcp_dbf_scsi_devreset(const char *tag, struct scsi_cmnd *scmnd, u8 flag)
+void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag)
{
- struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device);
+ char tmp_tag[ZFCP_DBF_TAG_LEN];
+
+ if (flag == FCP_TMF_TGT_RESET)
+ memcpy(tmp_tag, "tr_", 3);
+ else
+ memcpy(tmp_tag, "lr_", 3);
- zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1,
- zfcp_sdev->port->adapter->dbf, scmnd, NULL, 0);
+ memcpy(&tmp_tag[3], tag, 4);
+ _zfcp_dbf_scsi(tmp_tag, 1, scmnd, NULL);
}
#endif /* ZFCP_DBF_H */
struct zfcp_adapter *adapter = act->adapter;
list_move(&act->list, &act->adapter->erp_ready_head);
- zfcp_dbf_rec_action("erardy1", act);
+ zfcp_dbf_rec_run("erardy1", act);
wake_up(&adapter->erp_ready_wq);
- zfcp_dbf_rec_thread("erardy2", adapter->dbf);
+ zfcp_dbf_rec_run("erardy2", act);
}
static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
return 0;
+ if (p_status & ZFCP_STATUS_COMMON_NOESC)
+ return need;
if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
/* fall through */
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
&zfcp_sdev->status);
erp_action = &zfcp_sdev->erp_action;
+ memset(erp_action, 0, sizeof(struct zfcp_erp_action));
+ erp_action->port = port;
+ erp_action->sdev = sdev;
if (!(atomic_read(&zfcp_sdev->status) &
ZFCP_STATUS_COMMON_RUNNING))
act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
zfcp_erp_action_dismiss_port(port);
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
erp_action = &port->erp_action;
+ memset(erp_action, 0, sizeof(struct zfcp_erp_action));
+ erp_action->port = port;
if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
break;
zfcp_erp_action_dismiss_adapter(adapter);
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
erp_action = &adapter->erp_action;
+ memset(erp_action, 0, sizeof(struct zfcp_erp_action));
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING))
act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
return NULL;
}
- memset(erp_action, 0, sizeof(struct zfcp_erp_action));
erp_action->adapter = adapter;
- erp_action->port = port;
- erp_action->sdev = sdev;
erp_action->action = need;
erp_action->status = act_status;
static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
struct zfcp_port *port,
struct scsi_device *sdev,
- char *id, void *ref, u32 act_status)
+ char *id, u32 act_status)
{
int retval = 1, need;
- struct zfcp_erp_action *act = NULL;
+ struct zfcp_erp_action *act;
if (!adapter->erp_thread)
return -EIO;
++adapter->erp_total_count;
list_add_tail(&act->list, &adapter->erp_ready_head);
wake_up(&adapter->erp_ready_wq);
- zfcp_dbf_rec_thread("eracte1", adapter->dbf);
retval = 0;
out:
- zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, sdev);
+ zfcp_dbf_rec_trig(id, adapter, port, sdev, want, need);
return retval;
}
static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
- int clear_mask, char *id, void *ref)
+ int clear_mask, char *id)
{
zfcp_erp_adapter_block(adapter, clear_mask);
zfcp_scsi_schedule_rports_block(adapter);
return -EIO;
}
return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
- adapter, NULL, NULL, id, ref, 0);
+ adapter, NULL, NULL, id, 0);
}
/**
* @adapter: Adapter to reopen.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
- char *id, void *ref)
+void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, char *id)
{
unsigned long flags;
ZFCP_STATUS_COMMON_ERP_FAILED);
else
zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
- NULL, NULL, id, ref, 0);
+ NULL, NULL, id, 0);
write_unlock_irqrestore(&adapter->erp_lock, flags);
}
* @adapter: Adapter to shut down.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
- char *id, void *ref)
+ char *id)
{
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
- zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
+ zfcp_erp_adapter_reopen(adapter, clear | flags, id);
}
/**
* @port: Port to shut down.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
- void *ref)
+void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id)
{
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
- zfcp_erp_port_reopen(port, clear | flags, id, ref);
+ zfcp_erp_port_reopen(port, clear | flags, id);
}
static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
ZFCP_STATUS_COMMON_UNBLOCKED | clear);
}
-static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
- int clear, char *id, void *ref)
+static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear,
+ char *id)
{
zfcp_erp_port_block(port, clear);
zfcp_scsi_schedule_rport_block(port);
return;
zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
- port->adapter, port, NULL, id, ref, 0);
+ port->adapter, port, NULL, id, 0);
}
/**
* zfcp_erp_port_forced_reopen - Forced close of port and open again
* @port: Port to force close and to reopen.
+ * @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
- void *ref)
+void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id)
{
unsigned long flags;
struct zfcp_adapter *adapter = port->adapter;
write_lock_irqsave(&adapter->erp_lock, flags);
- _zfcp_erp_port_forced_reopen(port, clear, id, ref);
+ _zfcp_erp_port_forced_reopen(port, clear, id);
write_unlock_irqrestore(&adapter->erp_lock, flags);
}
-static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
- void *ref)
+static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id)
{
zfcp_erp_port_block(port, clear);
zfcp_scsi_schedule_rport_block(port);
}
return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
- port->adapter, port, NULL, id, ref, 0);
+ port->adapter, port, NULL, id, 0);
}
/**
* zfcp_erp_port_reopen - trigger remote port recovery
* @port: port to recover
* @clear_mask: flags in port status to be cleared
+ * @id: Id for debug trace event.
*
* Returns 0 if recovery has been triggered, < 0 if not.
*/
-int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
+int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id)
{
int retval;
unsigned long flags;
struct zfcp_adapter *adapter = port->adapter;
write_lock_irqsave(&adapter->erp_lock, flags);
- retval = _zfcp_erp_port_reopen(port, clear, id, ref);
+ retval = _zfcp_erp_port_reopen(port, clear, id);
write_unlock_irqrestore(&adapter->erp_lock, flags);
return retval;
}
static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
- void *ref, u32 act_status)
+ u32 act_status)
{
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
return;
zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter,
- zfcp_sdev->port, sdev, id, ref, act_status);
+ zfcp_sdev->port, sdev, id, act_status);
}
/**
* zfcp_erp_lun_reopen - initiate reopen of a LUN
* @sdev: SCSI device / LUN to be reopened
* @clear_mask: specifies flags in LUN status to be cleared
+ * @id: Id for debug trace event.
+ *
* Return: 0 on success, < 0 on error
*/
-void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
- void *ref)
+void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id)
{
unsigned long flags;
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
struct zfcp_adapter *adapter = port->adapter;
write_lock_irqsave(&adapter->erp_lock, flags);
- _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0);
+ _zfcp_erp_lun_reopen(sdev, clear, id, 0);
write_unlock_irqrestore(&adapter->erp_lock, flags);
}
* @sdev: SCSI device / LUN to shut down.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id,
- void *ref)
+void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id)
{
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
- zfcp_erp_lun_reopen(sdev, clear | flags, id, ref);
+ zfcp_erp_lun_reopen(sdev, clear | flags, id);
}
/**
int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
write_lock_irqsave(&adapter->erp_lock, flags);
- _zfcp_erp_lun_reopen(sdev, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF);
+ _zfcp_erp_lun_reopen(sdev, clear, id, ZFCP_STATUS_ERP_NO_REF);
write_unlock_irqrestore(&adapter->erp_lock, flags);
zfcp_erp_wait(adapter);
static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
{
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
- zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf);
+ zfcp_dbf_rec_run("eraubl1", &adapter->erp_action);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
}
static void zfcp_erp_port_unblock(struct zfcp_port *port)
{
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
- zfcp_dbf_rec_port("erpubl1", NULL, port);
+ zfcp_dbf_rec_run("erpubl1", &port->erp_action);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
}
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status))
- zfcp_dbf_rec_lun("erlubl1", NULL, sdev);
+ zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status);
}
static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
{
list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
- zfcp_dbf_rec_action("erator1", erp_action);
+ zfcp_dbf_rec_run("erator1", erp_action);
}
static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
ZFCP_STATUS_ERP_TIMEDOUT)) {
req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
- zfcp_dbf_rec_action("erscf_1", act);
+ zfcp_dbf_rec_run("erscf_1", act);
req->erp_action = NULL;
}
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
- zfcp_dbf_rec_action("erscf_2", act);
+ zfcp_dbf_rec_run("erscf_2", act);
if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
act->fsf_req_id = 0;
} else
}
static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
- int clear, char *id, void *ref)
+ int clear, char *id)
{
struct zfcp_port *port;
read_lock(&adapter->port_list_lock);
list_for_each_entry(port, &adapter->port_list, list)
- _zfcp_erp_port_reopen(port, clear, id, ref);
+ _zfcp_erp_port_reopen(port, clear, id);
read_unlock(&adapter->port_list_lock);
}
static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear,
- char *id, void *ref)
+ char *id)
{
struct scsi_device *sdev;
shost_for_each_device(sdev, port->adapter->scsi_host)
if (sdev_to_zfcp(sdev)->port == port)
- _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0);
+ _zfcp_erp_lun_reopen(sdev, clear, id, 0);
}
static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
{
switch (act->action) {
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
- _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
+ _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1");
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
- _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
+ _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2");
break;
case ZFCP_ERP_ACTION_REOPEN_PORT:
- _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
+ _zfcp_erp_port_reopen(act->port, 0, "ersff_3");
break;
case ZFCP_ERP_ACTION_REOPEN_LUN:
- _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", NULL, 0);
+ _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", 0);
break;
}
}
{
switch (act->action) {
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
- _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
+ _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1");
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
- _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
+ _zfcp_erp_port_reopen(act->port, 0, "ersfs_2");
break;
case ZFCP_ERP_ACTION_REOPEN_PORT:
- _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3", NULL);
+ _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3");
break;
}
}
read_unlock_irqrestore(&adapter->erp_lock, flags);
}
-static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
-{
- struct zfcp_qdio *qdio = act->adapter->qdio;
-
- if (zfcp_qdio_open(qdio))
- return ZFCP_ERP_FAILED;
- init_waitqueue_head(&qdio->req_q_wq);
- atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
- return ZFCP_ERP_SUCCEEDED;
-}
-
static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
{
struct zfcp_port *port;
adapter->peer_d_id);
if (IS_ERR(port)) /* error or port already attached */
return;
- _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
+ _zfcp_erp_port_reopen(port, 0, "ereptp1");
}
static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
return ZFCP_ERP_FAILED;
}
- zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);
wait_event(adapter->erp_ready_wq,
!list_empty(&adapter->erp_ready_head));
- zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);
if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
break;
if (ret)
return ZFCP_ERP_FAILED;
- zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf);
+ zfcp_dbf_rec_run("erasox1", act);
wait_event(adapter->erp_ready_wq,
!list_empty(&adapter->erp_ready_head));
- zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf);
+ zfcp_dbf_rec_run("erasox2", act);
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
return ZFCP_ERP_FAILED;
{
struct zfcp_adapter *adapter = act->adapter;
- if (zfcp_erp_adapter_strategy_open_qdio(act)) {
+ if (zfcp_qdio_open(adapter->qdio)) {
atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
&adapter->status);
if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
_zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "ersscg1", NULL);
+ "ersscg1");
return ZFCP_ERP_EXIT;
}
break;
if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
_zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "ersscg2", NULL);
+ "ersscg2");
return ZFCP_ERP_EXIT;
}
break;
if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) {
_zfcp_erp_lun_reopen(sdev,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "ersscg3", NULL, 0);
+ "ersscg3", 0);
return ZFCP_ERP_EXIT;
}
break;
}
list_del(&erp_action->list);
- zfcp_dbf_rec_action("eractd1", erp_action);
+ zfcp_dbf_rec_run("eractd1", erp_action);
switch (erp_action->action) {
case ZFCP_ERP_ACTION_REOPEN_LUN:
erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
}
if (adapter->erp_total_count == adapter->erp_low_mem_count)
- _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
+ _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1");
else {
zfcp_erp_strategy_memwait(erp_action);
retval = ZFCP_ERP_CONTINUES;
unsigned long flags;
for (;;) {
- zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);
wait_event_interruptible(adapter->erp_ready_wq,
!list_empty(&adapter->erp_ready_head) ||
kthread_should_stop());
- zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);
if (kthread_should_stop())
break;
/* zfcp_dbf.c */
extern int zfcp_dbf_adapter_register(struct zfcp_adapter *);
-extern void zfcp_dbf_adapter_unregister(struct zfcp_dbf *);
-extern void zfcp_dbf_rec_thread(char *, struct zfcp_dbf *);
-extern void zfcp_dbf_rec_thread_lock(char *, struct zfcp_dbf *);
-extern void zfcp_dbf_rec_adapter(char *, void *, struct zfcp_dbf *);
-extern void zfcp_dbf_rec_port(char *, void *, struct zfcp_port *);
-extern void zfcp_dbf_rec_lun(char *, void *, struct scsi_device *);
-extern void zfcp_dbf_rec_trigger(char *, void *, u8, u8, void *,
- struct zfcp_adapter *, struct zfcp_port *,
- struct scsi_device *);
-extern void zfcp_dbf_rec_action(char *, struct zfcp_erp_action *);
-extern void _zfcp_dbf_hba_fsf_response(const char *, int, struct zfcp_fsf_req *,
- struct zfcp_dbf *);
-extern void _zfcp_dbf_hba_fsf_unsol(const char *, int level, struct zfcp_dbf *,
- struct fsf_status_read_buffer *);
-extern void zfcp_dbf_hba_qdio(struct zfcp_dbf *, unsigned int, int, int);
+extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *);
+extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *,
+ struct zfcp_port *, struct scsi_device *, u8, u8);
+extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *);
+extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
-extern void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *, u32);
-extern void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *);
-extern void zfcp_dbf_san_els_request(struct zfcp_fsf_req *);
-extern void zfcp_dbf_san_els_response(struct zfcp_fsf_req *);
-extern void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *);
-extern void _zfcp_dbf_scsi(const char *, const char *, int, struct zfcp_dbf *,
- struct scsi_cmnd *, struct zfcp_fsf_req *,
- unsigned long);
+extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
+extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_scsi(char *, struct scsi_cmnd *, struct zfcp_fsf_req *);
/* zfcp_erp.c */
extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32);
extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32);
-extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *, void *);
-extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *,
- void *);
+extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *);
+extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *);
extern void zfcp_erp_set_port_status(struct zfcp_port *, u32);
extern void zfcp_erp_clear_port_status(struct zfcp_port *, u32);
-extern int zfcp_erp_port_reopen(struct zfcp_port *, int, char *, void *);
-extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *, void *);
-extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *,
- void *);
+extern int zfcp_erp_port_reopen(struct zfcp_port *, int, char *);
+extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *);
+extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *);
extern void zfcp_erp_set_lun_status(struct scsi_device *, u32);
extern void zfcp_erp_clear_lun_status(struct scsi_device *, u32);
-extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *, void *);
-extern void zfcp_erp_lun_shutdown(struct scsi_device *, int, char *, void *);
+extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *);
+extern void zfcp_erp_lun_shutdown(struct scsi_device *, int, char *);
extern void zfcp_erp_lun_shutdown_wait(struct scsi_device *, char *);
extern int zfcp_erp_thread_setup(struct zfcp_adapter *);
extern void zfcp_erp_thread_kill(struct zfcp_adapter *);
extern int zfcp_qdio_open(struct zfcp_qdio *);
extern void zfcp_qdio_close(struct zfcp_qdio *);
extern void zfcp_qdio_siosl(struct zfcp_adapter *);
+extern struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *,
+ struct qdio_buffer *);
/* zfcp_scsi.c */
extern struct zfcp_data zfcp_data;
if (!port->d_id)
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "fcrscn1", NULL);
+ "fcrscn1");
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
}
read_lock_irqsave(&adapter->port_list_lock, flags);
list_for_each_entry(port, &adapter->port_list, list)
if (port->wwpn == wwpn) {
- zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req);
+ zfcp_erp_port_forced_reopen(port, 0, "fciwwp1");
break;
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
(struct fsf_status_read_buffer *) fsf_req->data;
unsigned int els_type = status_buffer->payload.data[0];
- zfcp_dbf_san_incoming_els(fsf_req);
+ zfcp_dbf_san_in_els("fciels1", fsf_req);
if (els_type == ELS_PLOGI)
zfcp_fc_incoming_plogi(fsf_req);
else if (els_type == ELS_LOGO)
ret = zfcp_fc_ns_gid_pn(port);
if (ret) {
/* could not issue gid_pn for some reason */
- zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1", NULL);
+ zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1");
goto out;
}
goto out;
}
- zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL);
+ zfcp_erp_port_reopen(port, 0, "fcgpn_3");
out:
put_device(&port->dev);
}
if (adisc->els.status) {
/* request rejected or timed out */
zfcp_erp_port_forced_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fcadh_1", NULL);
+ "fcadh_1");
goto out;
}
if ((port->wwpn != adisc_resp->adisc_wwpn) ||
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) {
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fcadh_2", NULL);
+ "fcadh_2");
goto out;
}
/* send of ADISC was not possible */
atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
- zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
+ zfcp_erp_port_forced_reopen(port, 0, "fcltwk1");
out:
put_device(&port->dev);
port = zfcp_port_enqueue(adapter, acc->fp_wwpn,
ZFCP_STATUS_COMMON_NOESC, d_id);
if (!IS_ERR(port))
- zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL);
+ zfcp_erp_port_reopen(port, 0, "fcegpf1");
else if (PTR_ERR(port) != -EEXIST)
ret = PTR_ERR(port);
}
write_unlock_irqrestore(&adapter->port_list_lock, flags);
list_for_each_entry_safe(port, tmp, &remove_lh, list) {
- zfcp_erp_port_shutdown(port, 0, "fcegpf2", NULL);
+ zfcp_erp_port_shutdown(port, 0, "fcegpf2");
zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs);
}
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
zfcp_qdio_siosl(adapter);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fsrth_1", NULL);
+ "fsrth_1");
}
static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req,
{
dev_err(&req->adapter->ccw_device->dev, "FCP device not "
"operational because of an unsupported FC class\n");
- zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1", req);
+ zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
read_lock_irqsave(&adapter->port_list_lock, flags);
list_for_each_entry(port, &adapter->port_list, list)
if (port->d_id == d_id) {
- zfcp_erp_port_reopen(port, 0, "fssrpc1", req);
+ zfcp_erp_port_reopen(port, 0, "fssrpc1");
break;
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
struct fsf_status_read_buffer *sr_buf = req->data;
if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
- zfcp_dbf_hba_fsf_unsol("dism", adapter->dbf, sr_buf);
+ zfcp_dbf_hba_fsf_uss("fssrh_1", req);
mempool_free(sr_buf, adapter->pool.status_read_data);
zfcp_fsf_req_free(req);
return;
}
- zfcp_dbf_hba_fsf_unsol("read", adapter->dbf, sr_buf);
+ zfcp_dbf_hba_fsf_uss("fssrh_2", req);
switch (sr_buf->status_type) {
case FSF_STATUS_READ_PORT_CLOSED:
dev_warn(&adapter->ccw_device->dev,
"The error threshold for checksum statistics "
"has been exceeded\n");
- zfcp_dbf_hba_berr(adapter->dbf, req);
+ zfcp_dbf_hba_bit_err("fssrh_3", req);
break;
case FSF_STATUS_READ_LINK_DOWN:
zfcp_fsf_status_read_link_down(req);
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_COMMON_ERP_FAILED,
- "fssrh_2", req);
+ "fssrh_2");
zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0);
break;
"The FCP adapter reported a problem "
"that cannot be recovered\n");
zfcp_qdio_siosl(req->adapter);
- zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
+ zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1");
break;
}
/* all non-return stats set FSFREQ_ERROR*/
dev_err(&req->adapter->ccw_device->dev,
"The FCP adapter does not recognize the command 0x%x\n",
req->qtcb->header.fsf_command);
- zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1", req);
+ zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
"QTCB version 0x%x not supported by FCP adapter "
"(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
psq->word[0], psq->word[1]);
- zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1");
break;
case FSF_PROT_ERROR_STATE:
case FSF_PROT_SEQ_NUMB_ERROR:
- zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req);
+ zfcp_erp_adapter_reopen(adapter, 0, "fspse_2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PROT_UNSUPP_QTCB_TYPE:
dev_err(&adapter->ccw_device->dev,
"The QTCB type is not supported by the FCP adapter\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3");
break;
case FSF_PROT_HOST_CONNECTION_INITIALIZING:
atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
dev_err(&adapter->ccw_device->dev,
"0x%Lx is an ambiguous request identifier\n",
(unsigned long long)qtcb->bottom.support.req_handle);
- zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4");
break;
case FSF_PROT_LINK_DOWN:
zfcp_fsf_link_down_info_eval(req, &psq->link_down_info);
/* go through reopen to flush pending requests */
- zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req);
+ zfcp_erp_adapter_reopen(adapter, 0, "fspse_6");
break;
case FSF_PROT_REEST_QUEUE:
/* All ports should be marked as ready to run again */
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_COMMON_ERP_FAILED,
- "fspse_8", req);
+ "fspse_8");
break;
default:
dev_err(&adapter->ccw_device->dev,
"0x%x is not a valid transfer protocol status\n",
qtcb->prefix.prot_status);
zfcp_qdio_siosl(adapter);
- zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9");
}
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
dev_err(&adapter->ccw_device->dev,
"Unknown or unsupported arbitrated loop "
"fibre channel topology detected\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1");
return -EIO;
}
"FCP adapter maximum QTCB size (%d bytes) "
"is too small\n",
bottom->max_qtcb_size);
- zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1");
return;
}
atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
&qtcb->header.fsf_status_qual.link_down_info);
break;
default:
- zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3");
return;
}
dev_err(&adapter->ccw_device->dev,
"The FCP adapter only supports newer "
"control block versions\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4");
return;
}
if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
dev_err(&adapter->ccw_device->dev,
"The FCP adapter only supports older "
"control block versions\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5");
}
}
del_timer(&req->timer);
/* lookup request again, list might have changed */
zfcp_reqlist_find_rm(adapter->req_list, req_id);
- zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1", req);
+ zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1");
return -EIO;
}
goto out;
failed_req_send:
+ req->data = NULL;
mempool_free(sr_buf, adapter->pool.status_read_data);
failed_buf:
+ zfcp_dbf_hba_fsf_uss("fssr__1", req);
zfcp_fsf_req_free(req);
- zfcp_dbf_hba_fsf_unsol("fail", adapter->dbf, NULL);
out:
spin_unlock_irq(&qdio->req_q_lock);
return retval;
case FSF_PORT_HANDLE_NOT_VALID:
if (fsq->word[0] == fsq->word[1]) {
zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0,
- "fsafch1", req);
+ "fsafch1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
break;
case FSF_LUN_HANDLE_NOT_VALID:
if (fsq->word[0] == fsq->word[1]) {
- zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2",
- req);
+ zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
break;
zfcp_erp_set_port_status(zfcp_sdev->port,
ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_port_reopen(zfcp_sdev->port,
- ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3",
- req);
+ ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_BOXED:
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fsafch4", req);
+ "fsafch4");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
- req->data = zfcp_sdev;
+ req->data = sdev;
req->handler = zfcp_fsf_abort_fcp_command_handler;
req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
req->qtcb->header.port_handle = zfcp_sdev->port->handle;
switch (header->fsf_status) {
case FSF_GOOD:
- zfcp_dbf_san_ct_response(req);
+ zfcp_dbf_san_res("fsscth1", req);
ct->status = 0;
break;
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req);
+ zfcp_erp_adapter_reopen(adapter, 0, "fsscth1");
/* fall through */
case FSF_GENERIC_COMMAND_REJECTED:
case FSF_PAYLOAD_SIZE_MISMATCH:
req->qtcb->header.port_handle = wka_port->handle;
req->data = ct;
- zfcp_dbf_san_ct_request(req, wka_port->d_id);
+ zfcp_dbf_san_req("fssct_1", req, wka_port->d_id);
ret = zfcp_fsf_req_send(req);
if (ret)
switch (header->fsf_status) {
case FSF_GOOD:
- zfcp_dbf_san_els_response(req);
+ zfcp_dbf_san_res("fsselh1", req);
send_els->status = 0;
break;
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
req->handler = zfcp_fsf_send_els_handler;
req->data = els;
- zfcp_dbf_san_els_request(req);
+ zfcp_dbf_san_req("fssels1", req, d_id);
ret = zfcp_fsf_req_send(req);
if (ret)
switch (req->qtcb->header.fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1", req);
+ zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req);
+ zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1");
}
wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
switch (header->fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1", req);
+ zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ACCESS_DENIED:
&sdev_to_zfcp(sdev)->status);
zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fscpph2", req);
+ "fscpph2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (header->fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1", req);
+ zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1");
/* fall through */
case FSF_LUN_ALREADY_OPEN:
break;
zfcp_erp_set_port_status(zfcp_sdev->port,
ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_port_reopen(zfcp_sdev->port,
- ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2",
- req);
+ ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_SHARING_VIOLATION:
switch (req->qtcb->header.fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1",
- req);
+ zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_HANDLE_NOT_VALID:
- zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2", req);
+ zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PORT_BOXED:
zfcp_erp_set_port_status(zfcp_sdev->port,
ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_port_reopen(zfcp_sdev->port,
- ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3",
- req);
+ ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (header->fsf_status) {
case FSF_HANDLE_MISMATCH:
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1",
- req);
+ zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_FCPLUN_NOT_VALID:
case FSF_LUN_HANDLE_NOT_VALID:
- zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2", req);
+ zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
(unsigned long long)zfcp_scsi_dev_lun(sdev),
(unsigned long long)zfcp_sdev->port->wwpn);
zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0,
- "fssfch3", req);
+ "fssfch3");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_CMND_LENGTH_NOT_VALID:
(unsigned long long)zfcp_scsi_dev_lun(sdev),
(unsigned long long)zfcp_sdev->port->wwpn);
zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0,
- "fssfch4", req);
+ "fssfch4");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PORT_BOXED:
zfcp_erp_set_port_status(zfcp_sdev->port,
ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_port_reopen(zfcp_sdev->port,
- ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5",
- req);
+ ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_BOXED:
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fssfch6", req);
+ "fssfch6");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
struct fcp_resp_with_ext *fcp_rsp;
unsigned long flags;
- zfcp_fsf_fcp_handler_common(req);
-
read_lock_irqsave(&req->adapter->abort_lock, flags);
scpnt = req->data;
return;
}
+ zfcp_fsf_fcp_handler_common(req);
+
if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED);
goto skip_fsfstatus;
skip_fsfstatus:
zfcp_fsf_req_trace(req, scpnt);
- zfcp_dbf_scsi_result(req->adapter->dbf, scpnt, req);
+ zfcp_dbf_scsi_result(scpnt, req);
scpnt->host_scribble = NULL;
(scpnt->scsi_done) (scpnt);
struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
struct zfcp_qdio *qdio = adapter->qdio;
struct fsf_qtcb_bottom_io *io;
+ unsigned long flags;
if (unlikely(!(atomic_read(&zfcp_sdev->status) &
ZFCP_STATUS_COMMON_UNBLOCKED)))
return -EBUSY;
- spin_lock(&qdio->req_q_lock);
+ spin_lock_irqsave(&qdio->req_q_lock, flags);
if (atomic_read(&qdio->req_q_free) <= 0) {
atomic_inc(&qdio->req_q_full);
goto out;
zfcp_fsf_req_free(req);
scsi_cmnd->host_scribble = NULL;
out:
- spin_unlock(&qdio->req_q_lock);
+ spin_unlock_irqrestore(&qdio->req_q_lock, flags);
return retval;
}
break;
}
}
+
+struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *qdio,
+ struct qdio_buffer *sbal)
+{
+ struct qdio_buffer_element *sbale = &sbal->element[0];
+ u64 req_id = (unsigned long) sbale->addr;
+
+ return zfcp_reqlist_find(qdio->adapter->req_list, req_id);
+}
zfcp_qdio_siosl(adapter);
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
- ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL);
+ ZFCP_STATUS_COMMON_ERP_FAILED, id);
}
static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt)
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
if (unlikely(qdio_err)) {
- zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err);
return;
}
int sbal_idx, sbal_no;
if (unlikely(qdio_err)) {
- zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
return;
}
* put SBALs back to response queue
*/
if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count))
- zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2", NULL);
+ zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2");
}
static struct qdio_buffer_element *
if (!ret) {
atomic_inc(&qdio->req_q_full);
/* assume hanging outbound queue, try queue recovery */
- zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL);
+ zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1");
}
spin_lock_irq(&qdio->req_q_lock);
return -ENOMEM;
zfcp_qdio_setup_init_data(&init_data, qdio);
+ init_waitqueue_head(&qdio->req_q_wq);
return qdio_allocate(&init_data);
}
/* set index of first avalable SBALS / number of available SBALS */
qdio->req_q_idx = 0;
atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q);
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
return 0;
MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support");
#endif
+static bool allow_lun_scan = 1;
+module_param(allow_lun_scan, bool, 0600);
+MODULE_PARM_DESC(allow_lun_scan, "For NPIV, scan and attach all storage LUNs");
+
static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
int reason)
{
static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
{
- struct zfcp_adapter *adapter =
- (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
-
set_host_byte(scpnt, result);
- zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt);
+ zfcp_dbf_scsi_fail_send(scpnt);
scpnt->scsi_done(scpnt);
}
-static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
- void (*done) (struct scsi_cmnd *))
+static
+int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt)
{
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
- struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device));
int status, scsi_result, ret;
/* reset the status for this request */
scpnt->result = 0;
scpnt->host_scribble = NULL;
- scpnt->scsi_done = done;
scsi_result = fc_remote_port_chkready(rport);
if (unlikely(scsi_result)) {
scpnt->result = scsi_result;
- zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt);
+ zfcp_dbf_scsi_fail_send(scpnt);
scpnt->scsi_done(scpnt);
return 0;
}
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
struct zfcp_port *port;
struct zfcp_unit *unit;
+ int npiv = adapter->connection_features & FSF_FEATURE_NPIV_MODE;
port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
if (!port)
if (unit)
put_device(&unit->dev);
- if (!unit && !(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) {
+ if (!unit && !(allow_lun_scan && npiv)) {
put_device(&port->dev);
return -ENXIO;
}
spin_lock_init(&zfcp_sdev->latencies.lock);
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);
- zfcp_erp_lun_reopen(sdev, 0, "scsla_1", NULL);
+ zfcp_erp_lun_reopen(sdev, 0, "scsla_1");
zfcp_erp_wait(port->adapter);
return 0;
old_req = zfcp_reqlist_find(adapter->req_list, old_reqid);
if (!old_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
- zfcp_dbf_scsi_abort("lte1", adapter->dbf, scpnt, NULL,
- old_reqid);
+ zfcp_dbf_scsi_abort("abrt_or", scpnt, NULL);
return FAILED; /* completion could be in progress */
}
old_req->data = NULL;
zfcp_erp_wait(adapter);
ret = fc_block_scsi_eh(scpnt);
- if (ret)
+ if (ret) {
+ zfcp_dbf_scsi_abort("abrt_bl", scpnt, NULL);
return ret;
+ }
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
- zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL,
- old_reqid);
+ zfcp_dbf_scsi_abort("abrt_ru", scpnt, NULL);
return SUCCESS;
}
}
- if (!abrt_req)
+ if (!abrt_req) {
+ zfcp_dbf_scsi_abort("abrt_ar", scpnt, NULL);
return FAILED;
+ }
wait_for_completion(&abrt_req->completion);
if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
- dbf_tag = "okay";
+ dbf_tag = "abrt_ok";
else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
- dbf_tag = "lte2";
+ dbf_tag = "abrt_nn";
else {
- dbf_tag = "fail";
+ dbf_tag = "abrt_fa";
retval = FAILED;
}
- zfcp_dbf_scsi_abort(dbf_tag, adapter->dbf, scpnt, abrt_req, old_reqid);
+ zfcp_dbf_scsi_abort(dbf_tag, scpnt, abrt_req);
zfcp_fsf_req_free(abrt_req);
return retval;
}
struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
int ret;
- zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);
+ zfcp_erp_adapter_reopen(adapter, 0, "schrh_1");
zfcp_erp_wait(adapter);
ret = fc_block_scsi_eh(scpnt);
if (ret)
port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
if (port) {
- zfcp_erp_port_forced_reopen(port, 0, "sctrpi1", NULL);
+ zfcp_erp_port_forced_reopen(port, 0, "sctrpi1");
put_device(&port->dev);
}
}
return -EINVAL;
zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_RUNNING);
- zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2",
- NULL);
+ zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2");
zfcp_erp_wait(port->adapter);
return count;
if (sdev) {
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);
zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
- "syufai2", NULL);
+ "syufai2");
zfcp_erp_wait(unit->port->adapter);
} else
zfcp_unit_scsi_scan(unit);
zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
- "syafai2", NULL);
+ "syafai2");
zfcp_erp_wait(adapter);
out:
zfcp_ccw_adapter_put(adapter);
put_device(&port->dev);
- zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL);
+ zfcp_erp_port_shutdown(port, 0, "syprs_1");
zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs);
out:
zfcp_ccw_adapter_put(adapter);
} /* End twa_scsi_eh_reset() */
/* This is the main scsi queue function to handle scsi opcodes */
-static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
int request_id, retval;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
return retval;
} /* End twa_scsi_queue() */
+static DEF_SCSI_QCMD(twa_scsi_queue)
+
/* This function hands scsi cdb's to the firmware */
static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
{
} /* End twl_scsi_eh_reset() */
/* This is the main scsi queue function to handle scsi opcodes */
-static int twl_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
int request_id, retval;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
return retval;
} /* End twl_scsi_queue() */
+static DEF_SCSI_QCMD(twl_scsi_queue)
+
/* This function tells the controller to shut down */
static void __twl_shutdown(TW_Device_Extension *tw_dev)
{
} /* End tw_scsiop_test_unit_ready_complete() */
/* This is the main scsi queue function to handle scsi opcodes */
-static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
unsigned char *command = SCpnt->cmnd;
int request_id = 0;
return retval;
} /* End tw_scsi_queue() */
+static DEF_SCSI_QCMD(tw_scsi_queue)
+
/* This function is the interrupt service routine */
static irqreturn_t tw_interrupt(int irq, void *dev_instance)
{
#include "53c700_d.h"
-STATIC int NCR_700_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+STATIC int NCR_700_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *);
STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt);
STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt);
STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt);
return IRQ_RETVAL(handled);
}
-STATIC int
-NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
+static int
+NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
{
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
return 0;
}
+STATIC DEF_SCSI_QCMD(NCR_700_queuecommand)
+
STATIC int
NCR_700_abort(struct scsi_cmnd * SCp)
{
Outgoing Mailbox for execution by the associated Host Adapter.
*/
-static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRoutine) (struct scsi_cmnd *))
+static int BusLogic_QueueCommand_lck(struct scsi_cmnd *Command, void (*CompletionRoutine) (struct scsi_cmnd *))
{
struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata;
struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[Command->device->id];
return 0;
}
+static DEF_SCSI_QCMD(BusLogic_QueueCommand)
#if 0
/*
*/
static const char *BusLogic_DriverInfo(struct Scsi_Host *);
-static int BusLogic_QueueCommand(struct scsi_cmnd *, void (*CompletionRoutine) (struct scsi_cmnd *));
+static int BusLogic_QueueCommand(struct Scsi_Host *h, struct scsi_cmnd *);
static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device *, sector_t, int *);
static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int);
static int BusLogic_SlaveConfigure(struct scsi_device *);
* Locks: host lock taken by caller
*/
-static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int NCR5380_queue_command_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
{
struct Scsi_Host *instance = cmd->device->host;
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
return 0;
}
+static DEF_SCSI_QCMD(NCR5380_queue_command)
/**
* NCR5380_main - NCR state machines
#endif
static int NCR5380_abort(Scsi_Cmnd * cmd);
static int NCR5380_bus_reset(Scsi_Cmnd * cmd);
-static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
+static int NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,
char *buffer, char **start, off_t offset, int length, int inout);
}
#endif
-static int NCR53c406a_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int NCR53c406a_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
{
int i;
return 0;
}
+static DEF_SCSI_QCMD(NCR53c406a_queue)
+
static int NCR53c406a_host_reset(Scsi_Cmnd * SCpnt)
{
DEB(printk("NCR53c406a_reset called\n"));
* queue the command down to the controller
*/
-static int inia100_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
+static int inia100_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
{
struct orc_scb *scb;
struct orc_host *host; /* Point to Host adapter control block */
return 0;
}
+static DEF_SCSI_QCMD(inia100_queue)
+
/*****************************************************************************
Function name : inia100_abort
Description : Abort a queued command.
* TODO: unify with aac_scsi_cmd().
*/
-static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int aac_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = cmd->device->host;
struct aac_dev *dev = (struct aac_dev *)host->hostdata;
return (aac_scsi_cmd(cmd) ? FAILED : 0);
}
+static DEF_SCSI_QCMD(aac_queuecommand)
+
/**
* aac_info - Returns the host adapter name
* @shost: Scsi host to report on
* in the 'scp' result field.
*/
static int
-advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
+advansys_queuecommand_lck(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *shost = scp->device->host;
int asc_res, result = 0;
return result;
}
+static DEF_SCSI_QCMD(advansys_queuecommand)
+
static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
{
PortAddr eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
* queue a command
*
*/
-static int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int aha152x_queue_lck(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
#if 0
if(*SCpnt->cmnd == REQUEST_SENSE) {
return aha152x_internal_queue(SCpnt, NULL, 0, done);
}
+static DEF_SCSI_QCMD(aha152x_queue)
+
/*
*
};
}
-static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int aha1542_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
{
unchar ahacmd = CMD_START_SCSI;
unchar direction;
return 0;
}
+static DEF_SCSI_QCMD(aha1542_queuecommand)
+
/* Initialize mailboxes */
static void setup_mailboxes(int bse, struct Scsi_Host *shpnt)
{
};
static int aha1542_detect(struct scsi_host_template *);
-static int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int aha1542_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
static int aha1542_dev_reset(Scsi_Cmnd * SCpnt);
static int aha1542_host_reset(Scsi_Cmnd * SCpnt);
return IRQ_RETVAL(handled);
}
-static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+static int aha1740_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{
unchar direction;
unchar *cmd = (unchar *) SCpnt->cmnd;
return 0;
}
+static DEF_SCSI_QCMD(aha1740_queuecommand)
+
/* Query the board for its irq_level and irq_type. Nothing else matters
in enhanced mode on an EISA bus. */
* Queue an SCB to the controller.
*/
static int
-ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
+ahd_linux_queue_lck(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
{
struct ahd_softc *ahd;
struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device);
return rtn;
}
+static DEF_SCSI_QCMD(ahd_linux_queue)
+
static struct scsi_target **
ahd_linux_target_in_softc(struct scsi_target *starget)
{
* Queue an SCB to the controller.
*/
static int
-ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
+ahc_linux_queue_lck(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
{
struct ahc_softc *ahc;
struct ahc_linux_device *dev = scsi_transport_device_data(cmd->device);
return rtn;
}
+static DEF_SCSI_QCMD(ahc_linux_queue)
+
static inline struct scsi_target **
ahc_linux_target_in_softc(struct scsi_target *starget)
{
* Description:
* Queue a SCB to the controller.
*-F*************************************************************************/
-static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+static int aic7xxx_queue_lck(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
{
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
return (0);
}
+static DEF_SCSI_QCMD(aic7xxx_queue)
+
/*+F*************************************************************************
* Function:
* aic7xxx_bus_device_reset
static int arcmsr_bus_reset(struct scsi_cmnd *);
static int arcmsr_bios_param(struct scsi_device *sdev,
struct block_device *bdev, sector_t capacity, int *info);
-static int arcmsr_queue_command(struct scsi_cmnd *cmd,
- void (*done) (struct scsi_cmnd *));
+static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static int arcmsr_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void arcmsr_remove(struct pci_dev *pdev);
}
}
-static int arcmsr_queue_command(struct scsi_cmnd *cmd,
+static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
void (* done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = cmd->device->host;
return 0;
}
+static DEF_SCSI_QCMD(arcmsr_queue_command)
+
static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
* done - function called on completion, with pointer to command descriptor
* Returns : 0, or < 0 on error.
*/
-int acornscsi_queuecmd(struct scsi_cmnd *SCpnt,
+static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
return 0;
}
+DEF_SCSI_QCMD(acornscsi_queuecmd)
+
/*
* Prototype: void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, struct scsi_cmnd **SCpntp2, int result)
* Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
* Returns: 0 on success, else error.
* Notes: io_request_lock is held, interrupts are disabled.
*/
-int fas216_queue_command(struct scsi_cmnd *SCpnt,
+static int fas216_queue_command_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
return result;
}
+DEF_SCSI_QCMD(fas216_queue_command)
+
/**
* fas216_internal_done - trigger restart of a waiting thread in fas216_noqueue_command
* @SCpnt: Command to wake
* Returns: scsi result code.
* Notes: io_request_lock is held, interrupts are disabled.
*/
-int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
+static int fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
BUG_ON(info->scsi.irq != NO_IRQ);
info->internal_done = 0;
- fas216_queue_command(SCpnt, fas216_internal_done);
+ fas216_queue_command_lck(SCpnt, fas216_internal_done);
/*
* This wastes time, since we can't return until the command is
return 0;
}
+DEF_SCSI_QCMD(fas216_noqueue_command)
+
/*
* Error handler timeout function. Indicate that we timed out,
* and wake up any error handler process so it can continue.
*/
extern int fas216_add (struct Scsi_Host *instance, struct device *dev);
-/* Function: int fas216_queue_command(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+/* Function: int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt)
* Purpose : queue a command for adapter to process.
- * Params : SCpnt - Command to queue
- * done - done function to call once command is complete
+ * Params : h - host adapter
+ * : SCpnt - Command to queue
* Returns : 0 - success, else error
*/
-extern int fas216_queue_command(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+extern int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt);
-/* Function: int fas216_noqueue_command(istruct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+/* Function: int fas216_noqueue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt)
* Purpose : queue a command for adapter to process, and process it to completion.
- * Params : SCpnt - Command to queue
- * done - done function to call once command is complete
+ * Params : h - host adapter
+ * : SCpnt - Command to queue
* Returns : 0 - success, else error
*/
-extern int fas216_noqueue_command(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+extern int fas216_noqueue_command(struct Scsi_Host *, struct scsi_cmnd *);
/* Function: irqreturn_t fas216_intr (FAS216_Info *info)
* Purpose : handle interrupts from the interface to progress a command
*
*/
-static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
SETUP_HOSTDATA(cmd->device->host);
Scsi_Cmnd *tmp;
return 0;
}
+static DEF_SCSI_QCMD(NCR5380_queue_command)
+
/*
* Function : NCR5380_main (void)
*
}
-/* This is the wrapper function for NCR5380_queue_command(). It just
- * tries to get the lock on the ST-DMA (see above) and then calls the
- * original function.
- */
-
-#if 0
-int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
-{
- /* falcon_get_lock();
- * ++guenther: moved to NCR5380_queue_command() to prevent
- * race condition, see there for an explanation.
- */
- return NCR5380_queue_command(cmd, done);
-}
-#endif
-
-
int __init atari_scsi_detect(struct scsi_host_template *host)
{
static int called = 0;
*
* Queue a command to the ATP queue. Called with the host lock held.
*/
-static int atp870u_queuecommand(struct scsi_cmnd * req_p,
+static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
void (*done) (struct scsi_cmnd *))
{
unsigned char c;
return 0;
}
+static DEF_SCSI_QCMD(atp870u_queuecommand)
+
/**
* send_s870 - send a command to the controller
* @host: host
bfa-y := bfad.o bfad_im.o bfad_attr.o bfad_debugfs.o
bfa-y += bfa_ioc.o bfa_ioc_cb.o bfa_ioc_ct.o bfa_hw_cb.o bfa_hw_ct.o
bfa-y += bfa_fcs.o bfa_fcs_lport.o bfa_fcs_rport.o bfa_fcs_fcpim.o bfa_fcbuild.o
-bfa-y += bfa_port.o bfa_fcpim.o bfa_core.o bfa_drv.o bfa_svc.o
+bfa-y += bfa_port.o bfa_fcpim.o bfa_core.o bfa_svc.o
ccflags-y := -DBFA_PERF_BUILD
#ifndef __BFA_H__
#define __BFA_H__
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#include "bfa_cs.h"
#include "bfa_plog.h"
#include "bfa_defs_svc.h"
* Interrupt message handlers
*/
void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m);
-void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
/*
* Request and response queue related defines
struct bfa_iocfc_cfg_s *cfg,
struct bfa_meminfo_s *meminfo,
struct bfa_pcidev_s *pcidev);
-void bfa_iocfc_detach(struct bfa_s *bfa);
void bfa_iocfc_init(struct bfa_s *bfa);
void bfa_iocfc_start(struct bfa_s *bfa);
void bfa_iocfc_stop(struct bfa_s *bfa);
u32 *maxvec);
void bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start,
u32 *end);
-void bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi);
void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns);
wwn_t bfa_iocfc_get_pwwn(struct bfa_s *bfa);
wwn_t bfa_iocfc_get_nwwn(struct bfa_s *bfa);
void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
struct bfa_meminfo_s *meminfo,
struct bfa_pcidev_s *pcidev);
-void bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod);
-void bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog);
void bfa_detach(struct bfa_s *bfa);
-void bfa_init(struct bfa_s *bfa);
-void bfa_start(struct bfa_s *bfa);
-void bfa_stop(struct bfa_s *bfa);
-void bfa_attach_fcs(struct bfa_s *bfa);
void bfa_cb_init(void *bfad, bfa_status_t status);
void bfa_cb_updateq(void *bfad, bfa_status_t status);
bfa_boolean_t bfa_intx(struct bfa_s *bfa);
-void bfa_intx_disable(struct bfa_s *bfa);
-void bfa_intx_enable(struct bfa_s *bfa);
void bfa_isr_enable(struct bfa_s *bfa);
void bfa_isr_disable(struct bfa_s *bfa);
typedef void (*bfa_cb_ioc_t) (void *cbarg, enum bfa_status status);
void bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr);
-void bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr);
-void bfa_adapter_get_attr(struct bfa_s *bfa,
- struct bfa_adapter_attr_s *ad_attr);
-u64 bfa_adapter_get_id(struct bfa_s *bfa);
bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa,
struct bfa_iocfc_intr_attr_s *attr);
void bfa_iocfc_enable(struct bfa_s *bfa);
void bfa_iocfc_disable(struct bfa_s *bfa);
-void bfa_chip_reset(struct bfa_s *bfa);
-void bfa_timer_tick(struct bfa_s *bfa);
#define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout) \
bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout)
-/*
- * BFA debug API functions
- */
-bfa_status_t bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen);
-bfa_status_t bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen);
-bfa_status_t bfa_debug_fwcore(struct bfa_s *bfa, void *buf,
- u32 *offset, int *buflen);
-void bfa_debug_fwsave_clear(struct bfa_s *bfa);
-bfa_status_t bfa_fw_stats_get(struct bfa_s *bfa, void *data);
-bfa_status_t bfa_fw_stats_clear(struct bfa_s *bfa);
-
#endif /* __BFA_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#ifndef __BFA_HCB_IOIM_H__
-#define __BFA_HCB_IOIM_H__
-
-#include "bfa_os_inc.h"
-/*
- * task attribute values in FCP-2 FCP_CMND IU
- */
-#define SIMPLE_Q 0
-#define HEAD_OF_Q 1
-#define ORDERED_Q 2
-#define ACA_Q 4
-#define UNTAGGED 5
-
-static inline lun_t
-bfad_int_to_lun(u32 luno)
-{
- union {
- u16 scsi_lun[4];
- lun_t bfa_lun;
- } lun;
-
- lun.bfa_lun = 0;
- lun.scsi_lun[0] = cpu_to_be16(luno);
-
- return lun.bfa_lun;
-}
-
-/*
- * Get LUN for the I/O request
- */
-#define bfa_cb_ioim_get_lun(__dio) \
- bfad_int_to_lun(((struct scsi_cmnd *)__dio)->device->lun)
-
-/*
- * Get CDB for the I/O request
- */
-static inline u8 *
-bfa_cb_ioim_get_cdb(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
-
- return (u8 *) cmnd->cmnd;
-}
-
-/*
- * Get I/O direction (read/write) for the I/O request
- */
-static inline enum fcp_iodir
-bfa_cb_ioim_get_iodir(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- enum dma_data_direction dmadir;
-
- dmadir = cmnd->sc_data_direction;
- if (dmadir == DMA_TO_DEVICE)
- return FCP_IODIR_WRITE;
- else if (dmadir == DMA_FROM_DEVICE)
- return FCP_IODIR_READ;
- else
- return FCP_IODIR_NONE;
-}
-
-/*
- * Get IO size in bytes for the I/O request
- */
-static inline u32
-bfa_cb_ioim_get_size(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
-
- return scsi_bufflen(cmnd);
-}
-
-/*
- * Get timeout for the I/O request
- */
-static inline u8
-bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- /*
- * TBD: need a timeout for scsi passthru
- */
- if (cmnd->device->host == NULL)
- return 4;
-
- return 0;
-}
-
-/*
- * Get Command Reference Number for the I/O request. 0 if none.
- */
-static inline u8
-bfa_cb_ioim_get_crn(struct bfad_ioim_s *dio)
-{
- return 0;
-}
-
-/*
- * Get SAM-3 priority for the I/O request. 0 is default.
- */
-static inline u8
-bfa_cb_ioim_get_priority(struct bfad_ioim_s *dio)
-{
- return 0;
-}
-
-/*
- * Get task attributes for the I/O request. Default is FCP_TASK_ATTR_SIMPLE(0).
- */
-static inline u8
-bfa_cb_ioim_get_taskattr(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- u8 task_attr = UNTAGGED;
-
- if (cmnd->device->tagged_supported) {
- switch (cmnd->tag) {
- case HEAD_OF_QUEUE_TAG:
- task_attr = HEAD_OF_Q;
- break;
- case ORDERED_QUEUE_TAG:
- task_attr = ORDERED_Q;
- break;
- default:
- task_attr = SIMPLE_Q;
- break;
- }
- }
-
- return task_attr;
-}
-
-/*
- * Get CDB length in bytes for the I/O request. Default is FCP_CMND_CDB_LEN(16).
- */
-static inline u8
-bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
-
- return cmnd->cmd_len;
-}
-
-/*
- * Assign queue to be used for the I/O request. This value depends on whether
- * the driver wants to use the queues via any specific algorithm. Currently,
- * this is not supported.
- */
-#define bfa_cb_ioim_get_reqq(__dio) BFA_FALSE
-
-#endif /* __BFA_HCB_IOIM_H__ */
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_modules.h"
#include "bfi_ctreg.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(HAL, CORE);
+/*
+ * BFA module list terminated by NULL
+ */
+static struct bfa_module_s *hal_mods[] = {
+ &hal_mod_sgpg,
+ &hal_mod_fcport,
+ &hal_mod_fcxp,
+ &hal_mod_lps,
+ &hal_mod_uf,
+ &hal_mod_rport,
+ &hal_mod_fcpim,
+ NULL
+};
+
+/*
+ * Message handlers for various modules.
+ */
+static bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = {
+ bfa_isr_unhandled, /* NONE */
+ bfa_isr_unhandled, /* BFI_MC_IOC */
+ bfa_isr_unhandled, /* BFI_MC_DIAG */
+ bfa_isr_unhandled, /* BFI_MC_FLASH */
+ bfa_isr_unhandled, /* BFI_MC_CEE */
+ bfa_fcport_isr, /* BFI_MC_FCPORT */
+ bfa_isr_unhandled, /* BFI_MC_IOCFC */
+ bfa_isr_unhandled, /* BFI_MC_LL */
+ bfa_uf_isr, /* BFI_MC_UF */
+ bfa_fcxp_isr, /* BFI_MC_FCXP */
+ bfa_lps_isr, /* BFI_MC_LPS */
+ bfa_rport_isr, /* BFI_MC_RPORT */
+ bfa_itnim_isr, /* BFI_MC_ITNIM */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_READ */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_WRITE */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_IO */
+ bfa_ioim_isr, /* BFI_MC_IOIM */
+ bfa_ioim_good_comp_isr, /* BFI_MC_IOIM_IOCOM */
+ bfa_tskim_isr, /* BFI_MC_TSKIM */
+ bfa_isr_unhandled, /* BFI_MC_SBOOT */
+ bfa_isr_unhandled, /* BFI_MC_IPFC */
+ bfa_isr_unhandled, /* BFI_MC_PORT */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+};
+/*
+ * Message handlers for mailbox command classes
+ */
+static bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = {
+ NULL,
+ NULL, /* BFI_MC_IOC */
+ NULL, /* BFI_MC_DIAG */
+ NULL, /* BFI_MC_FLASH */
+ NULL, /* BFI_MC_CEE */
+ NULL, /* BFI_MC_PORT */
+ bfa_iocfc_isr, /* BFI_MC_IOCFC */
+ NULL,
+};
+
+
+
+static void
+bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi)
+{
+ struct bfa_port_s *port = &bfa->modules.port;
+ u32 dm_len;
+ u8 *dm_kva;
+ u64 dm_pa;
+
+ dm_len = bfa_port_meminfo();
+ dm_kva = bfa_meminfo_dma_virt(mi);
+ dm_pa = bfa_meminfo_dma_phys(mi);
+
+ memset(port, 0, sizeof(struct bfa_port_s));
+ bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod);
+ bfa_port_mem_claim(port, dm_kva, dm_pa);
+
+ bfa_meminfo_dma_virt(mi) = dm_kva + dm_len;
+ bfa_meminfo_dma_phys(mi) = dm_pa + dm_len;
+}
+
/*
* BFA IOC FC related definitions
*/
/*
* BFA Interrupt handling functions
*/
-static void
-bfa_msix_errint(struct bfa_s *bfa, u32 intr)
-{
- bfa_ioc_error_isr(&bfa->ioc);
-}
-
-static void
-bfa_msix_lpu(struct bfa_s *bfa)
-{
- bfa_ioc_mbox_isr(&bfa->ioc);
-}
-
static void
bfa_reqq_resume(struct bfa_s *bfa, int qid)
{
bfa_intx(bfa);
}
-/*
- * hal_intr_api
- */
bfa_boolean_t
bfa_intx(struct bfa_s *bfa)
{
return BFA_TRUE;
}
-void
-bfa_intx_enable(struct bfa_s *bfa)
-{
- writel(bfa->iocfc.intr_mask, bfa->iocfc.bfa_regs.intr_mask);
-}
-
-void
-bfa_intx_disable(struct bfa_s *bfa)
-{
- writel(-1L, bfa->iocfc.bfa_regs.intr_mask);
-}
-
void
bfa_isr_enable(struct bfa_s *bfa)
{
intr = readl(bfa->iocfc.bfa_regs.intr_status);
if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1))
- bfa_msix_lpu(bfa);
+ bfa_ioc_mbox_isr(&bfa->ioc);
intr &= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
__HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT);
}
writel(intr, bfa->iocfc.bfa_regs.intr_status);
- bfa_msix_errint(bfa, intr);
+ bfa_ioc_error_isr(&bfa->ioc);
}
}
-void
-bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func)
-{
- bfa_isrs[mc] = isr_func;
-}
-
/*
* BFA IOC FC related functions
*/
/*
- * hal_ioc_pvt BFA IOC private functions
+ * BFA IOC private functions
*/
static void
* First allocate dma memory for IOC.
*/
bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa);
- dm_kva += bfa_ioc_meminfo();
- dm_pa += bfa_ioc_meminfo();
+ dm_kva += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
+ dm_pa += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
/*
* Claim DMA-able memory for the request/response queues and for shadow
bfa_meminfo_dma_virt(meminfo) = dm_kva;
bfa_meminfo_dma_phys(meminfo) = dm_pa;
- dbgsz = bfa_ioc_debug_trcsz(bfa_auto_recover);
+ dbgsz = (bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
if (dbgsz > 0) {
bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo));
bfa_meminfo_kva(meminfo) += dbgsz;
bfa_isr_enable(bfa);
}
-/*
- * hal_ioc_public
- */
/*
* Query IOC memory requirement information.
u32 *dm_len)
{
/* dma memory for IOC */
- *dm_len += bfa_ioc_meminfo();
+ *dm_len += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
bfa_iocfc_fw_cfg_sz(cfg, dm_len);
bfa_iocfc_cqs_sz(cfg, dm_len);
- *km_len += bfa_ioc_debug_trcsz(bfa_auto_recover);
+ *km_len += (bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
}
/*
bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev);
bfa_iocfc_mem_claim(bfa, cfg, meminfo);
- bfa_timer_init(&bfa->timer_mod);
+ INIT_LIST_HEAD(&bfa->timer_mod.timer_q);
INIT_LIST_HEAD(&bfa->comp_q);
for (i = 0; i < BFI_IOC_MAX_CQS; i++)
INIT_LIST_HEAD(&bfa->reqq_waitq[i]);
}
-/*
- * Query IOC memory requirement information.
- */
-void
-bfa_iocfc_detach(struct bfa_s *bfa)
-{
- bfa_ioc_detach(&bfa->ioc);
-}
-
/*
* Query IOC memory requirement information.
*/
}
}
-void
-bfa_adapter_get_attr(struct bfa_s *bfa, struct bfa_adapter_attr_s *ad_attr)
-{
- bfa_ioc_get_adapter_attr(&bfa->ioc, ad_attr);
-}
-
-u64
-bfa_adapter_get_id(struct bfa_s *bfa)
-{
- return bfa_ioc_get_adid(&bfa->ioc);
-}
-
void
bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr)
{
return cfgrsp->pbc_cfg.nvports;
}
-/*
- * hal_api
- */
/*
* Use this function query the memory requirement of the BFA library.
for (i = 0; hal_mods[i]; i++)
hal_mods[i]->detach(bfa);
-
- bfa_iocfc_detach(bfa);
-}
-
-
-void
-bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod)
-{
- bfa->trcmod = trcmod;
-}
-
-void
-bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog)
-{
- bfa->plog = plog;
-}
-
-/*
- * Initialize IOC.
- *
- * This function will return immediately, when the IOC initialization is
- * completed, the bfa_cb_init() will be called.
- *
- * @param[in] bfa instance
- *
- * @return void
- *
- * Special Considerations:
- *
- * @note
- * When this function returns, the driver should register the interrupt service
- * routine(s) and enable the device interrupts. If this is not done,
- * bfa_cb_init() will never get called
- */
-void
-bfa_init(struct bfa_s *bfa)
-{
- bfa_iocfc_init(bfa);
-}
-
-/*
- * Use this function initiate the IOC configuration setup. This function
- * will return immediately.
- *
- * @param[in] bfa instance
- *
- * @return None
- */
-void
-bfa_start(struct bfa_s *bfa)
-{
- bfa_iocfc_start(bfa);
-}
-
-/*
- * Use this function quiese the IOC. This function will return immediately,
- * when the IOC is actually stopped, the bfad->comp will be set.
- *
- * @param[in]bfa - pointer to bfa_t.
- *
- * @return None
- *
- * Special Considerations:
- * bfad->comp can be set before or after bfa_stop() returns.
- *
- * @note
- * In case of any failure, we could handle it automatically by doing a
- * reset and then succeed the bfa_stop() call.
- */
-void
-bfa_stop(struct bfa_s *bfa)
-{
- bfa_iocfc_stop(bfa);
+ bfa_ioc_detach(&bfa->ioc);
}
void
}
}
-void
-bfa_attach_fcs(struct bfa_s *bfa)
-{
- bfa->fcs = BFA_TRUE;
-}
-
-/*
- * Periodic timer heart beat from driver
- */
-void
-bfa_timer_tick(struct bfa_s *bfa)
-{
- bfa_timer_beat(&bfa->timer_mod);
-}
/*
* Return the list of PCI vendor/device id lists supported by this
cfg->drvcfg.num_rspq_elems = BFA_RSPQ_NELEMS_MIN;
cfg->drvcfg.min_cfg = BFA_TRUE;
}
-
-void
-bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr)
-{
- bfa_ioc_get_attr(&bfa->ioc, ioc_attr);
-}
-
-/*
- * Retrieve firmware trace information on IOC failure.
- */
-bfa_status_t
-bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen)
-{
- return bfa_ioc_debug_fwsave(&bfa->ioc, trcdata, trclen);
-}
-
-/*
- * Clear the saved firmware trace information of an IOC.
- */
-void
-bfa_debug_fwsave_clear(struct bfa_s *bfa)
-{
- bfa_ioc_debug_fwsave_clear(&bfa->ioc);
-}
-
-/*
- * Fetch firmware trace data.
- *
- * @param[in] bfa BFA instance
- * @param[out] trcdata Firmware trace buffer
- * @param[in,out] trclen Firmware trace buffer len
- *
- * @retval BFA_STATUS_OK Firmware trace is fetched.
- * @retval BFA_STATUS_INPROGRESS Firmware trace fetch is in progress.
- */
-bfa_status_t
-bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen)
-{
- return bfa_ioc_debug_fwtrc(&bfa->ioc, trcdata, trclen);
-}
-
-/*
- * Dump firmware memory.
- *
- * @param[in] bfa BFA instance
- * @param[out] buf buffer for dump
- * @param[in,out] offset smem offset to start read
- * @param[in,out] buflen length of buffer
- *
- * @retval BFA_STATUS_OK Firmware memory is dumped.
- * @retval BFA_STATUS_INPROGRESS Firmware memory dump is in progress.
- */
-bfa_status_t
-bfa_debug_fwcore(struct bfa_s *bfa, void *buf, u32 *offset, int *buflen)
-{
- return bfa_ioc_debug_fwcore(&bfa->ioc, buf, offset, buflen);
-}
-/*
- * Reset hw semaphore & usage cnt regs and initialize.
- */
-void
-bfa_chip_reset(struct bfa_s *bfa)
-{
- bfa_ioc_ownership_reset(&bfa->ioc);
- bfa_ioc_pll_init(&bfa->ioc);
-}
-
-/*
- * Fetch firmware statistics data.
- *
- * @param[in] bfa BFA instance
- * @param[out] data Firmware stats buffer
- *
- * @retval BFA_STATUS_OK Firmware trace is fetched.
- */
-bfa_status_t
-bfa_fw_stats_get(struct bfa_s *bfa, void *data)
-{
- return bfa_ioc_fw_stats_get(&bfa->ioc, data);
-}
-
-bfa_status_t
-bfa_fw_stats_clear(struct bfa_s *bfa)
-{
- return bfa_ioc_fw_stats_clear(&bfa->ioc);
-}
#ifndef __BFA_CS_H__
#define __BFA_CS_H__
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
/*
* BFA TRC
#define BFA_TRC_MAX (4 * 1024)
#endif
+#define BFA_TRC_TS(_trcm) \
+ ({ \
+ struct timeval tv; \
+ \
+ do_gettimeofday(&tv); \
+ (tv.tv_sec*1000000+tv.tv_usec); \
+ })
+
#ifndef BFA_TRC_TS
#define BFA_TRC_TS(_trcm) ((_trcm)->ticks++)
#endif
struct bfa_trc_s {
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u16 fileno;
u16 line;
#else
bfa_wc_down(wc);
}
+static inline void
+wwn2str(char *wwn_str, u64 wwn)
+{
+ union {
+ u64 wwn;
+ u8 byte[8];
+ } w;
+
+ w.wwn = wwn;
+ sprintf(wwn_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", w.byte[0],
+ w.byte[1], w.byte[2], w.byte[3], w.byte[4], w.byte[5],
+ w.byte[6], w.byte[7]);
+}
+
+static inline void
+fcid2str(char *fcid_str, u32 fcid)
+{
+ union {
+ u32 fcid;
+ u8 byte[4];
+ } f;
+
+ f.fcid = fcid;
+ sprintf(fcid_str, "%02x:%02x:%02x", f.byte[1], f.byte[2], f.byte[3]);
+}
+
+#define bfa_swap_3b(_x) \
+ ((((_x) & 0xff) << 16) | \
+ ((_x) & 0x00ff00) | \
+ (((_x) & 0xff0000) >> 16))
+
+#ifndef __BIG_ENDIAN
+#define bfa_hton3b(_x) bfa_swap_3b(_x)
+#else
+#define bfa_hton3b(_x) (_x)
+#endif
+
+#define bfa_ntoh3b(_x) bfa_hton3b(_x)
+
#endif /* __BFA_CS_H__ */
#define __BFA_DEFS_H__
#include "bfa_fc.h"
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#define BFA_MFG_SERIALNUM_SIZE 11
#define STRSZ(_n) (((_n) + 4) & ~3)
* Boot lun information.
*/
struct bfa_boot_bootlun_s {
- wwn_t pwwn; /* port wwn of target */
- lun_t lun; /* 64-bit lun */
+ wwn_t pwwn; /* port wwn of target */
+ struct scsi_lun lun; /* 64-bit lun */
};
#pragma pack()
struct bfa_iocfc_intr_attr_s {
u8 coalesce; /* enable/disable coalescing */
u8 rsvd[3];
- u16 latency; /* latency in microseconds */
- u16 delay; /* delay in microseconds */
+ __be16 latency; /* latency in microseconds */
+ __be16 delay; /* delay in microseconds */
};
/*
u8 qos_enabled; /* qos enabled or not */
u8 cfg_hardalpa; /* is hard alpa configured */
u8 hardalpa; /* configured hard alpa */
- u16 maxfrsize; /* maximum frame size */
+ __be16 maxfrsize; /* maximum frame size */
u8 rx_bbcredit; /* receive buffer credits */
u8 tx_bbcredit; /* transmit buffer credits */
u8 ratelimit; /* ratelimit enabled or not */
u8 fka_disabled; /* FKA is disabled */
u8 maxsz_verified; /* FCoE max size verified */
u8 fc_map[3]; /* FC map */
- u16 vlan; /* FCoE vlan tag/priority */
+ __be16 vlan; /* FCoE vlan tag/priority */
u32 fka_adv_per; /* FIP ka advert. period */
mac_t mac; /* FCF mac */
};
+++ /dev/null
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#include "bfa_modules.h"
-
-/*
- * BFA module list terminated by NULL
- */
-struct bfa_module_s *hal_mods[] = {
- &hal_mod_sgpg,
- &hal_mod_fcport,
- &hal_mod_fcxp,
- &hal_mod_lps,
- &hal_mod_uf,
- &hal_mod_rport,
- &hal_mod_fcpim,
- NULL
-};
-
-/*
- * Message handlers for various modules.
- */
-bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = {
- bfa_isr_unhandled, /* NONE */
- bfa_isr_unhandled, /* BFI_MC_IOC */
- bfa_isr_unhandled, /* BFI_MC_DIAG */
- bfa_isr_unhandled, /* BFI_MC_FLASH */
- bfa_isr_unhandled, /* BFI_MC_CEE */
- bfa_fcport_isr, /* BFI_MC_FCPORT */
- bfa_isr_unhandled, /* BFI_MC_IOCFC */
- bfa_isr_unhandled, /* BFI_MC_LL */
- bfa_uf_isr, /* BFI_MC_UF */
- bfa_fcxp_isr, /* BFI_MC_FCXP */
- bfa_lps_isr, /* BFI_MC_LPS */
- bfa_rport_isr, /* BFI_MC_RPORT */
- bfa_itnim_isr, /* BFI_MC_ITNIM */
- bfa_isr_unhandled, /* BFI_MC_IOIM_READ */
- bfa_isr_unhandled, /* BFI_MC_IOIM_WRITE */
- bfa_isr_unhandled, /* BFI_MC_IOIM_IO */
- bfa_ioim_isr, /* BFI_MC_IOIM */
- bfa_ioim_good_comp_isr, /* BFI_MC_IOIM_IOCOM */
- bfa_tskim_isr, /* BFI_MC_TSKIM */
- bfa_isr_unhandled, /* BFI_MC_SBOOT */
- bfa_isr_unhandled, /* BFI_MC_IPFC */
- bfa_isr_unhandled, /* BFI_MC_PORT */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
-};
-
-
-/*
- * Message handlers for mailbox command classes
- */
-bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = {
- NULL,
- NULL, /* BFI_MC_IOC */
- NULL, /* BFI_MC_DIAG */
- NULL, /* BFI_MC_FLASH */
- NULL, /* BFI_MC_CEE */
- NULL, /* BFI_MC_PORT */
- bfa_iocfc_isr, /* BFI_MC_IOCFC */
- NULL,
-};
-
-
-
-void
-bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi)
-{
- struct bfa_port_s *port = &bfa->modules.port;
- u32 dm_len;
- u8 *dm_kva;
- u64 dm_pa;
-
- dm_len = bfa_port_meminfo();
- dm_kva = bfa_meminfo_dma_virt(mi);
- dm_pa = bfa_meminfo_dma_phys(mi);
-
- memset(port, 0, sizeof(struct bfa_port_s));
- bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod);
- bfa_port_mem_claim(port, dm_kva, dm_pa);
-
- bfa_meminfo_dma_virt(mi) = dm_kva + dm_len;
- bfa_meminfo_dma_phys(mi) = dm_pa + dm_len;
-}
#ifndef __BFA_FC_H__
#define __BFA_FC_H__
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
typedef u64 wwn_t;
-typedef u64 lun_t;
#define WWN_NULL (0)
#define FC_SYMNAME_MAX 256 /* max name server symbolic name size */
* Fibre Channel Header Structure (FCHS) definition
*/
struct fchs_s {
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 routing:4; /* routing bits */
u32 cat_info:4; /* category info */
#else
u8 df_ctl; /* data field control */
u16 seq_cnt; /* sequence count */
- u16 ox_id; /* originator exchange ID */
+ __be16 ox_id; /* originator exchange ID */
u16 rx_id; /* responder exchange ID */
u32 ro; /* relative offset */
struct fc_plogi_csp_s {
u8 verhi; /* FC-PH high version */
u8 verlo; /* FC-PH low version */
- u16 bbcred; /* BB_Credit */
+ __be16 bbcred; /* BB_Credit */
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u8 ciro:1, /* continuously increasing RO */
rro:1, /* random relative offset */
npiv_supp:1, /* NPIV supported */
hg_supp:1;
#endif
- u16 rxsz; /* recieve data_field size */
+ __be16 rxsz; /* recieve data_field size */
- u16 conseq;
- u16 ro_bitmap;
+ __be16 conseq;
+ __be16 ro_bitmap;
- u32 e_d_tov;
+ __be32 e_d_tov;
};
/*
* FC-PH-x. Figure 78. pg. 318.
*/
struct fc_plogi_clp_s {
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 class_valid:1;
u32 intermix:1; /* class intermix supported if set =1.
* valid only for class1. Reserved for
*/
struct fc_prli_params_s {
u32 reserved:16;
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 reserved1:5;
u32 rec_support:1;
u32 task_retry_id:1;
struct fc_prli_params_page_s {
u32 type:8;
u32 codext:8;
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 origprocasv:1;
u32 rsppav:1;
u32 imagepair:1;
struct fc_prlo_params_page_s {
u32 type:8;
u32 type_ext:8;
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 opa_valid:1; /* originator process associator
* valid
*/
u32 type:8;
u32 type_ext:8;
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 opa_valid:1; /* originator process associator
* valid
*/
u32 type:8;
u32 type_ext:8;
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 opa_valid:1;
u32 rpa_valid:1;
u32 tpo_nport_valid:1;
struct fc_rscn_pl_s {
u8 command;
u8 pagelen;
- u16 payldlen;
+ __be16 payldlen;
struct fc_rscn_event_s event[1];
};
struct fc_rnid_general_topology_data_s {
u32 vendor_unique[4];
- u32 asso_type;
+ __be32 asso_type;
u32 phy_port_num;
- u32 num_attached_nodes;
+ __be32 num_attached_nodes;
u32 node_mgmt:8;
u32 ip_version:8;
u32 udp_tcp_port_num:16;
};
struct fc_rpsc_speed_info_s {
- u16 port_speed_cap; /*! see enum fc_rpsc_speed_cap */
- u16 port_op_speed; /*! see enum fc_rpsc_op_speed */
+ __be16 port_speed_cap; /*! see enum fc_rpsc_speed_cap */
+ __be16 port_op_speed; /*! see enum fc_rpsc_op_speed */
};
enum link_e2e_beacon_subcmd {
struct fc_rpsc2_cmd_s {
struct fc_els_cmd_s els_cmd;
- u32 token;
+ __be32 token;
u16 resvd;
- u16 num_pids; /* Number of pids in the request */
+ __be16 num_pids; /* Number of pids in the request */
struct {
u32 rsvd1:8;
u32 pid:24; /* port identifier */
* RPSC2 portInfo entry structure
*/
struct fc_rpsc2_port_info_s {
- u32 pid; /* PID */
- u16 resvd1;
- u16 index; /* port number / index */
- u8 resvd2;
- u8 type; /* port type N/NL/... */
- u16 speed; /* port Operating Speed */
+ __be32 pid; /* PID */
+ u16 resvd1;
+ __be16 index; /* port number / index */
+ u8 resvd2;
+ u8 type; /* port type N/NL/... */
+ __be16 speed; /* port Operating Speed */
};
/*
struct fc_rpsc2_acc_s {
u8 els_cmd;
u8 resvd;
- u16 num_pids; /* Number of pids in the request */
+ __be16 num_pids; /* Number of pids in the request */
struct fc_rpsc2_port_info_s port_info[1]; /* port information */
};
#define FCP_CMND_LUN_LEN 8
struct fcp_cmnd_s {
- lun_t lun; /* 64-bit LU number */
- u8 crn; /* command reference number */
-#ifdef __BIGENDIAN
+ struct scsi_lun lun; /* 64-bit LU number */
+ u8 crn; /* command reference number */
+#ifdef __BIG_ENDIAN
u8 resvd:1,
priority:4, /* FCP-3: SAM-3 priority */
taskattr:3; /* scsi task attribute */
resvd:1;
#endif
u8 tm_flags; /* task management flags */
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u8 addl_cdb_len:6, /* additional CDB length words */
iodir:2; /* read/write FCP_DATA IUs */
#else
/*
* !!! additional cdb bytes follows here!!!
*/
- u32 fcp_dl; /* bytes to be transferred */
+ __be32 fcp_dl; /* bytes to be transferred */
};
#define fcp_cmnd_cdb_len(_cmnd) ((_cmnd)->addl_cdb_len * 4 + FCP_CMND_CDB_LEN)
struct fcp_resp_s {
u32 reserved[2]; /* 2 words reserved */
u16 reserved2;
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u8 reserved3:3;
u8 fcp_conf_req:1; /* FCP_CONF is requested */
u8 resid_flags:2; /* underflow/overflow */
struct fcgs_rftid_req_s {
u32 rsvd:8;
u32 dap:24; /* port identifier */
- u32 fc4_type[8]; /* fc4 types */
+ __be32 fc4_type[8]; /* fc4 types */
};
/*
/* Accept Response to GMAL */
struct fcgs_gmal_resp_s {
- u32 ms_len; /* Num of entries */
+ __be32 ms_len; /* Num of entries */
u8 ms_ma[256];
};
* FDMI attribute
*/
struct fdmi_attr_s {
- u16 type;
- u16 len;
+ __be16 type;
+ __be16 len;
u8 value[1];
};
* HBA Attribute Block
*/
struct fdmi_hba_attr_s {
- u32 attr_count; /* # of attributes */
+ __be32 attr_count; /* # of attributes */
struct fdmi_attr_s hba_attr; /* n attributes */
};
* Registered Port List
*/
struct fdmi_port_list_s {
- u32 num_ports; /* number Of Port Entries */
+ __be32 num_ports; /* number Of Port Entries */
wwn_t port_entry; /* one or more */
};
* Port Attribute Block
*/
struct fdmi_port_attr_s {
- u32 attr_count; /* # of attributes */
+ __be32 attr_count; /* # of attributes */
struct fdmi_attr_s port_attr; /* n attributes */
};
* fcbuild.c - FC link service frame building and parsing routines
*/
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#include "bfa_fcbuild.h"
/*
* static build functions
*/
static void fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
- u16 ox_id);
+ __be16 ox_id);
static void fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
- u16 ox_id);
+ __be16 ox_id);
static struct fchs_s fc_els_req_tmpl;
static struct fchs_s fc_els_rsp_tmpl;
static struct fchs_s fc_bls_req_tmpl;
fc_els_req_tmpl.cat_info = FC_CAT_LD_REQUEST;
fc_els_req_tmpl.type = FC_TYPE_ELS;
fc_els_req_tmpl.f_ctl =
- bfa_os_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
+ bfa_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
FCTL_SI_XFER);
fc_els_req_tmpl.rx_id = FC_RXID_ANY;
fc_els_rsp_tmpl.cat_info = FC_CAT_LD_REPLY;
fc_els_rsp_tmpl.type = FC_TYPE_ELS;
fc_els_rsp_tmpl.f_ctl =
- bfa_os_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
+ bfa_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
FCTL_END_SEQ | FCTL_SI_XFER);
fc_els_rsp_tmpl.rx_id = FC_RXID_ANY;
*/
fc_bls_req_tmpl.routing = FC_RTG_BASIC_LINK;
fc_bls_req_tmpl.type = FC_TYPE_BLS;
- fc_bls_req_tmpl.f_ctl = bfa_os_hton3b(FCTL_END_SEQ | FCTL_SI_XFER);
+ fc_bls_req_tmpl.f_ctl = bfa_hton3b(FCTL_END_SEQ | FCTL_SI_XFER);
fc_bls_req_tmpl.rx_id = FC_RXID_ANY;
/*
fc_bls_rsp_tmpl.cat_info = FC_CAT_BA_ACC;
fc_bls_rsp_tmpl.type = FC_TYPE_BLS;
fc_bls_rsp_tmpl.f_ctl =
- bfa_os_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
+ bfa_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
FCTL_END_SEQ | FCTL_SI_XFER);
fc_bls_rsp_tmpl.rx_id = FC_RXID_ANY;
fcp_fchs_tmpl.cat_info = FC_CAT_UNSOLICIT_CMD;
fcp_fchs_tmpl.type = FC_TYPE_FCP;
fcp_fchs_tmpl.f_ctl =
- bfa_os_hton3b(FCTL_FS_EXCH | FCTL_END_SEQ | FCTL_SI_XFER);
+ bfa_hton3b(FCTL_FS_EXCH | FCTL_END_SEQ | FCTL_SI_XFER);
fcp_fchs_tmpl.seq_id = 1;
fcp_fchs_tmpl.rx_id = FC_RXID_ANY;
}
fchs->cat_info = FC_CAT_UNSOLICIT_CTRL;
fchs->type = FC_TYPE_SERVICES;
fchs->f_ctl =
- bfa_os_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
+ bfa_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
FCTL_SI_XFER);
fchs->rx_id = FC_RXID_ANY;
fchs->d_id = (d_id);
}
void
-fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
+fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id)
{
memcpy(fchs, &fc_els_req_tmpl, sizeof(struct fchs_s));
fchs->d_id = (d_id);
}
static void
-fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
+fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id)
{
memcpy(fchs, &fc_els_rsp_tmpl, sizeof(struct fchs_s));
fchs->d_id = d_id;
}
static void
-fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
+fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id)
{
memcpy(fchs, &fc_bls_rsp_tmpl, sizeof(struct fchs_s));
fchs->d_id = d_id;
static u16
fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
- u16 ox_id, wwn_t port_name, wwn_t node_name,
+ __be16 ox_id, wwn_t port_name, wwn_t node_name,
u16 pdu_size, u8 els_code)
{
struct fc_logi_s *plogi = (struct fc_logi_s *) (pld);
u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size,
u8 set_npiv, u8 set_auth, u16 local_bb_credits)
{
- u32 d_id = bfa_os_hton3b(FC_FABRIC_PORT);
- u32 *vvl_info;
+ u32 d_id = bfa_hton3b(FC_FABRIC_PORT);
+ __be32 *vvl_info;
memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
u16
fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
- u16 ox_id, wwn_t port_name, wwn_t node_name,
+ __be16 ox_id, wwn_t port_name, wwn_t node_name,
u16 pdu_size, u16 local_bb_credits)
{
u32 d_id = 0;
fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size)
{
- u32 d_id = bfa_os_hton3b(FC_FABRIC_PORT);
+ u32 d_id = bfa_hton3b(FC_FABRIC_PORT);
memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
u16
fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
- u16 ox_id, enum bfa_lport_role role)
+ __be16 ox_id, enum bfa_lport_role role)
{
struct fc_prli_s *prli = (struct fc_prli_s *) (pld);
return sizeof(struct fc_logo_s);
}
-static u16
+static u16
fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
- u32 s_id, u16 ox_id, wwn_t port_name,
+ u32 s_id, __be16 ox_id, wwn_t port_name,
wwn_t node_name, u8 els_code)
{
memset(adisc, '\0', sizeof(struct fc_adisc_s));
u16
fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
- u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name)
+ u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name)
{
return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name,
node_name, FC_ELS_ADISC);
u16
fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
- u32 s_id, u16 ox_id, wwn_t port_name,
+ u32 s_id, __be16 ox_id, wwn_t port_name,
wwn_t node_name)
{
return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name,
u16
fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
- u16 ox_id)
+ __be16 ox_id)
{
struct fc_els_cmd_s *acc = pld;
u16
fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id,
- u32 s_id, u16 ox_id, u8 reason_code,
+ u32 s_id, __be16 ox_id, u8 reason_code,
u8 reason_code_expl)
{
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
u16
fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id,
- u32 s_id, u16 ox_id, u16 rx_id)
+ u32 s_id, __be16 ox_id, u16 rx_id)
{
fc_bls_rsp_build(fchs, d_id, s_id, ox_id);
u16
fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, u32 d_id,
- u32 s_id, u16 ox_id)
+ u32 s_id, __be16 ox_id)
{
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
memset(els_cmd, 0, sizeof(struct fc_els_cmd_s));
u16
fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
- u32 d_id, u32 s_id, u16 ox_id, int num_pages)
+ u32 d_id, u32 s_id, __be16 ox_id, int num_pages)
{
int page;
u16
fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id,
- u32 s_id, u16 ox_id, int num_pages)
+ u32 s_id, __be16 ox_id, int num_pages)
{
int page;
u16
fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u32 d_id,
- u32 s_id, u16 ox_id, u32 data_format,
+ u32 s_id, __be16 ox_id, u32 data_format,
struct fc_rnid_common_id_data_s *common_id_data,
struct fc_rnid_general_topology_data_s *gen_topo_data)
{
fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2, u32 d_id,
u32 s_id, u32 *pid_list, u16 npids)
{
- u32 dctlr_id = FC_DOMAIN_CTRLR(bfa_os_hton3b(d_id));
+ u32 dctlr_id = FC_DOMAIN_CTRLR(bfa_hton3b(d_id));
int i = 0;
- fc_els_req_build(fchs, bfa_os_hton3b(dctlr_id), s_id, 0);
+ fc_els_req_build(fchs, bfa_hton3b(dctlr_id), s_id, 0);
memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s));
u16
fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc,
- u32 d_id, u32 s_id, u16 ox_id,
+ u32 d_id, u32 s_id, __be16 ox_id,
struct fc_rpsc_speed_info_s *oper_speed)
{
memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s));
return sizeof(struct fc_rpsc_acc_s);
}
-/*
- * TBD -
- * . get rid of unnecessary memsets
- */
-
u16
fc_logo_rsp_parse(struct fchs_s *fchs, int len)
{
}
u16
-fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
+fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id,
u32 reason_code, u32 reason_expl)
{
struct fc_ba_rjt_s *ba_rjt = (struct fc_ba_rjt_s *) (fchs + 1);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_gidpn_req_s *gidpn = (struct fcgs_gidpn_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_GID_PN);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
fcgs_gpnid_req_t *gpnid = (fcgs_gpnid_req_t *) (cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_GPN_ID);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
fcgs_gnnid_req_t *gnnid = (fcgs_gnnid_req_t *) (cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_GNN_ID);
fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr,
u8 set_br_reg, u32 s_id, u16 ox_id)
{
- u32 d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER);
+ u32 d_id = bfa_hton3b(FC_FABRIC_CONTROLLER);
fc_els_req_build(fchs, d_id, s_id, ox_id);
fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn,
u32 s_id, u16 ox_id)
{
- u32 d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER);
+ u32 d_id = bfa_hton3b(FC_FABRIC_CONTROLLER);
u16 payldlen;
fc_els_req_build(fchs, d_id, s_id, ox_id);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rftid_req_s *rftid = (struct fcgs_rftid_req_s *)(cthdr + 1);
- u32 type_value, d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 type_value, d_id = bfa_hton3b(FC_NAME_SERVER);
u8 index;
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rftid_req_s *rftid = (struct fcgs_rftid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rffid_req_s *rffid = (struct fcgs_rffid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_RFF_ID);
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rspnid_req_s *rspnid =
(struct fcgs_rspnid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_RSPN_ID);
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_gidft_req_s *gidft = (struct fcgs_gidft_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rpnid_req_s *rpnid = (struct fcgs_rpnid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_RPN_ID);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rnnid_req_s *rnnid = (struct fcgs_rnnid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_RNN_ID);
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rcsid_req_s *rcsid =
(struct fcgs_rcsid_req_s *) (cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_RCS_ID);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rptid_req_s *rptid = (struct fcgs_rptid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_RPT_ID);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_ganxt_req_s *ganxt = (struct fcgs_ganxt_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_GA_NXT);
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
- u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+ u32 d_id = bfa_hton3b(FC_MGMT_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_fdmi_cthdr_build(cthdr, s_id, cmd_code);
fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask)
{
u8 index;
- u32 *ptr = (u32 *) bit_mask;
+ __be32 *ptr = (__be32 *) bit_mask;
u32 type_value;
/*
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
fcgs_gmal_req_t *gmal = (fcgs_gmal_req_t *) (cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+ u32 d_id = bfa_hton3b(FC_MGMT_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GMAL_CMD,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
fcgs_gfn_req_t *gfn = (fcgs_gfn_req_t *) (cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+ u32 d_id = bfa_hton3b(FC_MGMT_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GFN_CMD,
#ifndef __FCBUILD_H__
#define __FCBUILD_H__
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#include "bfa_fc.h"
#include "bfa_defs_fcs.h"
u16 pdu_size);
u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi,
- u32 s_id, u16 ox_id,
+ u32 s_id, __be16 ox_id,
wwn_t port_name, wwn_t node_name,
u16 pdu_size,
u16 local_bb_credits);
u16 pdu_size);
u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc,
- u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name,
+ u32 d_id, u32 s_id, __be16 ox_id, wwn_t port_name,
wwn_t node_name);
enum fc_parse_status fc_adisc_parse(struct fchs_s *fchs, void *pld,
wwn_t port_name, wwn_t node_name);
u16 fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc,
- u32 d_id, u32 s_id, u16 ox_id,
+ u32 d_id, u32 s_id, __be16 ox_id,
wwn_t port_name, wwn_t node_name);
u16 fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt,
- u32 d_id, u32 s_id, u16 ox_id,
+ u32 d_id, u32 s_id, __be16 ox_id,
u8 reason_code, u8 reason_code_expl);
u16 fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd,
- u32 d_id, u32 s_id, u16 ox_id);
+ u32 d_id, u32 s_id, __be16 ox_id);
u16 fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id,
u32 s_id, u16 ox_id);
enum fc_parse_status fc_prli_rsp_parse(struct fc_prli_s *prli, int len);
u16 fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
- u32 s_id, u16 ox_id,
+ u32 s_id, __be16 ox_id,
enum bfa_lport_role role);
u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid,
u16 fc_rnid_acc_build(struct fchs_s *fchs,
struct fc_rnid_acc_s *rnid_acc, u32 d_id, u32 s_id,
- u16 ox_id, u32 data_format,
+ __be16 ox_id, u32 data_format,
struct fc_rnid_common_id_data_s *common_id_data,
struct fc_rnid_general_topology_data_s *gen_topo_data);
u32 d_id, u32 s_id, u16 ox_id);
u16 fc_rpsc_acc_build(struct fchs_s *fchs,
struct fc_rpsc_acc_s *rpsc_acc, u32 d_id, u32 s_id,
- u16 ox_id, struct fc_rpsc_speed_info_s *oper_speed);
+ __be16 ox_id, struct fc_rpsc_speed_info_s *oper_speed);
u16 fc_gid_ft_build(struct fchs_s *fchs, void *pld, u32 s_id,
u8 fc4_type);
u32 s_id, u16 ox_id, wwn_t port_name);
u16 fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
- u32 s_id, u16 ox_id);
+ u32 s_id, __be16 ox_id);
u16 fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id,
u16 cmd_code);
void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask);
void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
- u16 ox_id);
+ __be16 ox_id);
enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len);
wwn_t port_name);
u16 fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id,
- u32 s_id, u16 ox_id, u16 rx_id);
+ u32 s_id, __be16 ox_id, u16 rx_id);
int fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code);
u16 fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
- u32 d_id, u32 s_id, u16 ox_id, int num_pages);
+ u32 d_id, u32 s_id, __be16 ox_id, int num_pages);
u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc,
- u32 d_id, u32 s_id, u16 ox_id, int num_pages);
+ u32 d_id, u32 s_id, __be16 ox_id, int num_pages);
u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len);
u16 fc_tprlo_rsp_parse(struct fchs_s *fchs, int len);
u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
- u16 ox_id, u32 reason_code, u32 reason_expl);
+ __be16 ox_id, u32 reason_code, u32 reason_expl);
u16 fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
u32 port_id);
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_modules.h"
-#include "bfa_cb_ioim.h"
BFA_TRC_FILE(HAL, FCPIM);
BFA_MODULE(fcpim);
-
-#define bfa_fcpim_add_iostats(__l, __r, __stats) \
- (__l->__stats += __r->__stats)
-
-
/*
* BFA ITNIM Related definitions
*/
} while (0)
/*
- * bfa_itnim_sm BFA itnim state machine
+ * itnim state machine event
*/
-
-
enum bfa_itnim_event {
BFA_ITNIM_SM_CREATE = 1, /* itnim is created */
BFA_ITNIM_SM_ONLINE = 2, /* itnim is online */
if ((__fcpim)->profile_start) \
(__fcpim)->profile_start(__ioim); \
} while (0)
-/*
- * hal_ioim_sm
- */
/*
* IO state machine events
* forward declaration for BFA IOIM functions
*/
static bfa_boolean_t bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim);
-static bfa_boolean_t bfa_ioim_sge_setup(struct bfa_ioim_s *ioim);
-static void bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim);
+static bfa_boolean_t bfa_ioim_sgpg_alloc(struct bfa_ioim_s *ioim);
static bfa_boolean_t bfa_ioim_send_abort(struct bfa_ioim_s *ioim);
static void bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim);
static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete);
static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete);
static bfa_boolean_t bfa_ioim_is_abortable(struct bfa_ioim_s *ioim);
-
/*
* forward declaration of BFA IO state machine
*/
enum bfa_ioim_event event);
static void bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim,
enum bfa_ioim_event event);
-
/*
* forward declaration for BFA TSKIM functions
*/
static void __bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete);
static void __bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete);
static bfa_boolean_t bfa_tskim_match_scope(struct bfa_tskim_s *tskim,
- lun_t lun);
+ struct scsi_lun lun);
static void bfa_tskim_gather_ios(struct bfa_tskim_s *tskim);
static void bfa_tskim_cleanp_comp(void *tskim_cbarg);
static void bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim);
static bfa_boolean_t bfa_tskim_send_abort(struct bfa_tskim_s *tskim);
static void bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim);
-
/*
* forward declaration of BFA TSKIM state machine
*/
enum bfa_tskim_event event);
static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim,
enum bfa_tskim_event event);
-
/*
- * hal_fcpim_mod BFA FCP Initiator Mode module
+ * BFA FCP Initiator Mode module
*/
/*
- * Compute and return memory needed by FCP(im) module.
+ * Compute and return memory needed by FCP(im) module.
*/
static void
bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
static void
bfa_fcpim_detach(struct bfa_s *bfa)
{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
-
- bfa_ioim_detach(fcpim);
- bfa_tskim_detach(fcpim);
}
static void
}
}
-void
-bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats,
- struct bfa_itnim_iostats_s *rstats)
-{
- bfa_fcpim_add_iostats(lstats, rstats, total_ios);
- bfa_fcpim_add_iostats(lstats, rstats, qresumes);
- bfa_fcpim_add_iostats(lstats, rstats, no_iotags);
- bfa_fcpim_add_iostats(lstats, rstats, io_aborts);
- bfa_fcpim_add_iostats(lstats, rstats, no_tskims);
- bfa_fcpim_add_iostats(lstats, rstats, iocomp_ok);
- bfa_fcpim_add_iostats(lstats, rstats, iocomp_underrun);
- bfa_fcpim_add_iostats(lstats, rstats, iocomp_overrun);
- bfa_fcpim_add_iostats(lstats, rstats, iocomp_aborted);
- bfa_fcpim_add_iostats(lstats, rstats, iocomp_timedout);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_nexus_abort);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_proto_err);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_dif_err);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_sqer_needed);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_res_free);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_hostabrts);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_utags);
- bfa_fcpim_add_iostats(lstats, rstats, io_cleanups);
- bfa_fcpim_add_iostats(lstats, rstats, io_tmaborts);
- bfa_fcpim_add_iostats(lstats, rstats, onlines);
- bfa_fcpim_add_iostats(lstats, rstats, offlines);
- bfa_fcpim_add_iostats(lstats, rstats, creates);
- bfa_fcpim_add_iostats(lstats, rstats, deletes);
- bfa_fcpim_add_iostats(lstats, rstats, create_comps);
- bfa_fcpim_add_iostats(lstats, rstats, delete_comps);
- bfa_fcpim_add_iostats(lstats, rstats, sler_events);
- bfa_fcpim_add_iostats(lstats, rstats, fw_create);
- bfa_fcpim_add_iostats(lstats, rstats, fw_delete);
- bfa_fcpim_add_iostats(lstats, rstats, ioc_disabled);
- bfa_fcpim_add_iostats(lstats, rstats, cleanup_comps);
- bfa_fcpim_add_iostats(lstats, rstats, tm_cmnds);
- bfa_fcpim_add_iostats(lstats, rstats, tm_fw_rsps);
- bfa_fcpim_add_iostats(lstats, rstats, tm_success);
- bfa_fcpim_add_iostats(lstats, rstats, tm_failures);
- bfa_fcpim_add_iostats(lstats, rstats, tm_io_comps);
- bfa_fcpim_add_iostats(lstats, rstats, tm_qresumes);
- bfa_fcpim_add_iostats(lstats, rstats, tm_iocdowns);
- bfa_fcpim_add_iostats(lstats, rstats, tm_cleanups);
- bfa_fcpim_add_iostats(lstats, rstats, tm_cleanup_comps);
- bfa_fcpim_add_iostats(lstats, rstats, io_comps);
- bfa_fcpim_add_iostats(lstats, rstats, input_reqs);
- bfa_fcpim_add_iostats(lstats, rstats, output_reqs);
- bfa_fcpim_add_iostats(lstats, rstats, rd_throughput);
- bfa_fcpim_add_iostats(lstats, rstats, wr_throughput);
-}
-
void
bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov)
{
return fcpim->path_tov / 1000;
}
-bfa_status_t
-bfa_fcpim_port_iostats(struct bfa_s *bfa, struct bfa_itnim_iostats_s *stats,
- u8 lp_tag)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- struct list_head *qe, *qen;
- struct bfa_itnim_s *itnim;
-
- /* accumulate IO stats from itnim */
- memset(stats, 0, sizeof(struct bfa_itnim_iostats_s));
- list_for_each_safe(qe, qen, &fcpim->itnim_q) {
- itnim = (struct bfa_itnim_s *) qe;
- if (itnim->rport->rport_info.lp_tag != lp_tag)
- continue;
- bfa_fcpim_add_stats(stats, &(itnim->stats));
- }
- return BFA_STATUS_OK;
-}
-bfa_status_t
-bfa_fcpim_get_modstats(struct bfa_s *bfa, struct bfa_itnim_iostats_s *modstats)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- struct list_head *qe, *qen;
- struct bfa_itnim_s *itnim;
-
- /* accumulate IO stats from itnim */
- memset(modstats, 0, sizeof(struct bfa_itnim_iostats_s));
- list_for_each_safe(qe, qen, &fcpim->itnim_q) {
- itnim = (struct bfa_itnim_s *) qe;
- bfa_fcpim_add_stats(modstats, &(itnim->stats));
- }
- return BFA_STATUS_OK;
-}
-
-bfa_status_t
-bfa_fcpim_get_del_itn_stats(struct bfa_s *bfa,
- struct bfa_fcpim_del_itn_stats_s *modstats)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
-
- *modstats = fcpim->del_itn_stats;
-
- return BFA_STATUS_OK;
-}
-
-
-bfa_status_t
-bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time)
-{
- struct bfa_itnim_s *itnim;
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- struct list_head *qe, *qen;
-
- /* accumulate IO stats from itnim */
- list_for_each_safe(qe, qen, &fcpim->itnim_q) {
- itnim = (struct bfa_itnim_s *) qe;
- bfa_itnim_clear_stats(itnim);
- }
- fcpim->io_profile = BFA_TRUE;
- fcpim->io_profile_start_time = time;
- fcpim->profile_comp = bfa_ioim_profile_comp;
- fcpim->profile_start = bfa_ioim_profile_start;
-
- return BFA_STATUS_OK;
-}
-bfa_status_t
-bfa_fcpim_profile_off(struct bfa_s *bfa)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- fcpim->io_profile = BFA_FALSE;
- fcpim->io_profile_start_time = 0;
- fcpim->profile_comp = NULL;
- fcpim->profile_start = NULL;
- return BFA_STATUS_OK;
-}
-
-bfa_status_t
-bfa_fcpim_port_clear_iostats(struct bfa_s *bfa, u8 lp_tag)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- struct list_head *qe, *qen;
- struct bfa_itnim_s *itnim;
-
- /* clear IO stats from all active itnims */
- list_for_each_safe(qe, qen, &fcpim->itnim_q) {
- itnim = (struct bfa_itnim_s *) qe;
- if (itnim->rport->rport_info.lp_tag != lp_tag)
- continue;
- bfa_itnim_clear_stats(itnim);
- }
- return BFA_STATUS_OK;
-
-}
-
-bfa_status_t
-bfa_fcpim_clr_modstats(struct bfa_s *bfa)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- struct list_head *qe, *qen;
- struct bfa_itnim_s *itnim;
-
- /* clear IO stats from all active itnims */
- list_for_each_safe(qe, qen, &fcpim->itnim_q) {
- itnim = (struct bfa_itnim_s *) qe;
- bfa_itnim_clear_stats(itnim);
- }
- memset(&fcpim->del_itn_stats, 0,
- sizeof(struct bfa_fcpim_del_itn_stats_s));
-
- return BFA_STATUS_OK;
-}
-
-void
-bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
-
- bfa_assert(q_depth <= BFA_IOCFC_QDEPTH_MAX);
-
- fcpim->q_depth = q_depth;
-}
-
u16
bfa_fcpim_qdepth_get(struct bfa_s *bfa)
{
return fcpim->q_depth;
}
-void
-bfa_fcpim_update_ioredirect(struct bfa_s *bfa)
-{
- bfa_boolean_t ioredirect;
-
- /*
- * IO redirection is turned off when QoS is enabled and vice versa
- */
- ioredirect = bfa_fcport_is_qos_enabled(bfa) ? BFA_FALSE : BFA_TRUE;
-}
-
-void
-bfa_fcpim_set_ioredirect(struct bfa_s *bfa, bfa_boolean_t state)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- fcpim->ioredirect = state;
-}
-
-
-
/*
* BFA ITNIM module state machine functions
*/
/*
- * Beginning/unallocated state - no events expected.
+ * Beginning/unallocated state - no events expected.
*/
static void
bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
/*
- * Beginning state, only online event expected.
+ * Beginning state, only online event expected.
*/
static void
bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
/*
- * Waiting for itnim create response from firmware, a delete is pending.
+ * Waiting for itnim create response from firmware, a delete is pending.
*/
static void
bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
}
/*
- * Online state - normal parking state.
+ * Online state - normal parking state.
*/
static void
bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
/*
- * Second level error recovery need.
+ * Second level error recovery need.
*/
static void
bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
/*
- * Going offline. Waiting for active IO cleanup.
+ * Going offline. Waiting for active IO cleanup.
*/
static void
bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
}
/*
- * Deleting itnim. Waiting for active IO cleanup.
+ * Deleting itnim. Waiting for active IO cleanup.
*/
static void
bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
}
/*
- * Offline state.
+ * Offline state.
*/
static void
bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
}
-/*
- * IOC h/w failed state.
- */
static void
bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
enum bfa_itnim_event event)
}
/*
- * Itnim is deleted, waiting for firmware response to delete.
+ * Itnim is deleted, waiting for firmware response to delete.
*/
static void
bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
/*
- * Initiate cleanup of all IOs on an IOC failure.
+ * Initiate cleanup of all IOs on an IOC failure.
*/
static void
bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim)
}
/*
- * IO cleanup completion
+ * IO cleanup completion
*/
static void
bfa_itnim_cleanp_comp(void *itnim_cbarg)
}
/*
- * Initiate cleanup of all IOs.
+ * Initiate cleanup of all IOs.
*/
static void
bfa_itnim_cleanup(struct bfa_itnim_s *itnim)
bfa_sm_send_event(itnim, BFA_ITNIM_SM_QRESUME);
}
-
-
-
/*
* bfa_itnim_public
*/
fcpim->del_itn_stats.del_tm_iocdowns += itnim->stats.tm_iocdowns;
}
-
-
/*
- * bfa_itnim_public
+ * bfa_itnim_public
*/
/*
- * Itnim interrupt processing.
+ * Itnim interrupt processing.
*/
void
bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
}
}
-
-
/*
- * bfa_itnim_api
+ * bfa_itnim_api
*/
struct bfa_itnim_s *
bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable));
}
-bfa_status_t
-bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim,
- struct bfa_itnim_ioprofile_s *ioprofile)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(itnim->bfa);
- if (!fcpim->io_profile)
- return BFA_STATUS_IOPROFILE_OFF;
-
- itnim->ioprofile.index = BFA_IOBUCKET_MAX;
- itnim->ioprofile.io_profile_start_time =
- bfa_io_profile_start_time(itnim->bfa);
- itnim->ioprofile.clock_res_mul = bfa_io_lat_clock_res_mul;
- itnim->ioprofile.clock_res_div = bfa_io_lat_clock_res_div;
- *ioprofile = itnim->ioprofile;
-
- return BFA_STATUS_OK;
-}
-
-void
-bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
- struct bfa_itnim_iostats_s *stats)
-{
- *stats = itnim->stats;
-}
-
void
bfa_itnim_clear_stats(struct bfa_itnim_s *itnim)
{
*/
/*
- * IO is not started (unallocated).
+ * IO is not started (unallocated).
*/
static void
bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
if (ioim->nsges > BFI_SGE_INLINE) {
- if (!bfa_ioim_sge_setup(ioim)) {
+ if (!bfa_ioim_sgpg_alloc(ioim)) {
bfa_sm_set_state(ioim, bfa_ioim_sm_sgalloc);
return;
}
}
/*
- * IO is waiting for SG pages.
+ * IO is waiting for SG pages.
*/
static void
bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
/*
- * IO is active.
+ * IO is active.
*/
static void
bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
break;
case BFA_IOIM_SM_SQRETRY:
- if (bfa_ioim_get_iotag(ioim) != BFA_TRUE) {
- /* max retry completed free IO */
+ if (bfa_ioim_maxretry_reached(ioim)) {
+ /* max retry reached, free IO */
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
bfa_ioim_move_to_comp_q(ioim);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
}
/*
-* IO is retried with new tag.
-*/
+ * IO is retried with new tag.
+ */
static void
bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
{
switch (event) {
case BFA_IOIM_SM_FREE:
/* abts and rrq done. Now retry the IO with new tag */
+ bfa_ioim_update_iotag(ioim);
if (!bfa_ioim_send_ioreq(ioim)) {
bfa_sm_set_state(ioim, bfa_ioim_sm_qfull);
break;
}
/*
- * IO is being aborted, waiting for completion from firmware.
+ * IO is being aborted, waiting for completion from firmware.
*/
static void
bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
/*
- * IO is waiting for room in request CQ
+ * IO is waiting for room in request CQ
*/
static void
bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
/*
- * Active IO is being aborted, waiting for room in request CQ.
+ * Active IO is being aborted, waiting for room in request CQ.
*/
static void
bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
/*
- * Active IO is being cleaned up, waiting for room in request CQ.
+ * Active IO is being cleaned up, waiting for room in request CQ.
*/
static void
bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
-
-/*
- * hal_ioim_private
- */
-
static void
__bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete)
{
ioim->nsgpgs = BFA_SGPG_NPAGE(ioim->nsges);
list_splice_tail_init(&ioim->iosp->sgpg_wqe.sgpg_q, &ioim->sgpg_q);
- bfa_ioim_sgpg_setup(ioim);
+ ioim->sgpg = bfa_q_first(&ioim->sgpg_q);
bfa_sm_send_event(ioim, BFA_IOIM_SM_SGALLOCED);
}
{
struct bfa_itnim_s *itnim = ioim->itnim;
struct bfi_ioim_req_s *m;
- static struct fcp_cmnd_s cmnd_z0 = { 0 };
- struct bfi_sge_s *sge;
+ static struct fcp_cmnd_s cmnd_z0 = { { { 0 } } };
+ struct bfi_sge_s *sge, *sgpge;
u32 pgdlen = 0;
u32 fcp_dl;
u64 addr;
struct scatterlist *sg;
+ struct bfa_sgpg_s *sgpg;
struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
+ u32 i, sge_id, pgcumsz;
+ enum dma_data_direction dmadir;
/*
* check for room in queue to send request now
*/
m->io_tag = cpu_to_be16(ioim->iotag);
m->rport_hdl = ioim->itnim->rport->fw_handle;
- m->io_timeout = bfa_cb_ioim_get_timeout(ioim->dio);
+ m->io_timeout = 0;
- /*
- * build inline IO SG element here
- */
sge = &m->sges[0];
- if (ioim->nsges) {
- sg = (struct scatterlist *)scsi_sglist(cmnd);
- addr = bfa_os_sgaddr(sg_dma_address(sg));
- sge->sga = *(union bfi_addr_u *) &addr;
- pgdlen = sg_dma_len(sg);
- sge->sg_len = pgdlen;
- sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?
+ sgpg = ioim->sgpg;
+ sge_id = 0;
+ sgpge = NULL;
+ pgcumsz = 0;
+ scsi_for_each_sg(cmnd, sg, ioim->nsges, i) {
+ if (i == 0) {
+ /* build inline IO SG element */
+ addr = bfa_sgaddr_le(sg_dma_address(sg));
+ sge->sga = *(union bfi_addr_u *) &addr;
+ pgdlen = sg_dma_len(sg);
+ sge->sg_len = pgdlen;
+ sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?
BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST;
- bfa_sge_to_be(sge);
- sge++;
+ bfa_sge_to_be(sge);
+ sge++;
+ } else {
+ if (sge_id == 0)
+ sgpge = sgpg->sgpg->sges;
+
+ addr = bfa_sgaddr_le(sg_dma_address(sg));
+ sgpge->sga = *(union bfi_addr_u *) &addr;
+ sgpge->sg_len = sg_dma_len(sg);
+ pgcumsz += sgpge->sg_len;
+
+ /* set flags */
+ if (i < (ioim->nsges - 1) &&
+ sge_id < (BFI_SGPG_DATA_SGES - 1))
+ sgpge->flags = BFI_SGE_DATA;
+ else if (i < (ioim->nsges - 1))
+ sgpge->flags = BFI_SGE_DATA_CPL;
+ else
+ sgpge->flags = BFI_SGE_DATA_LAST;
+
+ bfa_sge_to_le(sgpge);
+
+ sgpge++;
+ if (i == (ioim->nsges - 1)) {
+ sgpge->flags = BFI_SGE_PGDLEN;
+ sgpge->sga.a32.addr_lo = 0;
+ sgpge->sga.a32.addr_hi = 0;
+ sgpge->sg_len = pgcumsz;
+ bfa_sge_to_le(sgpge);
+ } else if (++sge_id == BFI_SGPG_DATA_SGES) {
+ sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg);
+ sgpge->flags = BFI_SGE_LINK;
+ sgpge->sga = sgpg->sgpg_pa;
+ sgpge->sg_len = pgcumsz;
+ bfa_sge_to_le(sgpge);
+ sge_id = 0;
+ pgcumsz = 0;
+ }
+ }
}
if (ioim->nsges > BFI_SGE_INLINE) {
* set up I/O command parameters
*/
m->cmnd = cmnd_z0;
- m->cmnd.lun = bfa_cb_ioim_get_lun(ioim->dio);
- m->cmnd.iodir = bfa_cb_ioim_get_iodir(ioim->dio);
- m->cmnd.cdb = *(scsi_cdb_t *)bfa_cb_ioim_get_cdb(ioim->dio);
- fcp_dl = bfa_cb_ioim_get_size(ioim->dio);
+ int_to_scsilun(cmnd->device->lun, &m->cmnd.lun);
+ dmadir = cmnd->sc_data_direction;
+ if (dmadir == DMA_TO_DEVICE)
+ m->cmnd.iodir = FCP_IODIR_WRITE;
+ else if (dmadir == DMA_FROM_DEVICE)
+ m->cmnd.iodir = FCP_IODIR_READ;
+ else
+ m->cmnd.iodir = FCP_IODIR_NONE;
+
+ m->cmnd.cdb = *(scsi_cdb_t *) cmnd->cmnd;
+ fcp_dl = scsi_bufflen(cmnd);
m->cmnd.fcp_dl = cpu_to_be32(fcp_dl);
/*
bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa));
}
if (itnim->seq_rec ||
- (bfa_cb_ioim_get_size(ioim->dio) & (sizeof(u32) - 1)))
+ (scsi_bufflen(cmnd) & (sizeof(u32) - 1)))
bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa));
-#ifdef IOIM_ADVANCED
- m->cmnd.crn = bfa_cb_ioim_get_crn(ioim->dio);
- m->cmnd.priority = bfa_cb_ioim_get_priority(ioim->dio);
- m->cmnd.taskattr = bfa_cb_ioim_get_taskattr(ioim->dio);
-
- /*
- * Handle large CDB (>16 bytes).
- */
- m->cmnd.addl_cdb_len = (bfa_cb_ioim_get_cdblen(ioim->dio) -
- FCP_CMND_CDB_LEN) / sizeof(u32);
- if (m->cmnd.addl_cdb_len) {
- memcpy(&m->cmnd.cdb + 1, (scsi_cdb_t *)
- bfa_cb_ioim_get_cdb(ioim->dio) + 1,
- m->cmnd.addl_cdb_len * sizeof(u32));
- fcp_cmnd_fcpdl(&m->cmnd) =
- cpu_to_be32(bfa_cb_ioim_get_size(ioim->dio));
- }
-#endif
-
/*
* queue I/O message to firmware
*/
* at queuing time.
*/
static bfa_boolean_t
-bfa_ioim_sge_setup(struct bfa_ioim_s *ioim)
+bfa_ioim_sgpg_alloc(struct bfa_ioim_s *ioim)
{
u16 nsgpgs;
}
ioim->nsgpgs = nsgpgs;
- bfa_ioim_sgpg_setup(ioim);
+ ioim->sgpg = bfa_q_first(&ioim->sgpg_q);
return BFA_TRUE;
}
-static void
-bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
-{
- int sgeid, nsges, i;
- struct bfi_sge_s *sge;
- struct bfa_sgpg_s *sgpg;
- u32 pgcumsz;
- u64 addr;
- struct scatterlist *sg;
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
-
- sgeid = BFI_SGE_INLINE;
- ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q);
-
- sg = scsi_sglist(cmnd);
- sg = sg_next(sg);
-
- do {
- sge = sgpg->sgpg->sges;
- nsges = ioim->nsges - sgeid;
- if (nsges > BFI_SGPG_DATA_SGES)
- nsges = BFI_SGPG_DATA_SGES;
-
- pgcumsz = 0;
- for (i = 0; i < nsges; i++, sge++, sgeid++, sg = sg_next(sg)) {
- addr = bfa_os_sgaddr(sg_dma_address(sg));
- sge->sga = *(union bfi_addr_u *) &addr;
- sge->sg_len = sg_dma_len(sg);
- pgcumsz += sge->sg_len;
-
- /*
- * set flags
- */
- if (i < (nsges - 1))
- sge->flags = BFI_SGE_DATA;
- else if (sgeid < (ioim->nsges - 1))
- sge->flags = BFI_SGE_DATA_CPL;
- else
- sge->flags = BFI_SGE_DATA_LAST;
-
- bfa_sge_to_le(sge);
- }
-
- sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg);
-
- /*
- * set the link element of each page
- */
- if (sgeid == ioim->nsges) {
- sge->flags = BFI_SGE_PGDLEN;
- sge->sga.a32.addr_lo = 0;
- sge->sga.a32.addr_hi = 0;
- } else {
- sge->flags = BFI_SGE_LINK;
- sge->sga = sgpg->sgpg_pa;
- }
- sge->sg_len = pgcumsz;
-
- bfa_sge_to_le(sge);
- } while (sgeid < ioim->nsges);
-}
-
/*
* Send I/O abort request to firmware.
*/
}
bfa_itnim_iodone(ioim->itnim);
} else
- bfa_tskim_iodone(ioim->iosp->tskim);
+ bfa_wc_down(&ioim->iosp->tskim->wc);
}
static bfa_boolean_t
return BFA_TRUE;
}
-/*
- * or after the link comes back.
- */
void
bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov)
{
}
-
-/*
- * hal_ioim_friend
- */
-
/*
* Memory allocation and initialization.
*/
}
}
-/*
- * Driver detach time call.
- */
-void
-bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim)
-{
-}
-
void
bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
{
iotag = be16_to_cpu(rsp->io_tag);
ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
- bfa_assert(ioim->iotag == iotag);
+ bfa_assert(BFA_IOIM_TAG_2_ID(ioim->iotag) == iotag);
bfa_trc_fp(ioim->bfa, ioim->iotag);
bfa_ioim_cb_profile_comp(fcpim, ioim);
bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
}
-void
-bfa_ioim_profile_start(struct bfa_ioim_s *ioim)
-{
- ioim->start_time = jiffies;
-}
-
-void
-bfa_ioim_profile_comp(struct bfa_ioim_s *ioim)
-{
- u32 fcp_dl = bfa_cb_ioim_get_size(ioim->dio);
- u32 index = bfa_ioim_get_index(fcp_dl);
- u64 end_time = jiffies;
- struct bfa_itnim_latency_s *io_lat =
- &(ioim->itnim->ioprofile.io_latency);
- u32 val = (u32)(end_time - ioim->start_time);
-
- bfa_itnim_ioprofile_update(ioim->itnim, index);
-
- io_lat->count[index]++;
- io_lat->min[index] = (io_lat->min[index] < val) ?
- io_lat->min[index] : val;
- io_lat->max[index] = (io_lat->max[index] > val) ?
- io_lat->max[index] : val;
- io_lat->avg[index] += val;
-}
/*
* Called by itnim to clean up IO while going offline.
*/
}
-
-/*
- * hal_ioim_api
- */
-
/*
* Allocate IOIM resource for initiator mode I/O request.
*/
bfa_stats(ioim->itnim, io_comps);
fcpim->ios_active--;
+ ioim->iotag &= BFA_IOIM_IOTAG_MASK;
list_del(&ioim->qe);
list_add_tail(&ioim->qe, &fcpim->ioim_free_q);
}
* Obtain the queue over which this request has to be issued
*/
ioim->reqq = bfa_fcpim_ioredirect_enabled(ioim->bfa) ?
- bfa_cb_ioim_get_reqq(ioim->dio) :
- bfa_itnim_get_reqq(ioim);
+ BFA_FALSE : bfa_itnim_get_reqq(ioim);
bfa_sm_send_event(ioim, BFA_IOIM_SM_START);
}
return BFA_STATUS_OK;
}
-
/*
* BFA TSKIM state machine functions
*/
/*
- * Task management command beginning state.
+ * Task management command beginning state.
*/
static void
bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
}
/*
- * brief
- * TM command is active, awaiting completion from firmware to
- * cleanup IO requests in TM scope.
+ * TM command is active, awaiting completion from firmware to
+ * cleanup IO requests in TM scope.
*/
static void
bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
}
/*
- * An active TM is being cleaned up since ITN is offline. Awaiting cleanup
- * completion event from firmware.
+ * An active TM is being cleaned up since ITN is offline. Awaiting cleanup
+ * completion event from firmware.
*/
static void
bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
}
/*
- * Task management command is waiting for room in request CQ
+ * Task management command is waiting for room in request CQ
*/
static void
bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
}
/*
- * Task management command is active, awaiting for room in request CQ
- * to send clean up request.
+ * Task management command is active, awaiting for room in request CQ
+ * to send clean up request.
*/
static void
bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
case BFA_TSKIM_SM_DONE:
bfa_reqq_wcancel(&tskim->reqq_wait);
/*
- *
* Fall through !!!
*/
-
case BFA_TSKIM_SM_QRESUME:
bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup);
bfa_tskim_send_abort(tskim);
}
/*
- * BFA callback is pending
+ * BFA callback is pending
*/
static void
bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
}
}
-
-
-/*
- * hal_tskim_private
- */
-
static void
__bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete)
{
BFI_TSKIM_STS_FAILED);
}
-static bfa_boolean_t
-bfa_tskim_match_scope(struct bfa_tskim_s *tskim, lun_t lun)
+static bfa_boolean_t
+bfa_tskim_match_scope(struct bfa_tskim_s *tskim, struct scsi_lun lun)
{
switch (tskim->tm_cmnd) {
case FCP_TM_TARGET_RESET:
case FCP_TM_CLEAR_TASK_SET:
case FCP_TM_LUN_RESET:
case FCP_TM_CLEAR_ACA:
- return (tskim->lun == lun);
+ return !memcmp(&tskim->lun, &lun, sizeof(lun));
default:
bfa_assert(0);
}
/*
- * Gather affected IO requests and task management commands.
+ * Gather affected IO requests and task management commands.
*/
static void
bfa_tskim_gather_ios(struct bfa_tskim_s *tskim)
{
struct bfa_itnim_s *itnim = tskim->itnim;
struct bfa_ioim_s *ioim;
- struct list_head *qe, *qen;
+ struct list_head *qe, *qen;
+ struct scsi_cmnd *cmnd;
+ struct scsi_lun scsilun;
INIT_LIST_HEAD(&tskim->io_q);
*/
list_for_each_safe(qe, qen, &itnim->io_q) {
ioim = (struct bfa_ioim_s *) qe;
- if (bfa_tskim_match_scope
- (tskim, bfa_cb_ioim_get_lun(ioim->dio))) {
+ cmnd = (struct scsi_cmnd *) ioim->dio;
+ int_to_scsilun(cmnd->device->lun, &scsilun);
+ if (bfa_tskim_match_scope(tskim, scsilun)) {
list_del(&ioim->qe);
list_add_tail(&ioim->qe, &tskim->io_q);
}
*/
list_for_each_safe(qe, qen, &itnim->pending_q) {
ioim = (struct bfa_ioim_s *) qe;
- if (bfa_tskim_match_scope
- (tskim, bfa_cb_ioim_get_lun(ioim->dio))) {
+ cmnd = (struct scsi_cmnd *) ioim->dio;
+ int_to_scsilun(cmnd->device->lun, &scsilun);
+ if (bfa_tskim_match_scope(tskim, scsilun)) {
list_del(&ioim->qe);
list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_ioim_tov(ioim);
}
/*
- * IO cleanup completion
+ * IO cleanup completion
*/
static void
bfa_tskim_cleanp_comp(void *tskim_cbarg)
}
/*
- * Gather affected IO requests and task management commands.
+ * Gather affected IO requests and task management commands.
*/
static void
bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim)
}
/*
- * Send task management request to firmware.
+ * Send task management request to firmware.
*/
static bfa_boolean_t
bfa_tskim_send(struct bfa_tskim_s *tskim)
}
/*
- * Send abort request to cleanup an active TM to firmware.
+ * Send abort request to cleanup an active TM to firmware.
*/
static bfa_boolean_t
bfa_tskim_send_abort(struct bfa_tskim_s *tskim)
}
/*
- * Call to resume task management cmnd waiting for room in request queue.
+ * Call to resume task management cmnd waiting for room in request queue.
*/
static void
bfa_tskim_qresume(void *cbarg)
}
}
-
-
-/*
- * hal_tskim_friend
- */
-
/*
* Notification on completions from related ioim.
*/
}
/*
- * Memory allocation and initialization.
+ * Memory allocation and initialization.
*/
void
bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
bfa_meminfo_kva(minfo) = (u8 *) tskim;
}
-void
-bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim)
-{
- /*
- * @todo
- */
-}
-
void
bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
{
}
-
-/*
- * hal_tskim_api
- */
-
-
struct bfa_tskim_s *
bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk)
{
}
/*
- * Start a task management command.
+ * Start a task management command.
*
* @param[in] tskim BFA task management command instance
* @param[in] itnim i-t nexus for the task management command
* @return None.
*/
void
-bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, lun_t lun,
+bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim,
+ struct scsi_lun lun,
enum fcp_tm_cmnd tm_cmnd, u8 tsecs)
{
tskim->itnim = itnim;
(__itnim->ioprofile.iocomps[__index]++)
#define BFA_IOIM_RETRY_TAG_OFFSET 11
-#define BFA_IOIM_RETRY_TAG_MASK 0x07ff /* 2K IOs */
+#define BFA_IOIM_IOTAG_MASK 0x07ff /* 2K IOs */
#define BFA_IOIM_RETRY_MAX 7
/* Buckets are are 512 bytes to 2MB */
struct list_head ioim_resfree_q; /* IOs waiting for f/w */
struct list_head ioim_comp_q; /* IO global comp Q */
struct list_head tskim_free_q;
- u32 ios_active; /* current active IOs */
- u32 delay_comp;
+ u32 ios_active; /* current active IOs */
+ u32 delay_comp;
struct bfa_fcpim_del_itn_stats_s del_itn_stats;
bfa_boolean_t ioredirect;
bfa_boolean_t io_profile;
- u32 io_profile_start_time;
+ u32 io_profile_start_time;
bfa_fcpim_profile_t profile_comp;
bfa_fcpim_profile_t profile_start;
};
struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */
struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */
struct bfad_ioim_s *dio; /* driver IO handle */
- u16 iotag; /* FWI IO tag */
- u16 abort_tag; /* unqiue abort request tag */
- u16 nsges; /* number of SG elements */
- u16 nsgpgs; /* number of SG pages */
+ u16 iotag; /* FWI IO tag */
+ u16 abort_tag; /* unqiue abort request tag */
+ u16 nsges; /* number of SG elements */
+ u16 nsgpgs; /* number of SG pages */
struct bfa_sgpg_s *sgpg; /* first SG page */
struct list_head sgpg_q; /* allocated SG pages */
struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
bfa_cb_cbfn_t io_cbfn; /* IO completion handler */
- struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */
- u8 reqq; /* Request queue for I/O */
- u64 start_time; /* IO's Profile start val */
+ struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */
+ u8 reqq; /* Request queue for I/O */
+ u64 start_time; /* IO's Profile start val */
};
-
struct bfa_ioim_sp_s {
struct bfi_msg_s comp_rspmsg; /* IO comp f/w response */
u8 *snsinfo; /* sense info for this IO */
- struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */
- struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
+ struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */
+ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
bfa_boolean_t abort_explicit; /* aborted by OS */
struct bfa_tskim_s *tskim; /* Relevant TM cmd */
};
struct bfa_tskim_s {
struct list_head qe;
bfa_sm_t sm;
- struct bfa_s *bfa; /* BFA module */
+ struct bfa_s *bfa; /* BFA module */
struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */
struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */
- struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */
- bfa_boolean_t notify; /* notify itnim on TM comp */
- lun_t lun; /* lun if applicable */
- enum fcp_tm_cmnd tm_cmnd; /* task management command */
- u16 tsk_tag; /* FWI IO tag */
- u8 tsecs; /* timeout in seconds */
+ struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */
+ bfa_boolean_t notify; /* notify itnim on TM comp */
+ struct scsi_lun lun; /* lun if applicable */
+ enum fcp_tm_cmnd tm_cmnd; /* task management command */
+ u16 tsk_tag; /* FWI IO tag */
+ u8 tsecs; /* timeout in seconds */
struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
struct list_head io_q; /* queue of affected IOs */
- struct bfa_wc_s wc; /* waiting counter */
+ struct bfa_wc_s wc; /* waiting counter */
struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
enum bfi_tskim_status tsk_status; /* TM status */
};
-
/*
* BFA i-t-n (initiator mode)
*/
struct bfa_itnim_s {
- struct list_head qe; /* queue element */
- bfa_sm_t sm; /* i-t-n im BFA state machine */
- struct bfa_s *bfa; /* bfa instance */
- struct bfa_rport_s *rport; /* bfa rport */
- void *ditn; /* driver i-t-n structure */
+ struct list_head qe; /* queue element */
+ bfa_sm_t sm; /* i-t-n im BFA state machine */
+ struct bfa_s *bfa; /* bfa instance */
+ struct bfa_rport_s *rport; /* bfa rport */
+ void *ditn; /* driver i-t-n structure */
struct bfi_mhdr_s mhdr; /* pre-built mhdr */
- u8 msg_no; /* itnim/rport firmware handle */
- u8 reqq; /* CQ for requests */
+ u8 msg_no; /* itnim/rport firmware handle */
+ u8 reqq; /* CQ for requests */
struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
struct list_head pending_q; /* queue of pending IO requests */
struct list_head io_q; /* queue of active IO requests */
bfa_boolean_t seq_rec; /* SQER supported */
bfa_boolean_t is_online; /* itnim is ONLINE for IO */
bfa_boolean_t iotov_active; /* IO TOV timer is active */
- struct bfa_wc_s wc; /* waiting counter */
- struct bfa_timer_s timer; /* pending IO TOV */
+ struct bfa_wc_s wc; /* waiting counter */
+ struct bfa_timer_s timer; /* pending IO TOV */
struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
struct bfa_fcpim_mod_s *fcpim; /* fcpim module */
struct bfa_itnim_iostats_s stats;
struct bfa_itnim_ioprofile_s ioprofile;
};
-
#define bfa_itnim_is_online(_itnim) ((_itnim)->is_online)
#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod)
+#define BFA_IOIM_TAG_2_ID(_iotag) ((_iotag) & BFA_IOIM_IOTAG_MASK)
#define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \
- (&fcpim->ioim_arr[(_iotag & BFA_IOIM_RETRY_TAG_MASK)])
+ (&fcpim->ioim_arr[(_iotag & BFA_IOIM_IOTAG_MASK)])
#define BFA_TSKIM_FROM_TAG(_fcpim, _tmtag) \
(&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)])
(_bfa->modules.fcpim_mod.io_profile_start_time)
#define bfa_fcpim_get_io_profile(_bfa) \
(_bfa->modules.fcpim_mod.io_profile)
+#define bfa_ioim_update_iotag(__ioim) do { \
+ uint16_t k = (__ioim)->iotag >> BFA_IOIM_RETRY_TAG_OFFSET; \
+ k++; (__ioim)->iotag &= BFA_IOIM_IOTAG_MASK; \
+ (__ioim)->iotag |= k << BFA_IOIM_RETRY_TAG_OFFSET; \
+} while (0)
static inline bfa_boolean_t
-bfa_ioim_get_iotag(struct bfa_ioim_s *ioim)
+bfa_ioim_maxretry_reached(struct bfa_ioim_s *ioim)
{
- u16 k = ioim->iotag;
-
- k >>= BFA_IOIM_RETRY_TAG_OFFSET; k++;
-
- if (k > BFA_IOIM_RETRY_MAX)
+ uint16_t k = ioim->iotag >> BFA_IOIM_RETRY_TAG_OFFSET;
+ if (k < BFA_IOIM_RETRY_MAX)
return BFA_FALSE;
- ioim->iotag &= BFA_IOIM_RETRY_TAG_MASK;
- ioim->iotag |= k<<BFA_IOIM_RETRY_TAG_OFFSET;
return BFA_TRUE;
}
+
/*
* function prototypes
*/
void bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim,
struct bfa_meminfo_s *minfo);
-void bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim);
void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
void bfa_ioim_good_comp_isr(struct bfa_s *bfa,
struct bfi_msg_s *msg);
void bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim,
struct bfa_meminfo_s *minfo);
-void bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim);
void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
void bfa_tskim_iodone(struct bfa_tskim_s *tskim);
void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim);
void bfa_itnim_iodone(struct bfa_itnim_s *itnim);
void bfa_itnim_tskdone(struct bfa_itnim_s *itnim);
bfa_boolean_t bfa_itnim_hold_io(struct bfa_itnim_s *itnim);
-void bfa_ioim_profile_comp(struct bfa_ioim_s *ioim);
-void bfa_ioim_profile_start(struct bfa_ioim_s *ioim);
-
/*
* bfa fcpim module API functions
*/
-void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov);
+void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov);
u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa);
-void bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth);
u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa);
-bfa_status_t bfa_fcpim_get_modstats(struct bfa_s *bfa,
- struct bfa_itnim_iostats_s *modstats);
-bfa_status_t bfa_fcpim_port_iostats(struct bfa_s *bfa,
- struct bfa_itnim_iostats_s *stats, u8 lp_tag);
-bfa_status_t bfa_fcpim_get_del_itn_stats(struct bfa_s *bfa,
- struct bfa_fcpim_del_itn_stats_s *modstats);
-bfa_status_t bfa_fcpim_port_clear_iostats(struct bfa_s *bfa, u8 lp_tag);
-void bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *fcpim_stats,
- struct bfa_itnim_iostats_s *itnim_stats);
-bfa_status_t bfa_fcpim_clr_modstats(struct bfa_s *bfa);
-void bfa_fcpim_set_ioredirect(struct bfa_s *bfa,
- bfa_boolean_t state);
-void bfa_fcpim_update_ioredirect(struct bfa_s *bfa);
-bfa_status_t bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time);
-bfa_status_t bfa_fcpim_profile_off(struct bfa_s *bfa);
+
#define bfa_fcpim_ioredirect_enabled(__bfa) \
(((struct bfa_fcpim_mod_s *)(BFA_FCPIM_MOD(__bfa)))->ioredirect)
* bfa itnim API functions
*/
struct bfa_itnim_s *bfa_itnim_create(struct bfa_s *bfa,
- struct bfa_rport_s *rport, void *itnim);
-void bfa_itnim_delete(struct bfa_itnim_s *itnim);
-void bfa_itnim_online(struct bfa_itnim_s *itnim,
- bfa_boolean_t seq_rec);
-void bfa_itnim_offline(struct bfa_itnim_s *itnim);
-void bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
- struct bfa_itnim_iostats_s *stats);
-void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim);
-bfa_status_t bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim,
- struct bfa_itnim_ioprofile_s *ioprofile);
+ struct bfa_rport_s *rport, void *itnim);
+void bfa_itnim_delete(struct bfa_itnim_s *itnim);
+void bfa_itnim_online(struct bfa_itnim_s *itnim, bfa_boolean_t seq_rec);
+void bfa_itnim_offline(struct bfa_itnim_s *itnim);
+void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim);
+bfa_status_t bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim,
+ struct bfa_itnim_ioprofile_s *ioprofile);
+
#define bfa_itnim_get_reqq(__ioim) (((struct bfa_ioim_s *)__ioim)->itnim->reqq)
/*
- * BFA completion callback for bfa_itnim_online().
- *
- * @param[in] itnim FCS or driver itnim instance
- *
- * return None
+ * BFA completion callback for bfa_itnim_online().
*/
void bfa_cb_itnim_online(void *itnim);
/*
- * BFA completion callback for bfa_itnim_offline().
- *
- * @param[in] itnim FCS or driver itnim instance
- *
- * return None
+ * BFA completion callback for bfa_itnim_offline().
*/
void bfa_cb_itnim_offline(void *itnim);
void bfa_cb_itnim_tov_begin(void *itnim);
void bfa_cb_itnim_tov(void *itnim);
/*
- * BFA notification to FCS/driver for second level error recovery.
- *
+ * BFA notification to FCS/driver for second level error recovery.
* Atleast one I/O request has timedout and target is unresponsive to
* repeated abort requests. Second level error recovery should be initiated
* by starting implicit logout and recovery procedures.
- *
- * @param[in] itnim FCS or driver itnim instance
- *
- * return None
*/
void bfa_cb_itnim_sler(void *itnim);
bfa_status_t bfa_ioim_abort(struct bfa_ioim_s *ioim);
void bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim,
bfa_boolean_t iotov);
-
-
/*
- * I/O completion notification.
+ * I/O completion notification.
*
* @param[in] dio driver IO structure
* @param[in] io_status IO completion status
*
* @return None
*/
-void bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio,
- enum bfi_ioim_status io_status,
- u8 scsi_status, int sns_len,
- u8 *sns_info, s32 residue);
+void bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio,
+ enum bfi_ioim_status io_status,
+ u8 scsi_status, int sns_len,
+ u8 *sns_info, s32 residue);
/*
- * I/O good completion notification.
- *
- * @param[in] dio driver IO structure
- *
- * @return None
+ * I/O good completion notification.
*/
-void bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio);
+void bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio);
/*
- * I/O abort completion notification
- *
- * @param[in] dio driver IO that was aborted
- *
- * @return None
+ * I/O abort completion notification
*/
-void bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio);
+void bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio);
/*
* bfa tskim API functions
*/
-struct bfa_tskim_s *bfa_tskim_alloc(struct bfa_s *bfa,
- struct bfad_tskim_s *dtsk);
-void bfa_tskim_free(struct bfa_tskim_s *tskim);
-void bfa_tskim_start(struct bfa_tskim_s *tskim,
- struct bfa_itnim_s *itnim, lun_t lun,
- enum fcp_tm_cmnd tm, u8 t_secs);
-void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
- enum bfi_tskim_status tsk_status);
+struct bfa_tskim_s *bfa_tskim_alloc(struct bfa_s *bfa,
+ struct bfad_tskim_s *dtsk);
+void bfa_tskim_free(struct bfa_tskim_s *tskim);
+void bfa_tskim_start(struct bfa_tskim_s *tskim,
+ struct bfa_itnim_s *itnim, struct scsi_lun lun,
+ enum fcp_tm_cmnd tm, u8 t_secs);
+void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
+ enum bfi_tskim_status tsk_status);
#endif /* __BFA_FCPIM_H__ */
* bfa_fcs.c BFA FCS main
*/
+#include "bfad_drv.h"
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(FCS, FCS);
fcs->bfad = bfad;
fcs->min_cfg = min_cfg;
- bfa_attach_fcs(bfa);
+ bfa->fcs = BFA_TRUE;
fcbuild_init();
for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
}
}
-/*
- * Start FCS operations.
- */
-void
-bfa_fcs_start(struct bfa_fcs_s *fcs)
-{
- bfa_fcs_fabric_modstart(fcs);
-}
/*
* brief
bfa_fcs_fabric_psymb_init(&fcs->fabric);
}
-/*
- * brief
- * FCS FDMI Driver Parameter Initialization
- *
- * param[in] fcs FCS instance
- * param[in] fdmi_enable TRUE/FALSE
- *
- * return None
- */
-void
-bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable)
-{
-
- fcs->fdmi_enabled = fdmi_enable;
-
-}
/*
* brief
* FCS instance cleanup and exit.
}
-void
-bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod)
-{
- fcs->trcmod = trcmod;
-}
-
-void
-bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs)
-{
- bfa_wc_down(&fcs->wc);
-}
-
/*
* Fabric module implementation.
*/
u32 rsp_len,
u32 resid_len,
struct fchs_s *rspfchs);
-/*
- * fcs_fabric_sm fabric state machine functions
- */
-
-/*
- * Fabric state machine events
- */
-enum bfa_fcs_fabric_event {
- BFA_FCS_FABRIC_SM_CREATE = 1, /* create from driver */
- BFA_FCS_FABRIC_SM_DELETE = 2, /* delete from driver */
- BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */
- BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */
- BFA_FCS_FABRIC_SM_CONT_OP = 5, /* flogi/auth continue op */
- BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* flogi/auth retry op */
- BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* from flogi/auth */
- BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* from flogi/auth */
- BFA_FCS_FABRIC_SM_ISOLATE = 9, /* from EVFP processing */
- BFA_FCS_FABRIC_SM_NO_TAGGING = 10, /* no VFT tagging from EVFP */
- BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */
- BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* auth failed */
- BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* auth successful */
- BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */
- BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */
- BFA_FCS_FABRIC_SM_START = 16, /* from driver */
-};
static void bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
enum bfa_fcs_fabric_event event);
static void bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
-static void bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
- enum bfa_fcs_fabric_event event);
-static void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
- enum bfa_fcs_fabric_event event);
static void bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
-static void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
- enum bfa_fcs_fabric_event event);
static void bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
static void bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
case BFA_FCS_FABRIC_SM_DELETE:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
- bfa_fcs_modexit_comp(fabric->fcs);
+ bfa_wc_down(&fabric->fcs->wc);
break;
default:
case BFA_FCS_FABRIC_SM_LOOPBACK:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_loopback);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_fabric_set_opertype(fabric);
break;
case BFA_FCS_FABRIC_SM_LINK_DOWN:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
break;
case BFA_FCS_FABRIC_SM_DELETE:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_fabric_delete(fabric);
break;
switch (event) {
case BFA_FCS_FABRIC_SM_AUTH_FAILED:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
break;
case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
case BFA_FCS_FABRIC_SM_LINK_DOWN:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
break;
case BFA_FCS_FABRIC_SM_DELETE:
/*
* Authentication failed
*/
-static void
+void
bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event)
{
/*
* Port is in loopback mode.
*/
-static void
+void
bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event)
{
switch (event) {
case BFA_FCS_FABRIC_SM_LINK_DOWN:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_fabric_notify_offline(fabric);
break;
/*
* Fabric is online - normal operating state.
*/
-static void
+void
bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event)
{
switch (event) {
case BFA_FCS_FABRIC_SM_LINK_DOWN:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_fabric_notify_offline(fabric);
break;
case BFA_FCS_FABRIC_SM_AUTH_FAILED:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
break;
case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
bfa_trc(fabric->fcs, event);
wwn2str(pwwn_ptr, fabric->bport.port_cfg.pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Port is isolated due to VF_ID mismatch. "
"PWWN: %s Port VF_ID: %04x switch port VF_ID: %04x.",
pwwn_ptr, fabric->fcs->port_vfid,
switch (event) {
case BFA_FCS_FABRIC_SM_DELCOMP:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
- bfa_fcs_modexit_comp(fabric->fcs);
+ bfa_wc_down(&fabric->fcs->wc);
break;
case BFA_FCS_FABRIC_SM_LINK_UP:
struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg;
port_cfg->roles = BFA_LPORT_ROLE_FCP_IM;
- port_cfg->nwwn = bfa_ioc_get_nwwn(&fabric->fcs->bfa->ioc);
- port_cfg->pwwn = bfa_ioc_get_pwwn(&fabric->fcs->bfa->ioc);
+ port_cfg->nwwn = fabric->fcs->bfa->ioc.attr->nwwn;
+ port_cfg->pwwn = fabric->fcs->bfa->ioc.attr->pwwn;
}
/*
return;
case BFA_STATUS_EPROTOCOL:
- switch (bfa_lps_get_extstatus(fabric->lps)) {
+ switch (fabric->lps->ext_status) {
case BFA_EPROTO_BAD_ACCEPT:
fabric->stats.flogi_acc_err++;
break;
return;
}
- fabric->bb_credit = bfa_lps_get_peer_bbcredit(fabric->lps);
+ fabric->bb_credit = fabric->lps->pr_bbcred;
bfa_trc(fabric->fcs, fabric->bb_credit);
- if (!bfa_lps_is_brcd_fabric(fabric->lps))
- fabric->fabric_name = bfa_lps_get_peer_nwwn(fabric->lps);
+ if (!(fabric->lps->brcd_switch))
+ fabric->fabric_name = fabric->lps->pr_nwwn;
/*
* Check port type. It should be 1 = F-port.
*/
- if (bfa_lps_is_fport(fabric->lps)) {
- fabric->bport.pid = bfa_lps_get_pid(fabric->lps);
- fabric->is_npiv = bfa_lps_is_npiv_en(fabric->lps);
- fabric->is_auth = bfa_lps_is_authreq(fabric->lps);
+ if (fabric->lps->fport) {
+ fabric->bport.pid = fabric->lps->lp_pid;
+ fabric->is_npiv = fabric->lps->npiv_en;
+ fabric->is_auth = fabric->lps->auth_req;
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CONT_OP);
} else {
/*
* Nport-2-Nport direct attached
*/
fabric->bport.port_topo.pn2n.rem_port_wwn =
- bfa_lps_get_peer_pwwn(fabric->lps);
+ fabric->lps->pr_pwwn;
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC);
}
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START);
}
-/*
- * Suspend fabric activity as part of driver suspend.
- */
-void
-bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs)
-{
-}
-
-bfa_boolean_t
-bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric)
-{
- return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback);
-}
-
-bfa_boolean_t
-bfa_fcs_fabric_is_auth_failed(struct bfa_fcs_fabric_s *fabric)
-{
- return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_auth_failed);
-}
-
-enum bfa_port_type
-bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric)
-{
- return fabric->oper_type;
-}
/*
* Link up notification from BFA physical port module.
bfa_wc_down(&fabric->wc);
}
-/*
- * Base port is deleted.
- */
-void
-bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric)
-{
- bfa_wc_down(&fabric->wc);
-}
-
-
-/*
- * Check if fabric is online.
- *
- * param[in] fabric - Fabric instance. This can be a base fabric or vf.
- *
- * @return TRUE/FALSE
- */
-int
-bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric)
-{
- return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online);
-}
-
-/*
- * brief
- *
- */
-bfa_status_t
-bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, struct bfa_fcs_s *fcs,
- struct bfa_lport_cfg_s *port_cfg, struct bfad_vf_s *vf_drv)
-{
- bfa_sm_set_state(vf, bfa_fcs_fabric_sm_uninit);
- return BFA_STATUS_OK;
-}
/*
* Lookup for a vport withing a fabric given its pwwn
return NULL;
}
-/*
- * In a given fabric, return the number of lports.
- *
- * param[in] fabric - Fabric instance. This can be a base fabric or vf.
- *
- * @return : 1 or more.
- */
-u16
-bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric)
-{
- return fabric->num_vports;
-}
/*
* Get OUI of the attached switch.
u8 *tmp;
u16 oui;
- fab_nwwn = bfa_lps_get_peer_nwwn(fabric->lps);
+ fab_nwwn = fabric->lps->pr_nwwn;
tmp = (u8 *)&fab_nwwn;
oui = (tmp[3] << 8) | tmp[4];
* external loopback cable is in place. Our own FLOGI frames are
* sometimes looped back when switch port gets temporarily bypassed.
*/
- if ((pid == bfa_os_ntoh3b(FC_FABRIC_PORT)) &&
+ if ((pid == bfa_ntoh3b(FC_FABRIC_PORT)) &&
(els_cmd->els_code == FC_ELS_FLOGI) &&
(flogi->port_name == bfa_fcs_lport_get_pwwn(&fabric->bport))) {
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOOPBACK);
/*
* FLOGI/EVFP exchanges should be consumed by base fabric.
*/
- if (fchs->d_id == bfa_os_hton3b(FC_FABRIC_PORT)) {
+ if (fchs->d_id == bfa_hton3b(FC_FABRIC_PORT)) {
bfa_trc(fabric->fcs, pid);
bfa_fcs_fabric_process_uf(fabric, fchs, len);
return;
return;
reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
- bfa_os_hton3b(FC_FABRIC_PORT),
+ bfa_hton3b(FC_FABRIC_PORT),
n2n_port->reply_oxid, pcfg->pwwn,
pcfg->nwwn,
bfa_fcport_get_maxfrsize(bfa),
bfa_fcport_get_rx_bbcredit(bfa));
- bfa_fcxp_send(fcxp, NULL, fabric->vf_id, bfa_lps_get_tag(fabric->lps),
+ bfa_fcxp_send(fcxp, NULL, fabric->vf_id, fabric->lps->lp_tag,
BFA_FALSE, FC_CLASS_3,
reqlen, &fchs, bfa_fcs_fabric_flogiacc_comp, fabric,
FC_MAX_PDUSZ, 0);
wwn2str(pwwn_ptr, bfa_fcs_lport_get_pwwn(&fabric->bport));
wwn2str(fwwn_ptr,
bfa_fcs_lport_get_fabric_name(&fabric->bport));
- BFA_LOG(KERN_WARNING, bfad, log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Base port WWN = %s Fabric WWN = %s\n",
pwwn_ptr, fwwn_ptr);
}
#define BFA_FCS_OS_STR_LEN 64
+/*
+ * lps_pvt BFA LPS private functions
+ */
+
+enum bfa_lps_event {
+ BFA_LPS_SM_LOGIN = 1, /* login request from user */
+ BFA_LPS_SM_LOGOUT = 2, /* logout request from user */
+ BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */
+ BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */
+ BFA_LPS_SM_DELETE = 5, /* lps delete from user */
+ BFA_LPS_SM_OFFLINE = 6, /* Link is offline */
+ BFA_LPS_SM_RX_CVL = 7, /* Rx clear virtual link */
+ BFA_LPS_SM_SET_N2N_PID = 8, /* Set assigned PID for n2n */
+};
+
+
/*
* !!! Only append to the enums defined here to avoid any versioning
* !!! needed between trace utility and driver version
struct bfa_fcs_s;
#define __fcs_min_cfg(__fcs) ((__fcs)->min_cfg)
-void bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs);
#define BFA_FCS_BRCD_SWITCH_OUI 0x051e
#define N2N_LOCAL_PID 0x010000
#define N2N_REMOTE_PID 0x020000
#define BFA_FCS_RETRY_TIMEOUT 2000
-#define BFA_FCS_PID_IS_WKA(pid) ((bfa_os_ntoh3b(pid) > 0xFFF000) ? 1 : 0)
+#define BFA_FCS_PID_IS_WKA(pid) ((bfa_ntoh3b(pid) > 0xFFF000) ? 1 : 0)
struct bfa_fcs_lport_n2n_s {
u32 rsvd;
- u16 reply_oxid; /* ox_id from the req flogi to be
+ __be16 reply_oxid; /* ox_id from the req flogi to be
*used in flogi acc */
wwn_t rem_port_wwn; /* Attached port's wwn */
};
struct bfa_fcs_rport_s *rport);
void bfa_fcs_lport_del_rport(struct bfa_fcs_lport_s *port,
struct bfa_fcs_rport_s *rport);
-void bfa_fcs_lport_modinit(struct bfa_fcs_s *fcs);
-void bfa_fcs_lport_modexit(struct bfa_fcs_s *fcs);
void bfa_fcs_lport_ns_init(struct bfa_fcs_lport_s *vport);
void bfa_fcs_lport_ns_offline(struct bfa_fcs_lport_s *vport);
void bfa_fcs_lport_ns_online(struct bfa_fcs_lport_s *vport);
bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport);
void bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport,
struct bfa_vport_attr_s *vport_attr);
-void bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport,
- struct bfa_vport_stats_s *vport_stats);
-void bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport);
struct bfa_fcs_vport_s *bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs,
u16 vf_id, wwn_t vpwwn);
void bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport);
struct bfad_rport_s *rp_drv; /* driver peer instance */
u32 pid; /* port ID of rport */
u16 maxfrsize; /* maximum frame size */
- u16 reply_oxid; /* OX_ID of inbound requests */
+ __be16 reply_oxid; /* OX_ID of inbound requests */
enum fc_cos fc_cos; /* FC classes of service supp */
bfa_boolean_t cisc; /* CISC capable device */
bfa_boolean_t prlo; /* processing prlo or LOGO */
/*
* bfa fcs rport API functions
*/
-bfa_status_t bfa_fcs_rport_add(struct bfa_fcs_lport_s *port, wwn_t *pwwn,
- struct bfa_fcs_rport_s *rport,
- struct bfad_rport_s *rport_drv);
-bfa_status_t bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport);
-void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
- struct bfa_rport_attr_s *attr);
-void bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport,
- struct bfa_rport_stats_s *stats);
-void bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport);
struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port,
wwn_t rpwwn);
struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn(
struct bfa_fcs_lport_s *port, wwn_t rnwwn);
void bfa_fcs_rport_set_del_timeout(u8 rport_tmo);
-void bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport,
- enum bfa_port_speed speed);
void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport,
struct fchs_s *fchs, u16 len);
void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport);
struct bfa_fcs_rport_s *bfa_fcs_rport_create(struct bfa_fcs_lport_s *port,
u32 pid);
-void bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport);
-void bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport);
-void bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport);
void bfa_fcs_rport_start(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs,
struct fc_logi_s *plogi_rsp);
void bfa_fcs_rport_plogi_create(struct bfa_fcs_lport_s *port,
struct fc_logi_s *plogi);
void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
struct fc_logi_s *plogi);
-void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport);
-void bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, u16 ox_id);
+void bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, __be16 ox_id);
-void bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport);
void bfa_fcs_rport_itntm_ack(struct bfa_fcs_rport_s *rport);
void bfa_fcs_rport_fcptm_offline_done(struct bfa_fcs_rport_s *rport);
int bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport);
u8 option_rom_ver[BFA_VERSION_LEN];
u8 fw_version[8];
u8 os_name[256];
- u32 max_ct_pyld;
+ __be32 max_ct_pyld;
};
/*
*/
struct bfa_fcs_fdmi_port_attr_s {
u8 supp_fc4_types[32]; /* supported FC4 types */
- u32 supp_speed; /* supported speed */
- u32 curr_speed; /* current Speed */
- u32 max_frm_size; /* max frame size */
+ __be32 supp_speed; /* supported speed */
+ __be32 curr_speed; /* current Speed */
+ __be32 max_frm_size; /* max frame size */
u8 os_device_name[256]; /* OS device Name */
u8 host_name[256]; /* host name */
};
struct bfa_wc_s wc; /* waiting counter */
};
+/*
+ * fcs_fabric_sm fabric state machine functions
+ */
+
+/*
+ * Fabric state machine events
+ */
+enum bfa_fcs_fabric_event {
+ BFA_FCS_FABRIC_SM_CREATE = 1, /* create from driver */
+ BFA_FCS_FABRIC_SM_DELETE = 2, /* delete from driver */
+ BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */
+ BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */
+ BFA_FCS_FABRIC_SM_CONT_OP = 5, /* flogi/auth continue op */
+ BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* flogi/auth retry op */
+ BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* from flogi/auth */
+ BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* from flogi/auth */
+ BFA_FCS_FABRIC_SM_ISOLATE = 9, /* from EVFP processing */
+ BFA_FCS_FABRIC_SM_NO_TAGGING = 10, /* no VFT tagging from EVFP */
+ BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */
+ BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* auth failed */
+ BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* auth successful */
+ BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */
+ BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */
+ BFA_FCS_FABRIC_SM_START = 16, /* from driver */
+};
+
+/*
+ * fcs_rport_sm FCS rport state machine events
+ */
+
+enum rport_event {
+ RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */
+ RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */
+ RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */
+ RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */
+ RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */
+ RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */
+ RPSM_EVENT_DELETE = 7, /* RPORT delete request */
+ RPSM_EVENT_SCN = 8, /* state change notification */
+ RPSM_EVENT_ACCEPTED = 9, /* Good response from remote device */
+ RPSM_EVENT_FAILED = 10, /* Request to rport failed. */
+ RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */
+ RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */
+ RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */
+ RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */
+ RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */
+ RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */
+ RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */
+ RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continously */
+};
+
/*
* bfa fcs API functions
*/
void bfa_fcs_init(struct bfa_fcs_s *fcs);
void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
struct bfa_fcs_driver_info_s *driver_info);
-void bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable);
void bfa_fcs_exit(struct bfa_fcs_s *fcs);
-void bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod);
-void bfa_fcs_start(struct bfa_fcs_s *fcs);
/*
* bfa fcs vf public functions
*/
bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id);
-u16 bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric);
/*
* fabric protected interface functions
void bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs);
void bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs);
void bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs);
-void bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs);
void bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric);
void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric);
void bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
struct bfa_fcs_vport_s *vport);
void bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric,
struct bfa_fcs_vport_s *vport);
-int bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric);
struct bfa_fcs_vport_s *bfa_fcs_fabric_vport_lookup(
struct bfa_fcs_fabric_s *fabric, wwn_t pwwn);
void bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs);
void bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric,
struct fchs_s *fchs, u16 len);
-bfa_boolean_t bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric);
-bfa_boolean_t bfa_fcs_fabric_is_auth_failed(struct bfa_fcs_fabric_s *fabric);
-enum bfa_port_type bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric);
void bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric);
-void bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric);
-bfa_status_t bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf,
- struct bfa_fcs_s *fcs, struct bfa_lport_cfg_s *port_cfg,
- struct bfad_vf_s *vf_drv);
void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
wwn_t fabric_name);
u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric);
void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs);
void bfa_fcs_port_attach(struct bfa_fcs_s *fcs);
+void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+void bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
/*
* BFA FCS callback interfaces
* fcpim.c - FCP initiator mode i-t nexus state machine
*/
+#include "bfad_drv.h"
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
-#include "bfad_drv.h"
#include "bfad_im.h"
BFA_TRC_FILE(FCS, FCPIM);
break;
case BFA_FCS_ITNIM_SM_OFFLINE:
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_INITIATOR:
case BFA_FCS_ITNIM_SM_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_DELETE:
case BFA_FCS_ITNIM_SM_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
bfa_fcxp_discard(itnim->fcxp);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_INITIATOR:
} else {
/* invoke target offline */
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
- bfa_fcs_rport_logo_imp(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
}
break;
case BFA_FCS_ITNIM_SM_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
bfa_timer_stop(&itnim->timer);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_INITIATOR:
bfa_fcb_itnim_online(itnim->itnim_drv);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
wwn2str(rpwwn_buf, itnim->rport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Target (WWN = %s) is online for initiator (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
break;
case BFA_FCS_ITNIM_SM_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
bfa_itnim_offline(itnim->bfa_itnim);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_DELETE:
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
wwn2str(rpwwn_buf, itnim->rport->pwwn);
if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE)
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Target (WWN = %s) connectivity lost for "
"initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
else
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Target (WWN = %s) offlined by initiator (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
break;
switch (event) {
case BFA_FCS_ITNIM_SM_HCB_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_DELETE:
switch (event) {
case BFA_FCS_ITNIM_SM_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_RSP_ERROR:
itnim->stats.sler++;
bfa_trc(itnim->fcs, itnim->rport->pwwn);
- bfa_fcs_rport_logo_imp(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
}
struct bfa_fcs_itnim_s *
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
#include "bfa_fc.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(FCS, PORT);
bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting);
list_for_each_safe(qe, qen, &port->rport_q) {
rport = (struct bfa_fcs_rport_s *) qe;
- bfa_fcs_rport_delete(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
}
}
break;
bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting);
list_for_each_safe(qe, qen, &port->rport_q) {
rport = (struct bfa_fcs_rport_s *) qe;
- bfa_fcs_rport_delete(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
}
}
break;
return;
}
port->pid = rx_fchs->d_id;
+ bfa_lps_set_n2n_pid(port->fabric->lps, rx_fchs->d_id);
}
/*
(memcmp((void *)&bfa_fcs_lport_get_pwwn(port),
(void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
port->pid = rx_fchs->d_id;
+ bfa_lps_set_n2n_pid(port->fabric->lps, rx_fchs->d_id);
rport->pid = rx_fchs->s_id;
}
bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
* disappeared. Send implicit LOGO to old device.
*/
bfa_assert(rport->pwwn != plogi->port_name);
- bfa_fcs_rport_logo_imp(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
/*
* Inbound PLOGI from a new device (with old PID).
__port_action[port->fabric->fab_type].online(port);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Logical port online: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
__port_action[port->fabric->fab_type].offline(port);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
- if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE)
- BFA_LOG(KERN_ERR, bfad, log_level,
+ if (bfa_sm_cmp_state(port->fabric,
+ bfa_fcs_fabric_sm_online) == BFA_TRUE)
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Logical port lost fabric connectivity: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
else
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Logical port taken offline: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
list_for_each_safe(qe, qen, &port->rport_q) {
rport = (struct bfa_fcs_rport_s *) qe;
- bfa_fcs_rport_offline(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
}
}
char lpwwn_buf[BFA_STRING_32];
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Logical port deleted: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
port->vport ? port->vport->vport_drv : NULL);
bfa_fcs_vport_delete_comp(port->vport);
} else {
- bfa_fcs_fabric_port_delete_comp(port->fabric);
+ bfa_wc_down(&port->fabric->wc);
}
}
-
-/*
- * fcs_lport_api BFA FCS port API
- */
-/*
- * Module initialization
- */
-void
-bfa_fcs_lport_modinit(struct bfa_fcs_s *fcs)
-{
-
-}
-
-/*
- * Module cleanup
- */
-void
-bfa_fcs_lport_modexit(struct bfa_fcs_s *fcs)
-{
- bfa_fcs_modexit_comp(fcs);
-}
-
/*
* Unsolicited frame receive handling.
*/
struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
bfa_stats(lport, uf_recvs);
+ bfa_trc(lport->fcs, fchs->type);
if (!bfa_fcs_lport_is_online(lport)) {
bfa_stats(lport, uf_recv_drops);
* Only handles ELS frames for now.
*/
if (fchs->type != FC_TYPE_ELS) {
- bfa_trc(lport->fcs, fchs->type);
- bfa_assert(0);
+ bfa_trc(lport->fcs, fchs->s_id);
+ bfa_trc(lport->fcs, fchs->d_id);
+ /* ignore type FC_TYPE_FC_FSS */
+ if (fchs->type != FC_TYPE_FC_FSS)
+ bfa_sm_fault(lport->fcs, fchs->type);
return;
}
lport->fcs = fcs;
lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
lport->vport = vport;
- lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) :
- bfa_lps_get_tag(lport->fabric->lps);
+ lport->lp_tag = (vport) ? vport->lps->lp_tag :
+ lport->fabric->lps->lp_tag;
INIT_LIST_HEAD(&lport->rport_q);
lport->num_rports = 0;
vport ? vport->vport_drv : NULL);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(lport));
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"New logical port created: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
port_attr->port_cfg = port->port_cfg;
if (port->fabric) {
- port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric);
- port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric);
+ port_attr->port_type = port->fabric->oper_type;
+ port_attr->loopback = bfa_sm_cmp_state(port->fabric,
+ bfa_fcs_fabric_sm_loopback);
port_attr->authfail =
- bfa_fcs_fabric_is_auth_failed(port->fabric);
+ bfa_sm_cmp_state(port->fabric,
+ bfa_fcs_fabric_sm_auth_failed);
port_attr->fabric_name = bfa_fcs_lport_get_fabric_name(port);
memcpy(port_attr->fabric_ip_addr,
bfa_fcs_lport_get_fabric_ipaddr(port),
if (port->vport != NULL) {
port_attr->port_type = BFA_PORT_TYPE_VPORT;
port_attr->fpma_mac =
- bfa_lps_get_lp_mac(port->vport->lps);
+ port->vport->lps->lp_mac;
} else {
port_attr->fpma_mac =
- bfa_lps_get_lp_mac(port->fabric->lps);
+ port->fabric->lps->lp_mac;
}
} else {
port_attr->port_type = BFA_PORT_TYPE_UNKNOWN;
((void *)&pcfg->pwwn, (void *)&n2n_port->rem_port_wwn,
sizeof(wwn_t)) > 0) {
port->pid = N2N_LOCAL_PID;
+ bfa_lps_set_n2n_pid(port->fabric->lps, N2N_LOCAL_PID);
/*
* First, check if we know the device by pwwn.
*/
bfa_trc(port->fcs, rport->pid);
bfa_trc(port->fcs, rport->pwwn);
rport->pid = N2N_REMOTE_PID;
- bfa_fcs_rport_online(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
return;
}
bfa_assert(rport != NULL);
if (rport) {
bfa_trc(port->fcs, rport->pwwn);
- bfa_fcs_rport_delete(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
}
}
bfa_fcs_rport_create(port, N2N_REMOTE_PID);
struct fdmi_attr_s *attr;
u8 *curr_ptr;
u16 len, count;
+ u16 templen;
/*
* get hba attributes
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_NODENAME);
- attr->len = sizeof(wwn_t);
- memcpy(attr->value, &bfa_fcs_lport_get_nwwn(port), attr->len);
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = sizeof(wwn_t);
+ memcpy(attr->value, &bfa_fcs_lport_get_nwwn(port), templen);
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Manufacturer
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MANUFACTURER);
- attr->len = (u16) strlen(fcs_hba_attr->manufacturer);
- memcpy(attr->value, fcs_hba_attr->manufacturer, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = (u16) strlen(fcs_hba_attr->manufacturer);
+ memcpy(attr->value, fcs_hba_attr->manufacturer, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Serial Number
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_SERIALNUM);
- attr->len = (u16) strlen(fcs_hba_attr->serial_num);
- memcpy(attr->value, fcs_hba_attr->serial_num, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = (u16) strlen(fcs_hba_attr->serial_num);
+ memcpy(attr->value, fcs_hba_attr->serial_num, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Model
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL);
- attr->len = (u16) strlen(fcs_hba_attr->model);
- memcpy(attr->value, fcs_hba_attr->model, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = (u16) strlen(fcs_hba_attr->model);
+ memcpy(attr->value, fcs_hba_attr->model, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Model Desc
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL_DESC);
- attr->len = (u16) strlen(fcs_hba_attr->model_desc);
- memcpy(attr->value, fcs_hba_attr->model_desc, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = (u16) strlen(fcs_hba_attr->model_desc);
+ memcpy(attr->value, fcs_hba_attr->model_desc, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* H/W Version
if (fcs_hba_attr->hw_version[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_HW_VERSION);
- attr->len = (u16) strlen(fcs_hba_attr->hw_version);
- memcpy(attr->value, fcs_hba_attr->hw_version, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = (u16) strlen(fcs_hba_attr->hw_version);
+ memcpy(attr->value, fcs_hba_attr->hw_version, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
}
/*
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_DRIVER_VERSION);
- attr->len = (u16) strlen(fcs_hba_attr->driver_version);
- memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;;
+ templen = (u16) strlen(fcs_hba_attr->driver_version);
+ memcpy(attr->value, fcs_hba_attr->driver_version, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Option Rom Version
if (fcs_hba_attr->option_rom_ver[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_ROM_VERSION);
- attr->len = (u16) strlen(fcs_hba_attr->option_rom_ver);
- memcpy(attr->value, fcs_hba_attr->option_rom_ver, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = (u16) strlen(fcs_hba_attr->option_rom_ver);
+ memcpy(attr->value, fcs_hba_attr->option_rom_ver, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
}
/*
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_FW_VERSION);
- attr->len = (u16) strlen(fcs_hba_attr->driver_version);
- memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = (u16) strlen(fcs_hba_attr->driver_version);
+ memcpy(attr->value, fcs_hba_attr->driver_version, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* OS Name
if (fcs_hba_attr->os_name[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_OS_NAME);
- attr->len = (u16) strlen(fcs_hba_attr->os_name);
- memcpy(attr->value, fcs_hba_attr->os_name, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = (u16) strlen(fcs_hba_attr->os_name);
+ memcpy(attr->value, fcs_hba_attr->os_name, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
}
/*
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MAX_CT);
- attr->len = sizeof(fcs_hba_attr->max_ct_pyld);
- memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, attr->len);
- len += attr->len;
+ templen = sizeof(fcs_hba_attr->max_ct_pyld);
+ memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, templen);
+ len += templen;
count++;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Update size of payload
u8 *curr_ptr;
u16 len;
u8 count = 0;
+ u16 templen;
/*
* get port attributes
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FC4_TYPES);
- attr->len = sizeof(fcs_port_attr.supp_fc4_types);
- memcpy(attr->value, fcs_port_attr.supp_fc4_types, attr->len);
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = sizeof(fcs_port_attr.supp_fc4_types);
+ memcpy(attr->value, fcs_port_attr.supp_fc4_types, templen);
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
attr->len =
- cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Supported Speed
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_SUPP_SPEED);
- attr->len = sizeof(fcs_port_attr.supp_speed);
- memcpy(attr->value, &fcs_port_attr.supp_speed, attr->len);
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = sizeof(fcs_port_attr.supp_speed);
+ memcpy(attr->value, &fcs_port_attr.supp_speed, templen);
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
attr->len =
- cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* current Port Speed
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_SPEED);
- attr->len = sizeof(fcs_port_attr.curr_speed);
- memcpy(attr->value, &fcs_port_attr.curr_speed, attr->len);
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = sizeof(fcs_port_attr.curr_speed);
+ memcpy(attr->value, &fcs_port_attr.curr_speed, templen);
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* max frame size
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FRAME_SIZE);
- attr->len = sizeof(fcs_port_attr.max_frm_size);
- memcpy(attr->value, &fcs_port_attr.max_frm_size, attr->len);
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = sizeof(fcs_port_attr.max_frm_size);
+ memcpy(attr->value, &fcs_port_attr.max_frm_size, templen);
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* OS Device Name
if (fcs_port_attr.os_device_name[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_DEV_NAME);
- attr->len = (u16) strlen(fcs_port_attr.os_device_name);
- memcpy(attr->value, fcs_port_attr.os_device_name, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = (u16) strlen(fcs_port_attr.os_device_name);
+ memcpy(attr->value, fcs_port_attr.os_device_name, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
}
/*
* Host Name
if (fcs_port_attr.host_name[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_HOST_NAME);
- attr->len = (u16) strlen(fcs_port_attr.host_name);
- memcpy(attr->value, fcs_port_attr.host_name, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32));
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ templen = (u16) strlen(fcs_port_attr.host_name);
+ memcpy(attr->value, fcs_port_attr.host_name, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
- attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
}
/*
bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT);
}
-void
+static void
bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
struct bfa_fcs_fdmi_hba_attr_s *hba_attr)
{
hba_attr->max_ct_pyld = cpu_to_be32(FC_MAX_PDUSZ);
}
-void
+static void
bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
struct bfa_fcs_fdmi_port_attr_s *port_attr)
{
len = fc_gmal_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
bfa_fcs_lport_get_fcid(port),
- bfa_lps_get_peer_nwwn(port->fabric->lps));
+ port->fabric->lps->pr_nwwn);
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs,
len = fc_gfn_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
bfa_fcs_lport_get_fcid(port),
- bfa_lps_get_peer_nwwn(port->fabric->lps));
+ port->fabric->lps->pr_nwwn);
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs,
ms->fcxp = fcxp;
len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
- bfa_os_hton3b(FC_MGMT_SERVER),
+ bfa_hton3b(FC_MGMT_SERVER),
bfa_fcs_lport_get_fcid(port), 0,
port->port_cfg.pwwn, port->port_cfg.nwwn,
bfa_fcport_get_maxfrsize(port->fcs->bfa));
ns->fcxp = fcxp;
len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
- bfa_os_hton3b(FC_NAME_SERVER),
+ bfa_hton3b(FC_NAME_SERVER),
bfa_fcs_lport_get_fcid(port), 0,
port->port_cfg.pwwn, port->port_cfg.nwwn,
bfa_fcport_get_maxfrsize(port->fcs->bfa));
bfa_sm_send_event(ns, NSSM_EVENT_NS_QUERY);
}
-void
+static void
bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port)
{
/* Handle VU registrations for Base port only */
if ((!port->vport) && bfa_ioc_get_fcmode(&port->fcs->bfa->ioc)) {
len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
- bfa_lps_is_brcd_fabric(port->fabric->lps),
- port->pid, 0);
+ port->fabric->lps->brcd_switch,
+ port->pid, 0);
} else {
len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
BFA_FALSE,
while ((qe != qh) && (i < nrports)) {
rport = (struct bfa_fcs_rport_s *) qe;
- if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) {
+ if (bfa_ntoh3b(rport->pid) > 0xFFF000) {
qe = bfa_q_next(qe);
bfa_trc(fcs, (u32) rport->pwwn);
bfa_trc(fcs, rport->pid);
while ((qe != qh) && (i < *nrports)) {
rport = (struct bfa_fcs_rport_s *) qe;
- if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) {
+ if (bfa_ntoh3b(rport->pid) > 0xFFF000) {
qe = bfa_q_next(qe);
bfa_trc(fcs, (u32) rport->pwwn);
bfa_trc(fcs, rport->pid);
while (qe != qh) {
rport = (struct bfa_fcs_rport_s *) qe;
- if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000) ||
+ if ((bfa_ntoh3b(rport->pid) > 0xFFF000) ||
(bfa_fcs_rport_get_state(rport) ==
BFA_RPORT_OFFLINE)) {
qe = bfa_q_next(qe);
port_info->max_vports_supp =
bfa_lps_get_max_vport(port->fcs->bfa);
port_info->num_vports_inuse =
- bfa_fcs_fabric_vport_count(port->fabric);
+ port->fabric->num_vports;
port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP;
port_info->num_rports_inuse = port->num_rports;
} else {
switch (event) {
case BFA_FCS_VPORT_SM_START:
- if (bfa_fcs_fabric_is_online(__vport_fabric(vport))
+ if (bfa_sm_cmp_state(__vport_fabric(vport),
+ bfa_fcs_fabric_sm_online)
&& bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) {
bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc);
bfa_fcs_vport_do_fdisc(vport);
switch (event) {
case BFA_FCS_VPORT_SM_DELETE:
bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
- bfa_lps_discard(vport->lps);
+ bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_lport_delete(&vport->lport);
break;
case BFA_FCS_VPORT_SM_OFFLINE:
bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
- bfa_lps_discard(vport->lps);
+ bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
break;
case BFA_FCS_VPORT_SM_RSP_OK:
case BFA_FCS_VPORT_SM_OFFLINE:
bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
- bfa_lps_discard(vport->lps);
+ bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_lport_offline(&vport->lport);
break;
switch (event) {
case BFA_FCS_VPORT_SM_OFFLINE:
- bfa_lps_discard(vport->lps);
+ bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
/*
* !!! fall through !!!
*/
static void
bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport)
{
- u8 lsrjt_rsn = bfa_lps_get_lsrjt_rsn(vport->lps);
- u8 lsrjt_expl = bfa_lps_get_lsrjt_expl(vport->lps);
+ u8 lsrjt_rsn = vport->lps->lsrjt_rsn;
+ u8 lsrjt_expl = vport->lps->lsrjt_expl;
bfa_trc(__vport_fcs(vport), lsrjt_rsn);
bfa_trc(__vport_fcs(vport), lsrjt_expl);
/* For certain reason codes, we don't want to retry. */
- switch (bfa_lps_get_lsrjt_expl(vport->lps)) {
+ switch (vport->lps->lsrjt_expl) {
case FC_LS_RJT_EXP_INV_PORT_NAME: /* by brocade */
case FC_LS_RJT_EXP_INVALID_NPORT_ID: /* by Cisco */
if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES)
if (bfa_fcs_vport_lookup(fcs, vf_id, vport_cfg->pwwn) != NULL)
return BFA_STATUS_VPORT_EXISTS;
- if (bfa_fcs_fabric_vport_count(&fcs->fabric) ==
+ if (fcs->fabric.num_vports ==
bfa_lps_get_max_vport(fcs->bfa))
return BFA_STATUS_VPORT_MAX;
attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm);
}
-/*
- * Use this function to get vport's statistics.
- *
- * param[in] vport pointer to bfa_fcs_vport_t.
- * param[out] stats pointer to return vport statistics in
- *
- * return None
- */
-void
-bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport,
- struct bfa_vport_stats_s *stats)
-{
- *stats = vport->vport_stats;
-}
-
-/*
- * Use this function to clear vport's statistics.
- *
- * param[in] vport pointer to bfa_fcs_vport_t.
- *
- * return None
- */
-void
-bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport)
-{
- memset(&vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s));
-}
/*
* Lookup a virtual port. Excludes base port from lookup.
/*
* Initialiaze the V-Port fields
*/
- __vport_fcid(vport) = bfa_lps_get_pid(vport->lps);
+ __vport_fcid(vport) = vport->lps->lp_pid;
vport->vport_stats.fdisc_accepts++;
bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK);
break;
break;
case BFA_STATUS_EPROTOCOL:
- switch (bfa_lps_get_extstatus(vport->lps)) {
+ switch (vport->lps->ext_status) {
case BFA_EPROTO_BAD_ACCEPT:
vport->vport_stats.fdisc_acc_bad++;
break;
* rport.c Remote port implementation.
*/
+#include "bfad_drv.h"
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(FCS, RPORT);
static void bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport,
struct fchs_s *rx_fchs, u16 len);
static void bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport);
-/*
- * fcs_rport_sm FCS rport state machine events
- */
-
-enum rport_event {
- RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */
- RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */
- RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */
- RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */
- RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */
- RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */
- RPSM_EVENT_DELETE = 7, /* RPORT delete request */
- RPSM_EVENT_SCN = 8, /* state change notification */
- RPSM_EVENT_ACCEPTED = 9, /* Good response from remote device */
- RPSM_EVENT_FAILED = 10, /* Request to rport failed. */
- RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */
- RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */
- RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */
- RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */
- RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */
- RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */
- RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */
- RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continously */
-};
static void bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport,
enum rport_event event);
case RPSM_EVENT_LOGO_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
case RPSM_EVENT_LOGO_IMP:
case RPSM_EVENT_ADDRESS_CHANGE:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
case RPSM_EVENT_PLOGI_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
bfa_fcs_rport_send_plogiacc(rport, NULL);
break;
case RPSM_EVENT_DELETE:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
case RPSM_EVENT_SCN:
switch (event) {
case RPSM_EVENT_FC4_OFFLINE:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
case RPSM_EVENT_DELETE:
switch (event) {
case RPSM_EVENT_FC4_OFFLINE:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
default:
switch (event) {
case RPSM_EVENT_FC4_OFFLINE:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
case RPSM_EVENT_SCN:
twin->stats.plogi_rcvd += rport->stats.plogi_rcvd;
twin->stats.plogi_accs++;
- bfa_fcs_rport_delete(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
bfa_fcs_rport_update(twin, plogi_rsp);
twin->pid = rsp_fchs->s_id;
rport->itnim = bfa_fcs_itnim_create(rport);
if (!rport->itnim) {
bfa_trc(fcs, rpid);
- bfa_rport_delete(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport,
+ BFA_RPORT_SM_DELETE);
kfree(rport_drv);
return NULL;
}
bfa_fcs_rpf_rport_offline(rport);
}
- bfa_rport_delete(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_DELETE);
bfa_fcs_lport_del_rport(port, rport);
kfree(rport->rp_drv);
}
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
wwn2str(rpwwn_buf, rport->pwwn);
if (!BFA_FCS_PID_IS_WKA(rport->pid))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Remote port (WWN = %s) online for logical port (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
}
wwn2str(rpwwn_buf, rport->pwwn);
if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
if (bfa_fcs_lport_is_online(rport->port) == BFA_TRUE)
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Remote port (WWN = %s) connectivity lost for "
"logical port (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
else
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Remote port (WWN = %s) offlined by "
"logical port (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD);
}
-/*
- * Called by bport/vport to delete a remote port instance.
- *
- * Rport delete is called under the following conditions:
- * - vport is deleted
- * - vf is deleted
- * - explicit request from OS to delete rport
- */
-void
-bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
-}
-/*
- * Called by bport/vport to when a target goes offline.
- *
- */
-void
-bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
-}
-
-/*
- * Called by bport in n2n when a target (attached port) becomes online.
- *
- */
-void
-bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
-}
/*
* Called by bport/vport to notify SCN for the remote port
*/
bfa_sm_send_event(rport, RPSM_EVENT_SCN);
}
-/*
- * Called by fcpim to notify that the ITN cleanup is done.
- */
-void
-bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE);
-}
-
-/*
- * Called by fcptm to notify that the ITN cleanup is done.
- */
-void
-bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE);
-}
/*
* brief
bfa_trc(rport->fcs, rport->pwwn);
}
-/*
- * Called to process any unsolicted frames from this remote port
- */
-void
-bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
-}
-
/*
* Called to process any unsolicted frames from this remote port
*/
return bfa_sm_to_state(rport_sm_table, rport->sm);
}
+
/*
* brief
* Called by the Driver to set rport delete/ageout timeout
bfa_fcs_rport_del_timeout = rport_tmo * 1000;
}
void
-bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, u16 ox_id)
+bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, __be16 ox_id)
{
bfa_trc(rport->fcs, rport->pid);
* fcs_rport_api FCS rport API.
*/
-/*
- * Direct API to add a target by port wwn. This interface is used, for
- * example, by bios when target pwwn is known from boot lun configuration.
- */
-bfa_status_t
-bfa_fcs_rport_add(struct bfa_fcs_lport_s *port, wwn_t *pwwn,
- struct bfa_fcs_rport_s *rport, struct bfad_rport_s *rport_drv)
-{
- bfa_trc(port->fcs, *pwwn);
-
- return BFA_STATUS_OK;
-}
-
-/*
- * Direct API to remove a target and its associated resources. This
- * interface is used, for example, by driver to remove target
- * ports from the target list for a VM.
- */
-bfa_status_t
-bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport_in)
-{
-
- struct bfa_fcs_rport_s *rport;
-
- bfa_trc(rport_in->fcs, rport_in->pwwn);
-
- rport = bfa_fcs_lport_get_rport_by_pwwn(rport_in->port, rport_in->pwwn);
- if (rport == NULL) {
- /*
- * TBD Error handling
- */
- bfa_trc(rport_in->fcs, rport_in->pid);
- return BFA_STATUS_UNKNOWN_RWWN;
- }
-
- /*
- * TBD if this remote port is online, send a logo
- */
- return BFA_STATUS_OK;
-
-}
-
-/*
- * Remote device status for display/debug.
- */
-void
-bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
- struct bfa_rport_attr_s *rport_attr)
-{
- struct bfa_rport_qos_attr_s qos_attr;
- bfa_fcs_lport_t *port = rport->port;
- bfa_port_speed_t rport_speed = rport->rpf.rpsc_speed;
-
- memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s));
-
- rport_attr->pid = rport->pid;
- rport_attr->pwwn = rport->pwwn;
- rport_attr->nwwn = rport->nwwn;
- rport_attr->cos_supported = rport->fc_cos;
- rport_attr->df_sz = rport->maxfrsize;
- rport_attr->state = bfa_fcs_rport_get_state(rport);
- rport_attr->fc_cos = rport->fc_cos;
- rport_attr->cisc = rport->cisc;
- rport_attr->scsi_function = rport->scsi_function;
- rport_attr->curr_speed = rport->rpf.rpsc_speed;
- rport_attr->assigned_speed = rport->rpf.assigned_speed;
-
- bfa_rport_get_qos_attr(rport->bfa_rport, &qos_attr);
- rport_attr->qos_attr = qos_attr;
-
- rport_attr->trl_enforced = BFA_FALSE;
- if (bfa_fcport_is_ratelim(port->fcs->bfa)) {
- if (rport_speed == BFA_PORT_SPEED_UNKNOWN) {
- /* Use default ratelim speed setting */
- rport_speed =
- bfa_fcport_get_ratelim_speed(rport->fcs->bfa);
- }
-
- if (rport_speed < bfa_fcs_lport_get_rport_max_speed(port))
- rport_attr->trl_enforced = BFA_TRUE;
- }
-}
-
-/*
- * Per remote device statistics.
- */
-void
-bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport,
- struct bfa_rport_stats_s *stats)
-{
- *stats = rport->stats;
-}
-
-void
-bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport)
-{
- memset((char *)&rport->stats, 0,
- sizeof(struct bfa_rport_stats_s));
-}
-
struct bfa_fcs_rport_s *
bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
{
return rport;
}
-/*
- * This API is to set the Rport's speed. Should be used when RPSC is not
- * supported by the rport.
- */
-void
-bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport, bfa_port_speed_t speed)
-{
- rport->rpf.assigned_speed = speed;
-
- /* Set this speed in f/w only if the RPSC speed is not available */
- if (rport->rpf.rpsc_speed == BFA_PORT_SPEED_UNKNOWN)
- bfa_rport_speed(rport->bfa_rport, speed);
-}
-
-
-
/*
* Remote port features (RPF) implementation.
*/
case RPFSM_EVENT_RPORT_ONLINE:
/* Send RPSC2 to a Brocade fabric only. */
if ((!BFA_FCS_PID_IS_WKA(rport->pid)) &&
- ((bfa_lps_is_brcd_fabric(rport->port->fabric->lps)) ||
+ ((rport->port->fabric->lps->brcd_switch) ||
(bfa_fcs_fabric_get_switch_oui(fabric) ==
BFA_FCS_BRCD_SWITCH_OUI))) {
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_modules.h"
#include "bfi_cbreg.h"
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_modules.h"
#include "bfi_ctreg.h"
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_ioc.h"
#include "bfi_ctreg.h"
#include "bfa_defs.h"
#include "bfa_defs_svc.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(CNA, IOC);
#define BFA_IOC_TOV 3000 /* msecs */
#define BFA_IOC_HWSEM_TOV 500 /* msecs */
#define BFA_IOC_HB_TOV 500 /* msecs */
-#define BFA_IOC_HWINIT_MAX 2
+#define BFA_IOC_HWINIT_MAX 5
#define BFA_IOC_TOV_RECOVER BFA_IOC_HB_TOV
#define bfa_ioc_timer_start(__ioc) \
bfa_ioc_hb_check, (__ioc), BFA_IOC_HB_TOV)
#define bfa_hb_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->hb_timer)
-#define BFA_DBG_FWTRC_ENTS (BFI_IOC_TRC_ENTS)
-#define BFA_DBG_FWTRC_LEN \
- (BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc_s) + \
- (sizeof(struct bfa_trc_mod_s) - \
- BFA_TRC_MAX * sizeof(struct bfa_trc_s)))
#define BFA_DBG_FWTRC_OFF(_fn) (BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn))
/*
((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
-#define bfa_ioc_notify_hbfail(__ioc) \
- ((__ioc)->ioc_hwif->ioc_notify_hbfail(__ioc))
-
-#ifdef BFA_IOC_IS_UEFI
-#define bfa_ioc_is_bios_optrom(__ioc) (0)
-#define bfa_ioc_is_uefi(__ioc) BFA_IOC_IS_UEFI
-#else
-#define bfa_ioc_is_bios_optrom(__ioc) \
- (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(__ioc)) < BFA_IOC_FWIMG_MINSZ)
-#define bfa_ioc_is_uefi(__ioc) (0)
-#endif
+#define bfa_ioc_notify_fail(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc))
+#define bfa_ioc_sync_join(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_join(__ioc))
+#define bfa_ioc_sync_leave(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_leave(__ioc))
+#define bfa_ioc_sync_ack(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_ack(__ioc))
+#define bfa_ioc_sync_complete(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_complete(__ioc))
#define bfa_ioc_mbox_cmd_pending(__ioc) \
(!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \
* forward declarations
*/
static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc);
-static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc);
static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force);
static void bfa_ioc_timeout(void *ioc);
static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc);
static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc);
static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc);
static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc);
-static void bfa_ioc_hb_stop(struct bfa_ioc_s *ioc);
-static void bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force);
static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc);
static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc);
static void bfa_ioc_recover(struct bfa_ioc_s *ioc);
static void bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc);
static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc);
static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc);
-static void bfa_ioc_pf_enabled(struct bfa_ioc_s *ioc);
-static void bfa_ioc_pf_disabled(struct bfa_ioc_s *ioc);
-static void bfa_ioc_pf_failed(struct bfa_ioc_s *ioc);
+static void bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc);
+static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc);
static void bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc);
-/*
- * hal_ioc_sm
- */
/*
* IOC state machine definitions/declarations
IOC_E_ENABLED = 5, /* f/w enabled */
IOC_E_FWRSP_GETATTR = 6, /* IOC get attribute response */
IOC_E_DISABLED = 7, /* f/w disabled */
- IOC_E_FAILED = 8, /* failure notice by iocpf sm */
- IOC_E_HBFAIL = 9, /* heartbeat failure */
- IOC_E_HWERROR = 10, /* hardware error interrupt */
- IOC_E_TIMEOUT = 11, /* timeout */
+ IOC_E_INITFAILED = 8, /* failure notice by iocpf sm */
+ IOC_E_PFFAILED = 9, /* failure notice by iocpf sm */
+ IOC_E_HBFAIL = 10, /* heartbeat failure */
+ IOC_E_HWERROR = 11, /* hardware error interrupt */
+ IOC_E_TIMEOUT = 12, /* timeout */
};
bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc_s, enum ioc_event);
-bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event);
{BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING},
{BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
{BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
- {BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL},
+ {BFA_SM(bfa_ioc_sm_fail_retry), BFA_IOC_INITFAIL},
{BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL},
{BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
{BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
/*
* Forward declareations for iocpf state machine
*/
-static void bfa_iocpf_enable(struct bfa_ioc_s *ioc);
-static void bfa_iocpf_disable(struct bfa_ioc_s *ioc);
-static void bfa_iocpf_fail(struct bfa_ioc_s *ioc);
-static void bfa_iocpf_initfail(struct bfa_ioc_s *ioc);
-static void bfa_iocpf_getattrfail(struct bfa_ioc_s *ioc);
-static void bfa_iocpf_stop(struct bfa_ioc_s *ioc);
static void bfa_iocpf_timeout(void *ioc_arg);
static void bfa_iocpf_sem_timeout(void *ioc_arg);
bfa_fsm_state_decl(bfa_iocpf, hwinit, struct bfa_iocpf_s, enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, enabling, struct bfa_iocpf_s, enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, ready, struct bfa_iocpf_s, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, initfail_sync, struct bfa_iocpf_s,
+ enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, initfail, struct bfa_iocpf_s, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, fail_sync, struct bfa_iocpf_s, enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, fail, struct bfa_iocpf_s, enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, disabling, struct bfa_iocpf_s, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, disabling_sync, struct bfa_iocpf_s,
+ enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf_s, enum iocpf_event);
static struct bfa_sm_table_s iocpf_sm_table[] = {
{BFA_SM(bfa_iocpf_sm_hwinit), BFA_IOCPF_HWINIT},
{BFA_SM(bfa_iocpf_sm_enabling), BFA_IOCPF_HWINIT},
{BFA_SM(bfa_iocpf_sm_ready), BFA_IOCPF_READY},
+ {BFA_SM(bfa_iocpf_sm_initfail_sync), BFA_IOCPF_INITFAIL},
{BFA_SM(bfa_iocpf_sm_initfail), BFA_IOCPF_INITFAIL},
+ {BFA_SM(bfa_iocpf_sm_fail_sync), BFA_IOCPF_FAIL},
{BFA_SM(bfa_iocpf_sm_fail), BFA_IOCPF_FAIL},
{BFA_SM(bfa_iocpf_sm_disabling), BFA_IOCPF_DISABLING},
+ {BFA_SM(bfa_iocpf_sm_disabling_sync), BFA_IOCPF_DISABLING},
{BFA_SM(bfa_iocpf_sm_disabled), BFA_IOCPF_DISABLED},
};
static void
bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc)
{
- bfa_iocpf_enable(ioc);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_ENABLE);
}
/*
bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
break;
- case IOC_E_FAILED:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
- break;
-
+ case IOC_E_PFFAILED:
+ /* !!! fall through !!! */
case IOC_E_HWERROR:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
- bfa_iocpf_initfail(ioc);
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ if (event != IOC_E_PFFAILED)
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
break;
case IOC_E_DISABLE:
case IOC_E_DETACH:
bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
- bfa_iocpf_stop(ioc);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
break;
case IOC_E_ENABLE:
bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
break;
- case IOC_E_FAILED:
- bfa_ioc_timer_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
break;
-
+ case IOC_E_PFFAILED:
case IOC_E_HWERROR:
bfa_ioc_timer_stop(ioc);
- /* fall through */
-
+ /* !!! fall through !!! */
case IOC_E_TIMEOUT:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
- bfa_iocpf_getattrfail(ioc);
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ if (event != IOC_E_PFFAILED)
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL);
break;
case IOC_E_DISABLE:
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
bfa_ioc_hb_monitor(ioc);
- BFA_LOG(KERN_INFO, bfad, log_level, "IOC enabled\n");
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n");
}
static void
break;
case IOC_E_DISABLE:
- bfa_ioc_hb_stop(ioc);
+ bfa_hb_timer_stop(ioc);
bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
break;
- case IOC_E_FAILED:
- bfa_ioc_hb_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
- break;
-
+ case IOC_E_PFFAILED:
case IOC_E_HWERROR:
- bfa_ioc_hb_stop(ioc);
+ bfa_hb_timer_stop(ioc);
/* !!! fall through !!! */
-
case IOC_E_HBFAIL:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
- bfa_iocpf_fail(ioc);
+ bfa_ioc_fail_notify(ioc);
+
+ if (ioc->iocpf.auto_recover)
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ else
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
+
+ if (event != IOC_E_PFFAILED)
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);
break;
default:
bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc)
{
struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
- bfa_iocpf_disable(ioc);
- BFA_LOG(KERN_INFO, bfad, log_level, "IOC disabled\n");
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE);
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC disabled\n");
}
/*
* after iocpf sm completes failure processing and
* moves to disabled state.
*/
- bfa_iocpf_fail(ioc);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);
break;
default:
case IOC_E_DETACH:
bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
- bfa_iocpf_stop(ioc);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
break;
default:
static void
-bfa_ioc_sm_initfail_entry(struct bfa_ioc_s *ioc)
+bfa_ioc_sm_fail_retry_entry(struct bfa_ioc_s *ioc)
{
- ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_trc(ioc, 0);
}
/*
- * Hardware initialization failed.
+ * Hardware initialization retry.
*/
static void
-bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event)
+bfa_ioc_sm_fail_retry(struct bfa_ioc_s *ioc, enum ioc_event event)
{
bfa_trc(ioc, event);
bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
break;
- case IOC_E_FAILED:
+ case IOC_E_PFFAILED:
+ case IOC_E_HWERROR:
/*
- * Initialization failure during iocpf init retry.
+ * Initialization retry failed.
*/
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ if (event != IOC_E_PFFAILED)
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
+ break;
+
+ case IOC_E_INITFAILED:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
+ break;
+
+ case IOC_E_ENABLE:
break;
case IOC_E_DISABLE:
case IOC_E_DETACH:
bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
- bfa_iocpf_stop(ioc);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
break;
default:
static void
bfa_ioc_sm_fail_entry(struct bfa_ioc_s *ioc)
{
- struct list_head *qe;
- struct bfa_ioc_hbfail_notify_s *notify;
- struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
-
- /*
- * Notify driver and common modules registered for notification.
- */
- ioc->cbfn->hbfail_cbfn(ioc->bfa);
- list_for_each(qe, &ioc->hb_notify_q) {
- notify = (struct bfa_ioc_hbfail_notify_s *) qe;
- notify->cbfn(notify->cbarg);
- }
-
- BFA_LOG(KERN_CRIT, bfad, log_level,
- "Heart Beat of IOC has failed\n");
+ bfa_trc(ioc, 0);
}
/*
switch (event) {
- case IOC_E_FAILED:
- /*
- * Initialization failure during iocpf recovery.
- * !!! Fall through !!!
- */
case IOC_E_ENABLE:
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
break;
- case IOC_E_ENABLED:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
- break;
-
case IOC_E_DISABLE:
bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
break;
+ case IOC_E_DETACH:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
+ break;
+
case IOC_E_HWERROR:
/*
* HB failure notification, ignore.
}
}
-
-
/*
* IOCPF State Machine
*/
-
/*
* Reset entry actions -- initialize state machine
*/
switch (event) {
case IOCPF_E_SEMLOCKED:
if (bfa_ioc_firmware_lock(ioc)) {
- iocpf->retry_count = 0;
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ if (bfa_ioc_sync_complete(ioc)) {
+ iocpf->retry_count = 0;
+ bfa_ioc_sync_join(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ } else {
+ bfa_ioc_firmware_unlock(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_sem_timer_start(ioc);
+ }
} else {
- bfa_ioc_hw_sem_release(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_mismatch);
}
break;
case IOCPF_E_DISABLE:
- bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_sem_timer_stop(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
- bfa_ioc_pf_disabled(ioc);
+ bfa_fsm_send_event(ioc, IOC_E_DISABLED);
break;
case IOCPF_E_STOP:
- bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_sem_timer_stop(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
break;
case IOCPF_E_DISABLE:
bfa_iocpf_timer_stop(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
- bfa_ioc_pf_disabled(ioc);
+ bfa_fsm_send_event(ioc, IOC_E_DISABLED);
break;
case IOCPF_E_STOP:
switch (event) {
case IOCPF_E_SEMLOCKED:
- iocpf->retry_count = 0;
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ if (bfa_ioc_sync_complete(ioc)) {
+ bfa_ioc_sync_join(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ } else {
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_sem_timer_start(ioc);
+ }
break;
case IOCPF_E_DISABLE:
- bfa_ioc_hw_sem_get_cancel(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ bfa_sem_timer_stop(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
break;
default:
}
}
-
static void
bfa_iocpf_sm_hwinit_entry(struct bfa_iocpf_s *iocpf)
{
bfa_iocpf_timer_start(iocpf->ioc);
- bfa_ioc_reset(iocpf->ioc, BFA_FALSE);
+ bfa_ioc_hwinit(iocpf->ioc, BFA_FALSE);
}
/*
*/
case IOCPF_E_TIMEOUT:
- iocpf->retry_count++;
- if (iocpf->retry_count < BFA_IOC_HWINIT_MAX) {
- bfa_iocpf_timer_start(ioc);
- bfa_ioc_reset(ioc, BFA_TRUE);
- break;
- }
-
- bfa_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
-
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
if (event == IOCPF_E_TIMEOUT)
- bfa_ioc_pf_failed(ioc);
+ bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
break;
case IOCPF_E_DISABLE:
- bfa_ioc_hw_sem_release(ioc);
bfa_iocpf_timer_stop(ioc);
+ bfa_ioc_sync_leave(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
break;
}
}
-
static void
bfa_iocpf_sm_enabling_entry(struct bfa_iocpf_s *iocpf)
{
switch (event) {
case IOCPF_E_FWRSP_ENABLE:
bfa_iocpf_timer_stop(ioc);
- bfa_ioc_hw_sem_release(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_ready);
break;
*/
case IOCPF_E_TIMEOUT:
- iocpf->retry_count++;
- if (iocpf->retry_count < BFA_IOC_HWINIT_MAX) {
- writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
- break;
- }
-
- bfa_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
-
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
if (event == IOCPF_E_TIMEOUT)
- bfa_ioc_pf_failed(ioc);
+ bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
break;
case IOCPF_E_DISABLE:
bfa_iocpf_timer_stop(ioc);
- bfa_ioc_hw_sem_release(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);
break;
}
}
-
-
static void
bfa_iocpf_sm_ready_entry(struct bfa_iocpf_s *iocpf)
{
- bfa_ioc_pf_enabled(iocpf->ioc);
+ bfa_fsm_send_event(iocpf->ioc, IOC_E_ENABLED);
}
static void
break;
case IOCPF_E_GETATTRFAIL:
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
break;
case IOCPF_E_FAIL:
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);
break;
case IOCPF_E_FWREADY:
- if (bfa_ioc_is_operational(ioc))
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
- else
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
-
- bfa_ioc_pf_failed(ioc);
+ if (bfa_ioc_is_operational(ioc)) {
+ bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);
+ } else {
+ bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
+ }
break;
default:
}
}
-
static void
bfa_iocpf_sm_disabling_entry(struct bfa_iocpf_s *iocpf)
{
case IOCPF_E_FWRSP_DISABLE:
case IOCPF_E_FWREADY:
bfa_iocpf_timer_stop(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
break;
case IOCPF_E_FAIL:
case IOCPF_E_TIMEOUT:
writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
break;
case IOCPF_E_FWRSP_ENABLE:
}
}
+static void
+bfa_iocpf_sm_disabling_sync_entry(struct bfa_iocpf_s *iocpf)
+{
+ bfa_ioc_hw_sem_get(iocpf->ioc);
+}
+
+/**
+ * IOC hb ack request is being removed.
+ */
+static void
+bfa_iocpf_sm_disabling_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc_s *ioc = iocpf->ioc;
+
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOCPF_E_SEMLOCKED:
+ bfa_ioc_sync_leave(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ break;
+
+ case IOCPF_E_FAIL:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
/*
* IOC disable completion entry.
*/
static void
bfa_iocpf_sm_disabled_entry(struct bfa_iocpf_s *iocpf)
{
- bfa_ioc_pf_disabled(iocpf->ioc);
+ bfa_fsm_send_event(iocpf->ioc, IOC_E_DISABLED);
}
static void
switch (event) {
case IOCPF_E_ENABLE:
+ iocpf->retry_count = 0;
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
break;
}
}
+static void
+bfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf_s *iocpf)
+{
+ bfa_ioc_hw_sem_get(iocpf->ioc);
+}
+
+/**
+ * @brief
+ * Hardware initialization failed.
+ */
+static void
+bfa_iocpf_sm_initfail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc_s *ioc = iocpf->ioc;
+
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOCPF_E_SEMLOCKED:
+ bfa_ioc_notify_fail(ioc);
+ bfa_ioc_sync_ack(ioc);
+ iocpf->retry_count++;
+ if (iocpf->retry_count >= BFA_IOC_HWINIT_MAX) {
+ bfa_ioc_sync_leave(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
+ } else {
+ if (bfa_ioc_sync_complete(ioc))
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ else {
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
+ }
+ }
+ break;
+
+ case IOCPF_E_DISABLE:
+ bfa_sem_timer_stop(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
+ break;
+
+ case IOCPF_E_STOP:
+ bfa_sem_timer_stop(ioc);
+ bfa_ioc_firmware_unlock(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
+ break;
+
+ case IOCPF_E_FAIL:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
static void
bfa_iocpf_sm_initfail_entry(struct bfa_iocpf_s *iocpf)
{
- bfa_iocpf_timer_start(iocpf->ioc);
+ bfa_fsm_send_event(iocpf->ioc, IOC_E_INITFAILED);
}
/*
switch (event) {
case IOCPF_E_DISABLE:
- bfa_iocpf_timer_stop(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
break;
case IOCPF_E_STOP:
- bfa_iocpf_timer_stop(ioc);
bfa_ioc_firmware_unlock(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
break;
- case IOCPF_E_TIMEOUT:
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
- break;
-
default:
bfa_sm_fault(ioc, event);
}
}
-
static void
-bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf)
+bfa_iocpf_sm_fail_sync_entry(struct bfa_iocpf_s *iocpf)
{
- /*
+ /**
* Mark IOC as failed in hardware and stop firmware.
*/
bfa_ioc_lpu_stop(iocpf->ioc);
- writel(BFI_IOC_FAIL, iocpf->ioc->ioc_regs.ioc_fwstate);
- /*
- * Notify other functions on HB failure.
- */
- bfa_ioc_notify_hbfail(iocpf->ioc);
-
- /*
+ /**
* Flush any queued up mailbox requests.
*/
bfa_ioc_mbox_hbfail(iocpf->ioc);
- if (iocpf->auto_recover)
- bfa_iocpf_recovery_timer_start(iocpf->ioc);
+ bfa_ioc_hw_sem_get(iocpf->ioc);
+}
+
+static void
+bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc_s *ioc = iocpf->ioc;
+
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOCPF_E_SEMLOCKED:
+ iocpf->retry_count = 0;
+ bfa_ioc_sync_ack(ioc);
+ bfa_ioc_notify_fail(ioc);
+ if (!iocpf->auto_recover) {
+ bfa_ioc_sync_leave(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+ } else {
+ if (bfa_ioc_sync_complete(ioc))
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ else {
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
+ }
+ }
+ break;
+
+ case IOCPF_E_DISABLE:
+ bfa_sem_timer_stop(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
+ break;
+
+ case IOCPF_E_FAIL:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+static void
+bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf)
+{
}
/*
switch (event) {
case IOCPF_E_DISABLE:
- if (iocpf->auto_recover)
- bfa_iocpf_timer_stop(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
break;
- case IOCPF_E_TIMEOUT:
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
- break;
-
default:
bfa_sm_fault(ioc, event);
}
}
-
-
/*
- * hal_ioc_pvt BFA IOC private functions
+ * BFA IOC private functions
*/
static void
return BFA_FALSE;
}
-void
-bfa_ioc_sem_release(void __iomem *sem_reg)
-{
- writel(1, sem_reg);
-}
-
static void
bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
{
bfa_sem_timer_start(ioc);
}
-void
-bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc)
-{
- writel(1, ioc->ioc_regs.ioc_sem_reg);
-}
-
-static void
-bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc)
-{
- bfa_sem_timer_stop(ioc);
-}
-
/*
* Initialize LPU local memory (aka secondary memory / SRAM)
*/
int i;
u32 *fwsig = (u32 *) fwhdr;
- pgnum = bfa_ioc_smem_pgnum(ioc, loff);
- pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+ pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);
+ pgoff = PSS_SMEM_PGOFF(loff);
writel(pgnum, ioc->ioc_regs.host_page_num_fn);
for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32));
writel(1, ioc->ioc_regs.lpu_mbox_cmd);
}
-
static void
bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
{
bfa_ioc_send_enable(struct bfa_ioc_s *ioc)
{
struct bfi_ioc_ctrl_req_s enable_req;
- struct bfa_timeval_s tv;
+ struct timeval tv;
bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
bfa_ioc_portid(ioc));
enable_req.ioc_class = ioc->ioc_mc;
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
enable_req.tv_sec = be32_to_cpu(tv.tv_sec);
bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s));
}
hb_count = readl(ioc->ioc_regs.heartbeat);
if (ioc->hb_count == hb_count) {
- printk(KERN_CRIT "Firmware heartbeat failure at %d", hb_count);
bfa_ioc_recover(ioc);
return;
} else {
bfa_hb_timer_start(ioc);
}
-static void
-bfa_ioc_hb_stop(struct bfa_ioc_s *ioc)
-{
- bfa_hb_timer_stop(ioc);
-}
-
-
/*
* Initiate a full firmware download.
*/
bfa_trc(ioc, bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)));
fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno);
- pgnum = bfa_ioc_smem_pgnum(ioc, loff);
- pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+ pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);
+ pgoff = PSS_SMEM_PGOFF(loff);
writel(pgnum, ioc->ioc_regs.host_page_num_fn);
}
}
- writel(bfa_ioc_smem_pgnum(ioc, 0), ioc->ioc_regs.host_page_num_fn);
+ writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),
+ ioc->ioc_regs.host_page_num_fn);
/*
* Set boot type and boot param at the end.
swab32(boot_env));
}
-static void
-bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force)
-{
- bfa_ioc_hwinit(ioc, force);
-}
/*
* Update BFA configuration from firmware configuration.
static bfa_status_t
bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz)
{
- u32 pgnum, loff, r32;
+ u32 pgnum, loff;
+ __be32 r32;
int i, len;
u32 *buf = tbuf;
- pgnum = bfa_ioc_smem_pgnum(ioc, soff);
- loff = bfa_ioc_smem_pgoff(ioc, soff);
+ pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff);
+ loff = PSS_SMEM_PGOFF(soff);
bfa_trc(ioc, pgnum);
bfa_trc(ioc, loff);
bfa_trc(ioc, sz);
writel(pgnum, ioc->ioc_regs.host_page_num_fn);
}
}
- writel(bfa_ioc_smem_pgnum(ioc, 0), ioc->ioc_regs.host_page_num_fn);
+ writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),
+ ioc->ioc_regs.host_page_num_fn);
/*
* release semaphore.
*/
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_init_sem_reg);
bfa_trc(ioc, pgnum);
return BFA_STATUS_OK;
int i, len;
u32 pgnum, loff;
- pgnum = bfa_ioc_smem_pgnum(ioc, soff);
- loff = bfa_ioc_smem_pgoff(ioc, soff);
+ pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff);
+ loff = PSS_SMEM_PGOFF(soff);
bfa_trc(ioc, pgnum);
bfa_trc(ioc, loff);
bfa_trc(ioc, sz);
writel(pgnum, ioc->ioc_regs.host_page_num_fn);
}
}
- writel(bfa_ioc_smem_pgnum(ioc, 0), ioc->ioc_regs.host_page_num_fn);
+ writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),
+ ioc->ioc_regs.host_page_num_fn);
/*
* release semaphore.
*/
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_init_sem_reg);
bfa_trc(ioc, pgnum);
return BFA_STATUS_OK;
}
-/*
- * hal iocpf to ioc interface
- */
static void
-bfa_ioc_pf_enabled(struct bfa_ioc_s *ioc)
+bfa_ioc_fail_notify(struct bfa_ioc_s *ioc)
{
- bfa_fsm_send_event(ioc, IOC_E_ENABLED);
-}
+ struct list_head *qe;
+ struct bfa_ioc_hbfail_notify_s *notify;
+ struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
-static void
-bfa_ioc_pf_disabled(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(ioc, IOC_E_DISABLED);
-}
+ /**
+ * Notify driver and common modules registered for notification.
+ */
+ ioc->cbfn->hbfail_cbfn(ioc->bfa);
+ list_for_each(qe, &ioc->hb_notify_q) {
+ notify = (struct bfa_ioc_hbfail_notify_s *) qe;
+ notify->cbfn(notify->cbarg);
+ }
+
+ bfa_ioc_debug_save_ftrc(ioc);
+
+ BFA_LOG(KERN_CRIT, bfad, bfa_log_level,
+ "Heart Beat of IOC has failed\n");
-static void
-bfa_ioc_pf_failed(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(ioc, IOC_E_FAILED);
}
static void
* Provide enable completion callback.
*/
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
- BFA_LOG(KERN_WARNING, bfad, log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Running firmware version is incompatible "
"with the driver version\n");
}
-
-
-/*
- * hal_ioc_public
- */
-
bfa_status_t
bfa_ioc_pll_init(struct bfa_ioc_s *ioc)
{
/*
* release semaphore.
*/
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_init_sem_reg);
return BFA_STATUS_OK;
}
void
bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg)
{
- u32 *msgp = mbmsg;
+ __be32 *msgp = mbmsg;
u32 r32;
int i;
ioc->attr = (struct bfi_ioc_attr_s *) dm_kva;
}
-/*
- * Return size of dma memory required.
- */
-u32
-bfa_ioc_meminfo(void)
-{
- return BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
-}
-
void
bfa_ioc_enable(struct bfa_ioc_s *ioc)
{
bfa_fsm_send_event(ioc, IOC_E_DISABLE);
}
-/*
- * Returns memory required for saving firmware trace in case of crash.
- * Driver must call this interface to allocate memory required for
- * automatic saving of firmware trace. Driver should call
- * bfa_ioc_debug_memclaim() right after bfa_ioc_attach() to setup this
- * trace memory.
- */
-int
-bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover)
-{
- return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
-}
/*
* Initialize memory for saving firmware trace. Driver must initialize
bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave)
{
ioc->dbg_fwsave = dbg_fwsave;
- ioc->dbg_fwsave_len = bfa_ioc_debug_trcsz(ioc->iocpf.auto_recover);
-}
-
-u32
-bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr)
-{
- return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
-}
-
-u32
-bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr)
-{
- return PSS_SMEM_PGOFF(fmaddr);
+ ioc->dbg_fwsave_len = (ioc->iocpf.auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
}
/*
return BFA_TRUE;
}
-/*
- * Add to IOC heartbeat failure notification queue. To be used by common
- * modules such as cee, port, diag.
+/**
+ * Reset IOC fwstate registers.
*/
void
-bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
- struct bfa_ioc_hbfail_notify_s *notify)
+bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc)
{
- list_add_tail(¬ify->qe, &ioc->hb_notify_q);
+ writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
+ writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate);
}
#define BFA_MFG_NAME "Brocade"
else
ad_attr->prototype = 0;
- ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
+ ad_attr->pwwn = ioc->attr->pwwn;
ad_attr->mac = bfa_ioc_get_mac(ioc);
ad_attr->pcie_gen = ioc_attr->pcie_gen;
bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver);
ad_attr->cna_capable = ioc->cna;
- ad_attr->trunk_capable = (ad_attr->nports > 1) && !ioc->cna;
+ ad_attr->trunk_capable = (ad_attr->nports > 1) && !ioc->cna &&
+ !ad_attr->is_mezz;
}
enum bfa_ioc_type_e
bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);
}
-/*
- * hal_wwn_public
- */
-wwn_t
-bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc)
-{
- return ioc->attr->pwwn;
-}
-
-wwn_t
-bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc)
-{
- return ioc->attr->nwwn;
-}
-
-u64
-bfa_ioc_get_adid(struct bfa_ioc_s *ioc)
-{
- return ioc->attr->mfg_pwwn;
-}
-
mac_t
bfa_ioc_get_mac(struct bfa_ioc_s *ioc)
{
return ioc->attr->mac;
}
-wwn_t
-bfa_ioc_get_mfg_pwwn(struct bfa_ioc_s *ioc)
-{
- return ioc->attr->mfg_pwwn;
-}
-
-wwn_t
-bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc)
-{
- return ioc->attr->mfg_nwwn;
-}
-
mac_t
bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc)
{
return BFA_STATUS_OK;
}
-/*
- * Clear saved firmware trace
- */
-void
-bfa_ioc_debug_fwsave_clear(struct bfa_ioc_s *ioc)
-{
- ioc->dbg_fwsave_once = BFA_TRUE;
-}
/*
* Retrieve saved firmware trace from a prior IOC failure.
* Save firmware trace if configured.
*/
static void
-bfa_ioc_debug_save(struct bfa_ioc_s *ioc)
+bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc)
{
int tlen;
- if (ioc->dbg_fwsave_len) {
- tlen = ioc->dbg_fwsave_len;
- bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
+ if (ioc->dbg_fwsave_once) {
+ ioc->dbg_fwsave_once = BFA_FALSE;
+ if (ioc->dbg_fwsave_len) {
+ tlen = ioc->dbg_fwsave_len;
+ bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
+ }
}
}
static void
bfa_ioc_recover(struct bfa_ioc_s *ioc)
{
- if (ioc->dbg_fwsave_once) {
- ioc->dbg_fwsave_once = BFA_FALSE;
- bfa_ioc_debug_save(ioc);
- }
-
bfa_ioc_stats(ioc, ioc_hbfails);
bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
}
}
/*
- * hal_iocpf_pvt BFA IOC PF private functions
+ * BFA IOC PF private functions
*/
-
-static void
-bfa_iocpf_enable(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_ENABLE);
-}
-
-static void
-bfa_iocpf_disable(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE);
-}
-
-static void
-bfa_iocpf_fail(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);
-}
-
-static void
-bfa_iocpf_initfail(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
-}
-
-static void
-bfa_iocpf_getattrfail(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL);
-}
-
-static void
-bfa_iocpf_stop(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
-}
-
static void
bfa_iocpf_timeout(void *ioc_arg)
{
/*
* bfa timer function
*/
-void
-bfa_timer_init(struct bfa_timer_mod_s *mod)
-{
- INIT_LIST_HEAD(&mod->timer_q);
-}
-
void
bfa_timer_beat(struct bfa_timer_mod_s *mod)
{
#ifndef __BFA_IOC_H__
#define __BFA_IOC_H__
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#include "bfa_cs.h"
#include "bfi.h"
+#define BFA_DBG_FWTRC_ENTS (BFI_IOC_TRC_ENTS)
+#define BFA_DBG_FWTRC_LEN \
+ (BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc_s) + \
+ (sizeof(struct bfa_trc_mod_s) - \
+ BFA_TRC_MAX * sizeof(struct bfa_trc_s)))
/*
* BFA timer declarations
*/
#define BFA_TIMER_FREQ 200 /* specified in millisecs */
void bfa_timer_beat(struct bfa_timer_mod_s *mod);
-void bfa_timer_init(struct bfa_timer_mod_s *mod);
void bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
bfa_timer_cbfn_t timercb, void *arg,
unsigned int timeout);
#define bfa_swap_words(_x) ( \
((_x) << 32) | ((_x) >> 32))
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
#define bfa_sge_to_be(_x)
#define bfa_sge_to_le(_x) bfa_sge_word_swap(_x)
#define bfa_sgaddr_le(_x) bfa_swap_words(_x)
static inline void
__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa)
{
- dma_addr->a32.addr_lo = (u32) pa;
- dma_addr->a32.addr_hi = (u32) (bfa_os_u32(pa));
+ dma_addr->a32.addr_lo = (__be32) pa;
+ dma_addr->a32.addr_hi = (__be32) (pa >> 32);
}
static inline void
__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa)
{
- dma_addr->a32.addr_lo = (u32) cpu_to_be32(pa);
- dma_addr->a32.addr_hi = (u32) cpu_to_be32(bfa_os_u32(pa));
+ dma_addr->a32.addr_lo = cpu_to_be32(pa);
+ dma_addr->a32.addr_hi = cpu_to_be32(pa >> 32);
}
struct bfa_ioc_regs_s {
void __iomem *host_page_num_fn;
void __iomem *heartbeat;
void __iomem *ioc_fwstate;
+ void __iomem *alt_ioc_fwstate;
void __iomem *ll_halt;
+ void __iomem *alt_ll_halt;
void __iomem *err_set;
+ void __iomem *ioc_fail_sync;
void __iomem *shirq_isr_next;
void __iomem *shirq_msk_next;
void __iomem *smem_page_start;
void (*ioc_map_port) (struct bfa_ioc_s *ioc);
void (*ioc_isr_mode_set) (struct bfa_ioc_s *ioc,
bfa_boolean_t msix);
- void (*ioc_notify_hbfail) (struct bfa_ioc_s *ioc);
+ void (*ioc_notify_fail) (struct bfa_ioc_s *ioc);
void (*ioc_ownership_reset) (struct bfa_ioc_s *ioc);
+ void (*ioc_sync_join) (struct bfa_ioc_s *ioc);
+ void (*ioc_sync_leave) (struct bfa_ioc_s *ioc);
+ void (*ioc_sync_ack) (struct bfa_ioc_s *ioc);
+ bfa_boolean_t (*ioc_sync_complete) (struct bfa_ioc_s *ioc);
};
#define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func)
#define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS)
#define BFA_IOC_FLASH_CHUNK_ADDR(chunkno) (chunkno * BFI_FLASH_CHUNK_SZ_WORDS)
+#ifdef BFA_IOC_IS_UEFI
+#define bfa_ioc_is_bios_optrom(__ioc) (0)
+#define bfa_ioc_is_uefi(__ioc) BFA_IOC_IS_UEFI
+#else
+#define bfa_ioc_is_bios_optrom(__ioc) \
+ (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(__ioc)) < BFA_IOC_FWIMG_MINSZ)
+#define bfa_ioc_is_uefi(__ioc) (0)
+#endif
+
/*
* IOC mailbox interface
*/
void bfa_ioc_detach(struct bfa_ioc_s *ioc);
void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
enum bfi_mclass mc);
-u32 bfa_ioc_meminfo(void);
void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa);
void bfa_ioc_enable(struct bfa_ioc_s *ioc);
void bfa_ioc_disable(struct bfa_ioc_s *ioc);
bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc);
bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc);
bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc);
+void bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc);
enum bfa_ioc_type_e bfa_ioc_get_type(struct bfa_ioc_s *ioc);
void bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num);
void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc_s *ioc, char *fw_ver);
void bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr);
void bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
struct bfa_adapter_attr_s *ad_attr);
-int bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover);
void bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave);
bfa_status_t bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata,
int *trclen);
-void bfa_ioc_debug_fwsave_clear(struct bfa_ioc_s *ioc);
bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata,
int *trclen);
bfa_status_t bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf,
u32 *offset, int *buflen);
-u32 bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr);
-u32 bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr);
void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc);
bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc);
-void bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
- struct bfa_ioc_hbfail_notify_s *notify);
bfa_boolean_t bfa_ioc_sem_get(void __iomem *sem_reg);
-void bfa_ioc_sem_release(void __iomem *sem_reg);
-void bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc);
void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc,
struct bfi_ioc_image_hdr_s *fwhdr);
bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc,
/*
* bfa mfg wwn API functions
*/
-wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc);
-wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc);
mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc);
-wwn_t bfa_ioc_get_mfg_pwwn(struct bfa_ioc_s *ioc);
-wwn_t bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc);
mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc);
-u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc);
/*
* F/W Image Size & Chunk
return bfi_image_ct_cna_get_chunk(off); break;
case BFI_IMAGE_CB_FC:
return bfi_image_cb_fc_get_chunk(off); break;
- default: return 0;
+ default: return NULL;
}
}
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_ioc.h"
#include "bfi_cbreg.h"
#include "bfa_defs.h"
static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
-static void bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc);
+static bfa_boolean_t bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc);
-struct bfa_ioc_hwif_s hwif_cb;
+static struct bfa_ioc_hwif_s hwif_cb;
/*
* Called from bfa_ioc_attach() to map asic specific calls.
hwif_cb.ioc_reg_init = bfa_ioc_cb_reg_init;
hwif_cb.ioc_map_port = bfa_ioc_cb_map_port;
hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set;
- hwif_cb.ioc_notify_hbfail = bfa_ioc_cb_notify_hbfail;
+ hwif_cb.ioc_notify_fail = bfa_ioc_cb_notify_fail;
hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset;
+ hwif_cb.ioc_sync_join = bfa_ioc_cb_sync_join;
+ hwif_cb.ioc_sync_leave = bfa_ioc_cb_sync_leave;
+ hwif_cb.ioc_sync_ack = bfa_ioc_cb_sync_ack;
+ hwif_cb.ioc_sync_complete = bfa_ioc_cb_sync_complete;
ioc->ioc_hwif = &hwif_cb;
}
-/*
+/**
* Return true if firmware of current driver matches the running firmware.
*/
static bfa_boolean_t
bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc)
{
+ struct bfi_ioc_image_hdr_s fwhdr;
+ uint32_t fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+
+ if ((fwstate == BFI_IOC_UNINIT) || bfa_ioc_is_uefi(ioc) ||
+ bfa_ioc_is_bios_optrom(ioc))
+ return BFA_TRUE;
+
+ bfa_ioc_fwver_get(ioc, &fwhdr);
+
+ if (swab32(fwhdr.exec) == BFI_BOOT_TYPE_NORMAL)
+ return BFA_TRUE;
+
+ bfa_trc(ioc, fwstate);
+ bfa_trc(ioc, fwhdr.exec);
+ writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
+
return BFA_TRUE;
}
* Notify other functions on HB failure.
*/
static void
-bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc)
+bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc)
{
writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
readl(ioc->ioc_regs.err_set);
if (ioc->port_id == 0) {
ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG;
} else {
ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+ ioc->ioc_regs.alt_ioc_fwstate = (rb + BFA_IOC0_STATE_REG);
}
/*
* will lock it instead of clearing it.
*/
readl(ioc->ioc_regs.ioc_sem_reg);
- bfa_ioc_hw_sem_release(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
}
+/**
+ * Synchronized IOC failure processing routines
+ */
+static void
+bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc)
+{
+}
+static void
+bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc)
+{
+}
+
+static void
+bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc)
+{
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+}
+
+static bfa_boolean_t
+bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc)
+{
+ uint32_t fwstate, alt_fwstate;
+ fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+
+ /**
+ * At this point, this IOC is hoding the hw sem in the
+ * start path (fwcheck) OR in the disable/enable path
+ * OR to check if the other IOC has acknowledged failure.
+ *
+ * So, this IOC can be in UNINIT, INITING, DISABLED, FAIL
+ * or in MEMTEST states. In a normal scenario, this IOC
+ * can not be in OP state when this function is called.
+ *
+ * However, this IOC could still be in OP state when
+ * the OS driver is starting up, if the OptROM code has
+ * left it in that state.
+ *
+ * If we had marked this IOC's fwstate as BFI_IOC_FAIL
+ * in the failure case and now, if the fwstate is not
+ * BFI_IOC_FAIL it implies that the other PCI fn have
+ * reinitialized the ASIC or this IOC got disabled, so
+ * return TRUE.
+ */
+ if (fwstate == BFI_IOC_UNINIT ||
+ fwstate == BFI_IOC_INITING ||
+ fwstate == BFI_IOC_DISABLED ||
+ fwstate == BFI_IOC_MEMTEST ||
+ fwstate == BFI_IOC_OP)
+ return BFA_TRUE;
+ else {
+ alt_fwstate = readl(ioc->ioc_regs.alt_ioc_fwstate);
+ if (alt_fwstate == BFI_IOC_FAIL ||
+ alt_fwstate == BFI_IOC_DISABLED ||
+ alt_fwstate == BFI_IOC_UNINIT ||
+ alt_fwstate == BFI_IOC_INITING ||
+ alt_fwstate == BFI_IOC_MEMTEST)
+ return BFA_TRUE;
+ else
+ return BFA_FALSE;
+ }
+}
bfa_status_t
bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode)
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_ioc.h"
#include "bfi_ctreg.h"
#include "bfa_defs.h"
BFA_TRC_FILE(CNA, IOC_CT);
+#define bfa_ioc_ct_sync_pos(__ioc) \
+ ((uint32_t) (1 << bfa_ioc_pcifn(__ioc)))
+#define BFA_IOC_SYNC_REQD_SH 16
+#define bfa_ioc_ct_get_sync_ackd(__val) (__val & 0x0000ffff)
+#define bfa_ioc_ct_clear_sync_ackd(__val) (__val & 0xffff0000)
+#define bfa_ioc_ct_get_sync_reqd(__val) (__val >> BFA_IOC_SYNC_REQD_SH)
+#define bfa_ioc_ct_sync_reqd_pos(__ioc) \
+ (bfa_ioc_ct_sync_pos(__ioc) << BFA_IOC_SYNC_REQD_SH)
+
/*
* forward declarations
*/
static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
-static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_sync_join(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc);
+static bfa_boolean_t bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc);
-struct bfa_ioc_hwif_s hwif_ct;
+static struct bfa_ioc_hwif_s hwif_ct;
/*
* Called from bfa_ioc_attach() to map asic specific calls.
hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init;
hwif_ct.ioc_map_port = bfa_ioc_ct_map_port;
hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
- hwif_ct.ioc_notify_hbfail = bfa_ioc_ct_notify_hbfail;
+ hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail;
hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
+ hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join;
+ hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave;
+ hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack;
+ hwif_ct.ioc_sync_complete = bfa_ioc_ct_sync_complete;
ioc->ioc_hwif = &hwif_ct;
}
*/
if (usecnt == 0) {
writel(1, ioc->ioc_regs.ioc_usage_reg);
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(0, ioc->ioc_regs.ioc_fail_sync);
bfa_trc(ioc, usecnt);
return BFA_TRUE;
}
*/
bfa_ioc_fwver_get(ioc, &fwhdr);
if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) {
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
bfa_trc(ioc, usecnt);
return BFA_FALSE;
}
*/
usecnt++;
writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
bfa_trc(ioc, usecnt);
return BFA_TRUE;
}
writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
bfa_trc(ioc, usecnt);
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
}
/*
* Notify other functions on HB failure.
*/
static void
-bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc)
+bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc)
{
if (ioc->cna) {
writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt);
+ writel(__FW_INIT_HALT_P, ioc->ioc_regs.alt_ll_halt);
/* Wait for halt to take effect */
readl(ioc->ioc_regs.ll_halt);
+ readl(ioc->ioc_regs.alt_ll_halt);
} else {
writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
readl(ioc->ioc_regs.err_set);
if (ioc->port_id == 0) {
ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG;
ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+ ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1;
} else {
ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+ ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC0_STATE_REG;
ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+ ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0;
}
/*
ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
+ ioc->ioc_regs.ioc_fail_sync = (rb + BFA_IOC_FAIL_SYNC);
/*
* sram memory access
if (ioc->cna) {
bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
writel(0, ioc->ioc_regs.ioc_usage_reg);
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
}
/*
* will lock it instead of clearing it.
*/
readl(ioc->ioc_regs.ioc_sem_reg);
- bfa_ioc_hw_sem_release(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
}
+/**
+ * Synchronized IOC failure processing routines
+ */
+static void
+bfa_ioc_ct_sync_join(struct bfa_ioc_s *ioc)
+{
+ uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ uint32_t sync_pos = bfa_ioc_ct_sync_reqd_pos(ioc);
+
+ writel((r32 | sync_pos), ioc->ioc_regs.ioc_fail_sync);
+}
+static void
+bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc)
+{
+ uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ uint32_t sync_msk = bfa_ioc_ct_sync_reqd_pos(ioc) |
+ bfa_ioc_ct_sync_pos(ioc);
+
+ writel((r32 & ~sync_msk), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static void
+bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc)
+{
+ uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+
+ writel((r32 | bfa_ioc_ct_sync_pos(ioc)),
+ ioc->ioc_regs.ioc_fail_sync);
+}
+
+static bfa_boolean_t
+bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc)
+{
+ uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ uint32_t sync_reqd = bfa_ioc_ct_get_sync_reqd(r32);
+ uint32_t sync_ackd = bfa_ioc_ct_get_sync_ackd(r32);
+ uint32_t tmp_ackd;
+
+ if (sync_ackd == 0)
+ return BFA_TRUE;
+
+ /**
+ * The check below is to see whether any other PCI fn
+ * has reinitialized the ASIC (reset sync_ackd bits)
+ * and failed again while this IOC was waiting for hw
+ * semaphore (in bfa_iocpf_sm_semwait()).
+ */
+ tmp_ackd = sync_ackd;
+ if ((sync_reqd & bfa_ioc_ct_sync_pos(ioc)) &&
+ !(sync_ackd & bfa_ioc_ct_sync_pos(ioc)))
+ sync_ackd |= bfa_ioc_ct_sync_pos(ioc);
+
+ if (sync_reqd == sync_ackd) {
+ writel(bfa_ioc_ct_clear_sync_ackd(r32),
+ ioc->ioc_regs.ioc_fail_sync);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.alt_ioc_fwstate);
+ return BFA_TRUE;
+ }
+
+ /**
+ * If another PCI fn reinitialized and failed again while
+ * this IOC was waiting for hw sem, the sync_ackd bit for
+ * this IOC need to be set again to allow reinitialization.
+ */
+ if (tmp_ackd != sync_ackd)
+ writel((r32 | sync_ackd), ioc->ioc_regs.ioc_fail_sync);
+
+ return BFA_FALSE;
+}
/*
* Check the firmware state to know if pll_init has been completed already
void (*iocdisable) (struct bfa_s *bfa);
};
-extern struct bfa_module_s *hal_mods[];
struct bfa_s {
void *bfad; /* BFA driver instance */
struct bfa_msix_s msix;
};
-extern bfa_isr_func_t bfa_isrs[BFI_MC_MAX];
-extern bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[];
extern bfa_boolean_t bfa_auto_recover;
extern struct bfa_module_s hal_mod_sgpg;
extern struct bfa_module_s hal_mod_fcport;
+++ /dev/null
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#ifndef __BFA_OS_INC_H__
-#define __BFA_OS_INC_H__
-
-#include <linux/types.h>
-#include <linux/version.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/idr.h>
-#include <linux/interrupt.h>
-#include <linux/cdev.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/vmalloc.h>
-#include <linux/workqueue.h>
-#include <linux/bitops.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/scsi_transport_fc.h>
-#include <scsi/scsi_transport.h>
-
-#ifdef __BIG_ENDIAN
-#define __BIGENDIAN
-#endif
-
-static inline u64 bfa_os_get_log_time(void)
-{
- u64 system_time = 0;
- struct timeval tv;
- do_gettimeofday(&tv);
-
- /* We are interested in seconds only. */
- system_time = tv.tv_sec;
- return system_time;
-}
-
-#define bfa_io_lat_clock_res_div HZ
-#define bfa_io_lat_clock_res_mul 1000
-
-#define BFA_LOG(level, bfad, mask, fmt, arg...) \
-do { \
- if (((mask) == 4) || (level[1] <= '4')) \
- dev_printk(level, &((bfad)->pcidev)->dev, fmt, ##arg); \
-} while (0)
-
-#define bfa_swap_3b(_x) \
- ((((_x) & 0xff) << 16) | \
- ((_x) & 0x00ff00) | \
- (((_x) & 0xff0000) >> 16))
-
-#define bfa_os_swap_sgaddr(_x) ((u64)( \
- (((u64)(_x) & (u64)0x00000000000000ffull) << 32) | \
- (((u64)(_x) & (u64)0x000000000000ff00ull) << 32) | \
- (((u64)(_x) & (u64)0x0000000000ff0000ull) << 32) | \
- (((u64)(_x) & (u64)0x00000000ff000000ull) << 32) | \
- (((u64)(_x) & (u64)0x000000ff00000000ull) >> 32) | \
- (((u64)(_x) & (u64)0x0000ff0000000000ull) >> 32) | \
- (((u64)(_x) & (u64)0x00ff000000000000ull) >> 32) | \
- (((u64)(_x) & (u64)0xff00000000000000ull) >> 32)))
-
-#ifndef __BIGENDIAN
-#define bfa_os_hton3b(_x) bfa_swap_3b(_x)
-#define bfa_os_sgaddr(_x) (_x)
-#else
-#define bfa_os_hton3b(_x) (_x)
-#define bfa_os_sgaddr(_x) bfa_os_swap_sgaddr(_x)
-#endif
-
-#define bfa_os_ntoh3b(_x) bfa_os_hton3b(_x)
-#define bfa_os_u32(__pa64) ((__pa64) >> 32)
-
-#define BFA_TRC_TS(_trcm) \
- ({ \
- struct timeval tv; \
- \
- do_gettimeofday(&tv); \
- (tv.tv_sec*1000000+tv.tv_usec); \
- })
-
-#define boolean_t int
-
-/*
- * For current time stamp, OS API will fill-in
- */
-struct bfa_timeval_s {
- u32 tv_sec; /* seconds */
- u32 tv_usec; /* microseconds */
-};
-
-static inline void
-bfa_os_gettimeofday(struct bfa_timeval_s *tv)
-{
- struct timeval tmp_tv;
-
- do_gettimeofday(&tmp_tv);
- tv->tv_sec = (u32) tmp_tv.tv_sec;
- tv->tv_usec = (u32) tmp_tv.tv_usec;
-}
-
-static inline void
-wwn2str(char *wwn_str, u64 wwn)
-{
- union {
- u64 wwn;
- u8 byte[8];
- } w;
-
- w.wwn = wwn;
- sprintf(wwn_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", w.byte[0],
- w.byte[1], w.byte[2], w.byte[3], w.byte[4], w.byte[5],
- w.byte[6], w.byte[7]);
-}
-
-static inline void
-fcid2str(char *fcid_str, u32 fcid)
-{
- union {
- u32 fcid;
- u8 byte[4];
- } f;
-
- f.fcid = fcid;
- sprintf(fcid_str, "%02x:%02x:%02x", f.byte[1], f.byte[2], f.byte[3]);
-}
-
-#endif /* __BFA_OS_INC_H__ */
void bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
enum bfa_plog_eid event, u16 misc,
struct fchs_s *fchdr, u32 pld_w0);
-void bfa_plog_clear(struct bfa_plog_s *plog);
-void bfa_plog_enable(struct bfa_plog_s *plog);
-void bfa_plog_disable(struct bfa_plog_s *plog);
-bfa_boolean_t bfa_plog_get_setting(struct bfa_plog_s *plog);
#endif /* __BFA_PORTLOG_H__ */
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_defs_svc.h"
#include "bfa_port.h"
#include "bfi.h"
bfa_port_stats_swap(struct bfa_port_s *port, union bfa_port_stats_u *stats)
{
u32 *dip = (u32 *) stats;
- u32 t0, t1;
+ __be32 t0, t1;
int i;
for (i = 0; i < sizeof(union bfa_port_stats_u)/sizeof(u32);
i += 2) {
t0 = dip[i];
t1 = dip[i + 1];
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
dip[i] = be32_to_cpu(t0);
dip[i + 1] = be32_to_cpu(t1);
#else
port->stats_busy = BFA_FALSE;
if (status == BFA_STATUS_OK) {
- struct bfa_timeval_s tv;
+ struct timeval tv;
memcpy(port->stats, port->stats_dma.kva,
sizeof(union bfa_port_stats_u));
bfa_port_stats_swap(port, port->stats);
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
port->stats->fc.secs_reset = tv.tv_sec - port->stats_reset_time;
}
static void
bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status)
{
- struct bfa_timeval_s tv;
+ struct timeval tv;
port->stats_status = status;
port->stats_busy = BFA_FALSE;
/*
* re-initialize time stamp for stats reset
*/
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
port->stats_reset_time = tv.tv_sec;
if (port->stats_cbfn) {
bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
void *dev, struct bfa_trc_mod_s *trcmod)
{
- struct bfa_timeval_s tv;
+ struct timeval tv;
bfa_assert(port);
bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port);
bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port);
- bfa_ioc_hbfail_register(port->ioc, &port->hbfail);
+ list_add_tail(&port->hbfail.qe, &port->ioc->hb_notify_q);
/*
* initialize time stamp for stats reset
*/
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
port->stats_reset_time = tv.tv_sec;
bfa_trc(port, 0);
}
-
-/*
- * bfa_port_detach()
- *
- *
- * @param[in] port - Pointer to the Port module data structure
- *
- * @return void
- */
-void
-bfa_port_detach(struct bfa_port_s *port)
-{
- bfa_trc(port, 0);
-}
void bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
void *dev, struct bfa_trc_mod_s *trcmod);
-void bfa_port_detach(struct bfa_port_s *port);
void bfa_port_hbfail(void *arg);
bfa_status_t bfa_port_get_stats(struct bfa_port_s *port,
* General Public License for more details.
*/
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#include "bfa_plog.h"
#include "bfa_cs.h"
#include "bfa_modules.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(HAL, FCXP);
BFA_MODULE(fcxp);
#define BFA_LPS_MAX_VPORTS_SUPP_CB 255
#define BFA_LPS_MAX_VPORTS_SUPP_CT 190
-/*
- * lps_pvt BFA LPS private functions
- */
-
-enum bfa_lps_event {
- BFA_LPS_SM_LOGIN = 1, /* login request from user */
- BFA_LPS_SM_LOGOUT = 2, /* logout request from user */
- BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */
- BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */
- BFA_LPS_SM_DELETE = 5, /* lps delete from user */
- BFA_LPS_SM_OFFLINE = 6, /* Link is offline */
- BFA_LPS_SM_RX_CVL = 7, /* Rx clear virtual link */
-};
/*
* FC PORT related definitions
((bfa_fcport_is_disabled(bfa) == BFA_TRUE) || \
(bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE))
-
/*
* BFA port state machine events
*/
} \
} while (0)
-
-enum bfa_rport_event {
- BFA_RPORT_SM_CREATE = 1, /* rport create event */
- BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */
- BFA_RPORT_SM_ONLINE = 3, /* rport is online */
- BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */
- BFA_RPORT_SM_FWRSP = 5, /* firmware response */
- BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */
- BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */
- BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */
- BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */
-};
-
/*
* forward declarations FCXP related functions
*/
static void bfa_lps_free(struct bfa_lps_s *lps);
static void bfa_lps_send_login(struct bfa_lps_s *lps);
static void bfa_lps_send_logout(struct bfa_lps_s *lps);
+static void bfa_lps_send_set_n2n_pid(struct bfa_lps_s *lps);
static void bfa_lps_login_comp(struct bfa_lps_s *lps);
static void bfa_lps_logout_comp(struct bfa_lps_s *lps);
static void bfa_lps_cvl_event(struct bfa_lps_s *lps);
static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event
event);
static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event);
+static void bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps,
+ enum bfa_lps_event event);
static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event);
static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event
event);
return 0;
}
+static u64
+bfa_get_log_time(void)
+{
+ u64 system_time = 0;
+ struct timeval tv;
+ do_gettimeofday(&tv);
+
+ /* We are interested in seconds only. */
+ system_time = tv.tv_sec;
+ return system_time;
+}
+
static void
bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
{
memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s));
- pl_recp->tv = bfa_os_get_log_time();
+ pl_recp->tv = bfa_get_log_time();
BFA_PL_LOG_REC_INCR(plog->tail);
if (plog->head == plog->tail)
}
}
-void
-bfa_plog_clear(struct bfa_plog_s *plog)
-{
- plog->head = plog->tail = 0;
-}
-
-void
-bfa_plog_enable(struct bfa_plog_s *plog)
-{
- plog->plog_enabled = 1;
-}
-
-void
-bfa_plog_disable(struct bfa_plog_s *plog)
-{
- plog->plog_enabled = 0;
-}
-
-bfa_boolean_t
-bfa_plog_get_setting(struct bfa_plog_s *plog)
-{
- return (bfa_boolean_t)plog->plog_enabled;
-}
/*
* fcxp_pvt BFA FCXP private functions
bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP));
}
-/*
- * hal_fcxp_api BFA FCXP API
- */
-
/*
* Allocate an FCXP instance to send a response or to send a request
* that has a response. Request/response buffers are allocated by caller.
}
/*
- * Free the BFA FCXP
+ * Free the BFA FCXP
*
* @param[in] fcxp BFA fcxp pointer
*
fcxp->send_cbfn = bfa_fcxp_null_comp;
}
-
-
-/*
- * hal_fcxp_public BFA FCXP public functions
- */
-
void
bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
{
else
bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
BFA_PL_EID_LOGIN, 0, "FLOGI Accept");
+ /* If N2N, send the assigned PID to FW */
+ bfa_trc(lps->bfa, lps->fport);
+ bfa_trc(lps->bfa, lps->lp_pid);
+
+ if (!lps->fport && lps->lp_pid)
+ bfa_sm_send_event(lps, BFA_LPS_SM_SET_N2N_PID);
} else {
bfa_sm_set_state(lps, bfa_lps_sm_init);
if (lps->fdisc)
bfa_sm_set_state(lps, bfa_lps_sm_init);
break;
+ case BFA_LPS_SM_SET_N2N_PID:
+ bfa_trc(lps->bfa, lps->fport);
+ bfa_trc(lps->bfa, lps->lp_pid);
+ break;
+
default:
bfa_sm_fault(lps->bfa, event);
}
BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx");
break;
+ case BFA_LPS_SM_SET_N2N_PID:
+ if (bfa_reqq_full(lps->bfa, lps->reqq)) {
+ bfa_sm_set_state(lps, bfa_lps_sm_online_n2n_pid_wait);
+ bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
+ } else
+ bfa_lps_send_set_n2n_pid(lps);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ case BFA_LPS_SM_DELETE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ break;
+
+ default:
+ bfa_sm_fault(lps->bfa, event);
+ }
+}
+
+/**
+ * login complete
+ */
+static void
+bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_RESUME:
+ bfa_sm_set_state(lps, bfa_lps_sm_online);
+ bfa_lps_send_set_n2n_pid(lps);
+ break;
+
+ case BFA_LPS_SM_LOGOUT:
+ bfa_sm_set_state(lps, bfa_lps_sm_logowait);
+ bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+ BFA_PL_EID_LOGO, 0, "Logout");
+ break;
+
+ case BFA_LPS_SM_RX_CVL:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_reqq_wcancel(&lps->wqe);
+
+ /* Let the vport module know about this event */
+ bfa_lps_cvl_event(lps);
+ bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+ BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx");
+ break;
+
case BFA_LPS_SM_OFFLINE:
case BFA_LPS_SM_DELETE:
bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_reqq_wcancel(&lps->wqe);
break;
default:
switch (rsp->status) {
case BFA_STATUS_OK:
lps->fport = rsp->f_port;
+ if (lps->fport)
+ lps->lp_pid = rsp->lp_pid;
lps->npiv_en = rsp->npiv_en;
- lps->lp_pid = rsp->lp_pid;
lps->pr_bbcred = be16_to_cpu(rsp->bb_credit);
lps->pr_pwwn = rsp->port_name;
lps->pr_nwwn = rsp->node_name;
bfa_reqq_produce(lps->bfa, lps->reqq);
}
+/**
+ * send n2n pid set request to firmware
+ */
+static void
+bfa_lps_send_set_n2n_pid(struct bfa_lps_s *lps)
+{
+ struct bfi_lps_n2n_pid_req_s *m;
+
+ m = bfa_reqq_next(lps->bfa, lps->reqq);
+ bfa_assert(m);
+
+ bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_N2N_PID_REQ,
+ bfa_lpuid(lps->bfa));
+
+ m->lp_tag = lps->lp_tag;
+ m->lp_pid = lps->lp_pid;
+ bfa_reqq_produce(lps->bfa, lps->reqq);
+}
+
/*
* Indirect login completion handler for non-fcs
*/
bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
}
-/*
- * Initiate a lport logout (flogi).
- */
-void
-bfa_lps_flogo(struct bfa_lps_s *lps)
-{
- bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
-}
/*
* Initiate a lport FDSIC logout.
bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
}
-/*
- * Discard a pending login request -- should be called only for
- * link down handling.
- */
-void
-bfa_lps_discard(struct bfa_lps_s *lps)
-{
- bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
-}
-
-/*
- * Return lport services tag
- */
-u8
-bfa_lps_get_tag(struct bfa_lps_s *lps)
-{
- return lps->lp_tag;
-}
/*
* Return lport services tag given the pid
return 0;
}
-/*
- * return if fabric login indicates support for NPIV
- */
-bfa_boolean_t
-bfa_lps_is_npiv_en(struct bfa_lps_s *lps)
-{
- return lps->npiv_en;
-}
-
-/*
- * Return TRUE if attached to F-Port, else return FALSE
- */
-bfa_boolean_t
-bfa_lps_is_fport(struct bfa_lps_s *lps)
-{
- return lps->fport;
-}
-
-/*
- * Return TRUE if attached to a Brocade Fabric
- */
-bfa_boolean_t
-bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps)
-{
- return lps->brcd_switch;
-}
-/*
- * return TRUE if authentication is required
- */
-bfa_boolean_t
-bfa_lps_is_authreq(struct bfa_lps_s *lps)
-{
- return lps->auth_req;
-}
-
-bfa_eproto_status_t
-bfa_lps_get_extstatus(struct bfa_lps_s *lps)
-{
- return lps->ext_status;
-}
-
-/*
- * return port id assigned to the lport
- */
-u32
-bfa_lps_get_pid(struct bfa_lps_s *lps)
-{
- return lps->lp_pid;
-}
/*
* return port id assigned to the base lport
return BFA_LPS_FROM_TAG(mod, 0)->lp_pid;
}
-/*
- * Return bb_credit assigned in FLOGI response
- */
-u16
-bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps)
-{
- return lps->pr_bbcred;
-}
-
-/*
- * Return peer port name
- */
-wwn_t
-bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps)
-{
- return lps->pr_pwwn;
-}
-
-/*
- * Return peer node name
- */
-wwn_t
-bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps)
-{
- return lps->pr_nwwn;
-}
-
-/*
- * return reason code if login request is rejected
- */
-u8
-bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps)
-{
- return lps->lsrjt_rsn;
-}
-
-/*
- * return explanation code if login request is rejected
+/**
+ * Set PID in case of n2n (which is assigned during PLOGI)
*/
-u8
-bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps)
+void
+bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, uint32_t n2n_pid)
{
- return lps->lsrjt_expl;
-}
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, n2n_pid);
-/*
- * Return fpma/spma MAC for lport
- */
-mac_t
-bfa_lps_get_lp_mac(struct bfa_lps_s *lps)
-{
- return lps->lp_mac;
+ lps->lp_pid = n2n_pid;
+ bfa_sm_send_event(lps, BFA_LPS_SM_SET_N2N_PID);
}
/*
/*
* Start event after IOC is configured and BFA is started.
*/
+ fcport->use_flash_cfg = BFA_TRUE;
+
if (bfa_fcport_send_enable(fcport)) {
bfa_trc(fcport->bfa, BFA_TRUE);
bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE);
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port online: WWN = %s\n", pwwn_buf);
break;
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
wwn2str(pwwn_buf, fcport->pwwn);
if (BFA_PORT_IS_DISABLED(fcport->bfa))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
else
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Base port (WWN = %s) "
"lost fabric connectivity\n", pwwn_buf);
break;
bfa_fcport_reset_linkinfo(fcport);
wwn2str(pwwn_buf, fcport->pwwn);
if (BFA_PORT_IS_DISABLED(fcport->bfa))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
else
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Base port (WWN = %s) "
"lost fabric connectivity\n", pwwn_buf);
break;
bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE);
wwn2str(pwwn_buf, fcport->pwwn);
if (BFA_PORT_IS_DISABLED(fcport->bfa))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
else
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Base port (WWN = %s) "
"lost fabric connectivity\n", pwwn_buf);
break;
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port enabled: WWN = %s\n", pwwn_buf);
break;
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port enabled: WWN = %s\n", pwwn_buf);
break;
}
}
-
-
-/*
- * hal_port_private
- */
-
static void
__bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete)
{
struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
struct bfa_port_cfg_s *port_cfg = &fcport->cfg;
struct bfa_fcport_ln_s *ln = &fcport->ln;
- struct bfa_timeval_s tv;
+ struct timeval tv;
memset(fcport, 0, sizeof(struct bfa_fcport_s));
fcport->bfa = bfa;
/*
* initialize time stamp for stats reset
*/
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
fcport->stats_reset_time = tv.tv_sec;
/*
m->port_cfg = fcport->cfg;
m->msgtag = fcport->msgtag;
m->port_cfg.maxfrsize = cpu_to_be16(fcport->cfg.maxfrsize);
+ m->use_flash_cfg = fcport->use_flash_cfg;
bfa_dma_be_addr_set(m->stats_dma_addr, fcport->stats_pa);
bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_lo);
bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_hi);
static void
bfa_fcport_set_wwns(struct bfa_fcport_s *fcport)
{
- fcport->pwwn = bfa_ioc_get_pwwn(&fcport->bfa->ioc);
- fcport->nwwn = bfa_ioc_get_nwwn(&fcport->bfa->ioc);
+ fcport->pwwn = fcport->bfa->ioc.attr->pwwn;
+ fcport->nwwn = fcport->bfa->ioc.attr->nwwn;
bfa_trc(fcport->bfa, fcport->pwwn);
bfa_trc(fcport->bfa, fcport->nwwn);
struct bfa_qos_stats_s *s)
{
u32 *dip = (u32 *) d;
- u32 *sip = (u32 *) s;
+ __be32 *sip = (__be32 *) s;
int i;
/* Now swap the 32 bit fields */
struct bfa_fcoe_stats_s *s)
{
u32 *dip = (u32 *) d;
- u32 *sip = (u32 *) s;
+ __be32 *sip = (__be32 *) s;
int i;
for (i = 0; i < ((sizeof(struct bfa_fcoe_stats_s))/sizeof(u32));
i = i + 2) {
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
dip[i] = be32_to_cpu(sip[i]);
dip[i + 1] = be32_to_cpu(sip[i + 1]);
#else
if (complete) {
if (fcport->stats_status == BFA_STATUS_OK) {
- struct bfa_timeval_s tv;
+ struct timeval tv;
/* Swap FC QoS or FCoE stats */
if (bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
&fcport->stats_ret->fcoe,
&fcport->stats->fcoe);
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
fcport->stats_ret->fcoe.secs_reset =
tv.tv_sec - fcport->stats_reset_time;
}
struct bfa_fcport_s *fcport = cbarg;
if (complete) {
- struct bfa_timeval_s tv;
+ struct timeval tv;
/*
* re-initialize time stamp for stats reset
*/
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
fcport->stats_reset_time = tv.tv_sec;
fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
}
}
-
-
-/*
- * hal_port_public
- */
-
/*
* Called to initialize port attributes
*/
switch (msg->mhdr.msg_id) {
case BFI_FCPORT_I2H_ENABLE_RSP:
- if (fcport->msgtag == i2hmsg.penable_rsp->msgtag)
+ if (fcport->msgtag == i2hmsg.penable_rsp->msgtag) {
+
+ if (fcport->use_flash_cfg) {
+ fcport->cfg = i2hmsg.penable_rsp->port_cfg;
+ fcport->cfg.maxfrsize =
+ cpu_to_be16(fcport->cfg.maxfrsize);
+ fcport->cfg.path_tov =
+ cpu_to_be16(fcport->cfg.path_tov);
+ fcport->cfg.q_depth =
+ cpu_to_be16(fcport->cfg.q_depth);
+
+ if (fcport->cfg.trunked)
+ fcport->trunk.attr.state =
+ BFA_TRUNK_OFFLINE;
+ else
+ fcport->trunk.attr.state =
+ BFA_TRUNK_DISABLED;
+ fcport->use_flash_cfg = BFA_FALSE;
+ }
+
bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP);
+ }
break;
case BFI_FCPORT_I2H_DISABLE_RSP:
}
}
-
-
-/*
- * hal_port_api
- */
-
/*
* Registered callback for port events.
*/
attr->nwwn = fcport->nwwn;
attr->pwwn = fcport->pwwn;
- attr->factorypwwn = bfa_ioc_get_mfg_pwwn(&bfa->ioc);
- attr->factorynwwn = bfa_ioc_get_mfg_nwwn(&bfa->ioc);
+ attr->factorypwwn = bfa->ioc.attr->mfg_pwwn;
+ attr->factorynwwn = bfa->ioc.attr->mfg_nwwn;
memcpy(&attr->pport_cfg, &fcport->cfg,
sizeof(struct bfa_port_cfg_s));
/* beacon attributes */
attr->beacon = fcport->beacon;
attr->link_e2e_beacon = fcport->link_e2e_beacon;
- attr->plog_enabled = bfa_plog_get_setting(fcport->bfa->plog);
+ attr->plog_enabled = (bfa_boolean_t)fcport->bfa->plog->plog_enabled;
attr->io_profile = bfa_fcpim_get_io_profile(fcport->bfa);
attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa);
return BFA_STATUS_OK;
}
-/*
- * Fetch FCQoS port statistics
- */
-bfa_status_t
-bfa_fcport_get_qos_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
- bfa_cb_port_t cbfn, void *cbarg)
-{
- /* Meaningful only for FC mode */
- bfa_assert(bfa_ioc_get_fcmode(&bfa->ioc));
-
- return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg);
-}
-
-/*
- * Reset FCoE port statistics
- */
-bfa_status_t
-bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg)
-{
- /* Meaningful only for FC mode */
- bfa_assert(bfa_ioc_get_fcmode(&bfa->ioc));
-
- return bfa_fcport_clear_stats(bfa, cbfn, cbarg);
-}
-
-/*
- * Fetch FCQoS port statistics
- */
-bfa_status_t
-bfa_fcport_get_fcoe_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
- bfa_cb_port_t cbfn, void *cbarg)
-{
- /* Meaningful only for FCoE mode */
- bfa_assert(!bfa_ioc_get_fcmode(&bfa->ioc));
-
- return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg);
-}
-
-/*
- * Reset FCoE port statistics
- */
-bfa_status_t
-bfa_fcport_clear_fcoe_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg)
-{
- /* Meaningful only for FCoE mode */
- bfa_assert(!bfa_ioc_get_fcmode(&bfa->ioc));
-
- return bfa_fcport_clear_stats(bfa, cbfn, cbarg);
-}
-
-void
-bfa_fcport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- qos_attr->state = fcport->qos_attr.state;
- qos_attr->total_bb_cr = be32_to_cpu(fcport->qos_attr.total_bb_cr);
-}
-
-void
-bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa,
- struct bfa_qos_vc_attr_s *qos_vc_attr)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- struct bfa_qos_vc_attr_s *bfa_vc_attr = &fcport->qos_vc_attr;
- u32 i = 0;
-
- qos_vc_attr->total_vc_count = be16_to_cpu(bfa_vc_attr->total_vc_count);
- qos_vc_attr->shared_credit = be16_to_cpu(bfa_vc_attr->shared_credit);
- qos_vc_attr->elp_opmode_flags =
- be32_to_cpu(bfa_vc_attr->elp_opmode_flags);
-
- /* Individual VC info */
- while (i < qos_vc_attr->total_vc_count) {
- qos_vc_attr->vc_info[i].vc_credit =
- bfa_vc_attr->vc_info[i].vc_credit;
- qos_vc_attr->vc_info[i].borrow_credit =
- bfa_vc_attr->vc_info[i].borrow_credit;
- qos_vc_attr->vc_info[i].priority =
- bfa_vc_attr->vc_info[i].priority;
- ++i;
- }
-}
/*
* Fetch port attributes.
}
-void
-bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- enum bfa_ioc_type_e ioc_type = bfa_get_type(bfa);
-
- bfa_trc(bfa, on_off);
- bfa_trc(bfa, fcport->cfg.qos_enabled);
-
- bfa_trc(bfa, ioc_type);
-
- if (ioc_type == BFA_IOC_TYPE_FC) {
- fcport->cfg.qos_enabled = on_off;
- /*
- * Notify fcpim of the change in QoS state
- */
- bfa_fcpim_update_ioredirect(bfa);
- }
-}
-
-void
-bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- bfa_trc(bfa, on_off);
- bfa_trc(bfa, fcport->cfg.ratelimit);
-
- fcport->cfg.ratelimit = on_off;
- if (fcport->cfg.trl_def_speed == BFA_PORT_SPEED_UNKNOWN)
- fcport->cfg.trl_def_speed = BFA_PORT_SPEED_1GBPS;
-}
-
-/*
- * Configure default minimum ratelim speed
- */
-bfa_status_t
-bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_port_speed speed)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- bfa_trc(bfa, speed);
-
- /* Auto and speeds greater than the supported speed, are invalid */
- if ((speed == BFA_PORT_SPEED_AUTO) || (speed > fcport->speed_sup)) {
- bfa_trc(bfa, fcport->speed_sup);
- return BFA_STATUS_UNSUPP_SPEED;
- }
-
- fcport->cfg.trl_def_speed = speed;
-
- return BFA_STATUS_OK;
-}
-
/*
* Get default minimum ratelim speed
*/
return fcport->cfg.trl_def_speed;
}
-void
-bfa_fcport_busy(struct bfa_s *bfa, bfa_boolean_t status)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- bfa_trc(bfa, status);
- bfa_trc(bfa, fcport->diag_busy);
-
- fcport->diag_busy = status;
-}
-
-void
-bfa_fcport_beacon(void *dev, bfa_boolean_t beacon,
- bfa_boolean_t link_e2e_beacon)
-{
- struct bfa_s *bfa = dev;
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- bfa_trc(bfa, beacon);
- bfa_trc(bfa, link_e2e_beacon);
- bfa_trc(bfa, fcport->beacon);
- bfa_trc(bfa, fcport->link_e2e_beacon);
-
- fcport->beacon = beacon;
- fcport->link_e2e_beacon = link_e2e_beacon;
-}
bfa_boolean_t
bfa_fcport_is_linkup(struct bfa_s *bfa)
return fcport->cfg.qos_enabled;
}
-bfa_status_t
-bfa_trunk_get_attr(struct bfa_s *bfa, struct bfa_trunk_attr_s *attr)
-
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
-
- bfa_trc(bfa, fcport->cfg.trunked);
- bfa_trc(bfa, trunk->attr.state);
- *attr = trunk->attr;
- attr->port_id = bfa_lps_get_base_pid(bfa);
-
- return BFA_STATUS_OK;
-}
-
-void
-bfa_trunk_enable_cfg(struct bfa_s *bfa)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
-
- bfa_trc(bfa, 1);
- trunk->attr.state = BFA_TRUNK_OFFLINE;
- fcport->cfg.trunked = BFA_TRUE;
-}
-
-bfa_status_t
-bfa_trunk_enable(struct bfa_s *bfa)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
-
- bfa_trc(bfa, 1);
-
- trunk->attr.state = BFA_TRUNK_OFFLINE;
- bfa_fcport_disable(bfa);
- fcport->cfg.trunked = BFA_TRUE;
- bfa_fcport_enable(bfa);
-
- return BFA_STATUS_OK;
-}
-
-bfa_status_t
-bfa_trunk_disable(struct bfa_s *bfa)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
-
- bfa_trc(bfa, 0);
- trunk->attr.state = BFA_TRUNK_DISABLED;
- bfa_fcport_disable(bfa);
- fcport->cfg.trunked = BFA_FALSE;
- bfa_fcport_enable(bfa);
- return BFA_STATUS_OK;
-}
-
-
/*
* Rport State machine functions
*/
rp->bfa = bfa;
rp->rport_drv = rport_drv;
- bfa_rport_clear_stats(rp);
+ memset(&rp->stats, 0, sizeof(rp->stats));
bfa_assert(bfa_sm_cmp_state(rp, bfa_rport_sm_uninit));
bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE);
return rp;
}
-void
-bfa_rport_delete(struct bfa_rport_s *rport)
-{
- bfa_sm_send_event(rport, BFA_RPORT_SM_DELETE);
-}
-
void
bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info)
{
bfa_sm_send_event(rport, BFA_RPORT_SM_ONLINE);
}
-void
-bfa_rport_offline(struct bfa_rport_s *rport)
-{
- bfa_sm_send_event(rport, BFA_RPORT_SM_OFFLINE);
-}
-
void
bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed)
{
bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED);
}
-void
-bfa_rport_get_stats(struct bfa_rport_s *rport,
- struct bfa_rport_hal_stats_s *stats)
-{
- *stats = rport->stats;
-}
-
-void
-bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
- struct bfa_rport_qos_attr_s *qos_attr)
-{
- qos_attr->qos_priority = rport->qos_attr.qos_priority;
- qos_attr->qos_flow_id = be32_to_cpu(rport->qos_attr.qos_flow_id);
-
-}
-
-void
-bfa_rport_clear_stats(struct bfa_rport_s *rport)
-{
- memset(&rport->stats, 0, sizeof(rport->stats));
-}
-
/*
* SGPG related functions
{
}
-
-
-/*
- * hal_sgpg_public BFA SGPG public functions
- */
-
bfa_status_t
bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs)
{
bfa_uf_post_all(BFA_UF_MOD(bfa));
}
-
-
-/*
- * hal_uf_api
- */
-
/*
* Register handler for all unsolicted recieve frames.
*
/*
* RPORT related defines
*/
+enum bfa_rport_event {
+ BFA_RPORT_SM_CREATE = 1, /* rport create event */
+ BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */
+ BFA_RPORT_SM_ONLINE = 3, /* rport is online */
+ BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */
+ BFA_RPORT_SM_FWRSP = 5, /* firmware response */
+ BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */
+ BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */
+ BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */
+ BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */
+};
+
#define BFA_RPORT_MIN 4
struct bfa_rport_mod_s {
u8 myalpa; /* my ALPA in LOOP topology */
u8 rsvd[3];
struct bfa_port_cfg_s cfg; /* current port configuration */
+ bfa_boolean_t use_flash_cfg; /* get port cfg from flash */
struct bfa_qos_attr_s qos_attr; /* QoS Attributes */
struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */
struct bfa_reqq_wait_s reqq_wait;
void (*event_cbfn) (void *cbarg,
enum bfa_port_linkstate event), void *event_cbarg);
bfa_boolean_t bfa_fcport_is_disabled(struct bfa_s *bfa);
-void bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off);
-void bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off);
-bfa_status_t bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa,
- enum bfa_port_speed speed);
enum bfa_port_speed bfa_fcport_get_ratelim_speed(struct bfa_s *bfa);
void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit);
-void bfa_fcport_busy(struct bfa_s *bfa, bfa_boolean_t status);
-void bfa_fcport_beacon(void *dev, bfa_boolean_t beacon,
- bfa_boolean_t link_e2e_beacon);
-void bfa_fcport_qos_get_attr(struct bfa_s *bfa,
- struct bfa_qos_attr_s *qos_attr);
-void bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa,
- struct bfa_qos_vc_attr_s *qos_vc_attr);
-bfa_status_t bfa_fcport_get_qos_stats(struct bfa_s *bfa,
- union bfa_fcport_stats_u *stats,
- bfa_cb_port_t cbfn, void *cbarg);
-bfa_status_t bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn,
- void *cbarg);
-bfa_status_t bfa_fcport_get_fcoe_stats(struct bfa_s *bfa,
- union bfa_fcport_stats_u *stats,
- bfa_cb_port_t cbfn, void *cbarg);
-bfa_status_t bfa_fcport_clear_fcoe_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn,
- void *cbarg);
bfa_boolean_t bfa_fcport_is_ratelim(struct bfa_s *bfa);
bfa_boolean_t bfa_fcport_is_linkup(struct bfa_s *bfa);
bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa,
* bfa rport API functions
*/
struct bfa_rport_s *bfa_rport_create(struct bfa_s *bfa, void *rport_drv);
-void bfa_rport_delete(struct bfa_rport_s *rport);
void bfa_rport_online(struct bfa_rport_s *rport,
struct bfa_rport_info_s *rport_info);
-void bfa_rport_offline(struct bfa_rport_s *rport);
void bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed);
-void bfa_rport_get_stats(struct bfa_rport_s *rport,
- struct bfa_rport_hal_stats_s *stats);
-void bfa_rport_clear_stats(struct bfa_rport_s *rport);
void bfa_cb_rport_online(void *rport);
void bfa_cb_rport_offline(void *rport);
void bfa_cb_rport_qos_scn_flowid(void *rport,
void bfa_cb_rport_qos_scn_prio(void *rport,
struct bfa_rport_qos_attr_s old_qos_attr,
struct bfa_rport_qos_attr_s new_qos_attr);
-void bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
- struct bfa_rport_qos_attr_s *qos_attr);
/*
* bfa fcxp API functions
u32 bfa_lps_get_max_vport(struct bfa_s *bfa);
struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa);
void bfa_lps_delete(struct bfa_lps_s *lps);
-void bfa_lps_discard(struct bfa_lps_s *lps);
void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa,
u16 pdusz, wwn_t pwwn, wwn_t nwwn,
bfa_boolean_t auth_en);
void bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz,
wwn_t pwwn, wwn_t nwwn);
-void bfa_lps_flogo(struct bfa_lps_s *lps);
void bfa_lps_fdisclogo(struct bfa_lps_s *lps);
-u8 bfa_lps_get_tag(struct bfa_lps_s *lps);
-bfa_boolean_t bfa_lps_is_npiv_en(struct bfa_lps_s *lps);
-bfa_boolean_t bfa_lps_is_fport(struct bfa_lps_s *lps);
-bfa_boolean_t bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps);
-bfa_boolean_t bfa_lps_is_authreq(struct bfa_lps_s *lps);
-bfa_eproto_status_t bfa_lps_get_extstatus(struct bfa_lps_s *lps);
-u32 bfa_lps_get_pid(struct bfa_lps_s *lps);
+void bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, u32 n2n_pid);
u32 bfa_lps_get_base_pid(struct bfa_s *bfa);
u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid);
-u16 bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps);
-wwn_t bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps);
-wwn_t bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps);
-u8 bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps);
-u8 bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps);
-mac_t bfa_lps_get_lp_mac(struct bfa_lps_s *lps);
void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status);
void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status);
void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg);
void bfa_cb_lps_cvl_event(void *bfad, void *uarg);
-void bfa_trunk_enable_cfg(struct bfa_s *bfa);
-bfa_status_t bfa_trunk_enable(struct bfa_s *bfa);
-bfa_status_t bfa_trunk_disable(struct bfa_s *bfa);
-bfa_status_t bfa_trunk_get_attr(struct bfa_s *bfa,
- struct bfa_trunk_attr_s *attr);
-
#endif /* __BFA_SVC_H__ */
#include "bfad_drv.h"
#include "bfad_im.h"
#include "bfa_fcs.h"
-#include "bfa_os_inc.h"
#include "bfa_defs.h"
#include "bfa.h"
int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT;
int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH;
int bfa_io_max_sge = BFAD_IO_MAX_SGE;
-int log_level = 3; /* WARNING log level */
+int bfa_log_level = 3; /* WARNING log level */
int ioc_auto_recover = BFA_TRUE;
int bfa_linkup_delay = -1;
int fdmi_enable = BFA_TRUE;
u32 bfi_image_ct_fc_size, bfi_image_ct_cna_size, bfi_image_cb_fc_size;
u32 *bfi_image_ct_fc, *bfi_image_ct_cna, *bfi_image_cb_fc;
-const char *msix_name_ct[] = {
+static const char *msix_name_ct[] = {
"cpe0", "cpe1", "cpe2", "cpe3",
"rme0", "rme1", "rme2", "rme3",
"ctrl" };
-const char *msix_name_cb[] = {
+static const char *msix_name_cb[] = {
"cpe0", "cpe1", "cpe2", "cpe3",
"rme0", "rme1", "rme2", "rme3",
"eemc", "elpu0", "elpu1", "epss", "mlpu" };
MODULE_PARM_DESC(bfa_lun_queue_depth, "Lun queue depth, default=32, Range[>0]");
module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(bfa_io_max_sge, "Max io scatter/gather elements, default=255");
-module_param(log_level, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(log_level, "Driver log level, default=3, "
+module_param(bfa_log_level, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_log_level, "Driver log level, default=3, "
"Range[Critical:1|Error:2|Warning:3|Info:4]");
module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ioc_auto_recover, "IOC auto recovery, default=1, "
}
spin_lock_irqsave(&bfad->bfad_lock, flags);
- bfa_init(&bfad->bfa);
+ bfa_iocfc_init(&bfad->bfa);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
/* Set up interrupt handler for each vectors */
spin_lock_irqsave(&bfad->bfad_lock, flags);
- bfa_timer_tick(&bfad->bfa);
+ bfa_timer_beat(&bfad->bfa.timer_mod);
bfa_comp_deq(&bfad->bfa, &doneq);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
goto out_hal_mem_alloc_failure;
}
- bfa_init_trc(&bfad->bfa, bfad->trcmod);
- bfa_init_plog(&bfad->bfa, &bfad->plog_buf);
+ bfad->bfa.trcmod = bfad->trcmod;
+ bfad->bfa.plog = &bfad->plog_buf;
bfa_plog_init(&bfad->plog_buf);
bfa_plog_str(&bfad->plog_buf, BFA_PL_MID_DRVR, BFA_PL_EID_DRIVER_START,
0, "Driver Attach");
/* FCS INIT */
spin_lock_irqsave(&bfad->bfad_lock, flags);
- bfa_fcs_trc_init(&bfad->bfa_fcs, bfad->trcmod);
+ bfad->bfa_fcs.trcmod = bfad->trcmod;
bfa_fcs_attach(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE);
- bfa_fcs_set_fdmi_param(&bfad->bfa_fcs, fdmi_enable);
+ bfad->bfa_fcs.fdmi_enabled = fdmi_enable;
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfad->bfad_flags |= BFAD_DRV_INIT_DONE;
spin_lock_irqsave(&bfad->bfad_lock, flags);
init_completion(&bfad->comp);
- bfa_stop(&bfad->bfa);
+ bfa_iocfc_stop(&bfad->bfa);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
wait_for_completion(&bfad->comp);
unsigned long flags;
spin_lock_irqsave(&bfad->bfad_lock, flags);
- bfa_start(&bfad->bfa);
- bfa_fcs_start(&bfad->bfa_fcs);
+ bfa_iocfc_start(&bfad->bfa);
+ bfa_fcs_fabric_modstart(&bfad->bfa_fcs);
bfad->bfad_flags |= BFAD_HAL_START_DONE;
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
spin_lock_irqsave(&bfad->bfad_lock, flags);
init_completion(&bfad->comp);
- bfa_stop(&bfad->bfa);
+ bfa_iocfc_stop(&bfad->bfa);
bfad->bfad_flags &= ~BFAD_HAL_START_DONE;
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
wait_for_completion(&bfad->comp);
/*
* If bfa_linkup_delay is set to -1 default; try to retrive the
- * value using the bfad_os_get_linkup_delay(); else use the
+ * value using the bfad_get_linkup_delay(); else use the
* passed in module param value as the bfa_linkup_delay.
*/
if (bfa_linkup_delay < 0) {
- bfa_linkup_delay = bfad_os_get_linkup_delay(bfad);
- bfad_os_rport_online_wait(bfad);
+ bfa_linkup_delay = bfad_get_linkup_delay(bfad);
+ bfad_rport_online_wait(bfad);
bfa_linkup_delay = -1;
} else
- bfad_os_rport_online_wait(bfad);
+ bfad_rport_online_wait(bfad);
- BFA_LOG(KERN_INFO, bfad, log_level, "bfa device claimed\n");
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "bfa device claimed\n");
return BFA_STATUS_OK;
}
if (strcmp(FCPI_NAME, " fcpim") == 0)
supported_fc4s |= BFA_LPORT_ROLE_FCP_IM;
- bfa_ioc_auto_recover(ioc_auto_recover);
+ bfa_auto_recover = ioc_auto_recover;
bfa_fcs_rport_set_del_timeout(rport_del_timeout);
error = pci_register_driver(&bfad_pci_driver);
/*
* FC transport template entry, get SCSI target port ID.
*/
-void
+static void
bfad_im_get_starget_port_id(struct scsi_target *starget)
{
struct Scsi_Host *shost;
bfad = im_port->bfad;
spin_lock_irqsave(&bfad->bfad_lock, flags);
- itnim = bfad_os_get_itnim(im_port, starget->id);
+ itnim = bfad_get_itnim(im_port, starget->id);
if (itnim)
fc_id = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim);
/*
* FC transport template entry, get SCSI target nwwn.
*/
-void
+static void
bfad_im_get_starget_node_name(struct scsi_target *starget)
{
struct Scsi_Host *shost;
bfad = im_port->bfad;
spin_lock_irqsave(&bfad->bfad_lock, flags);
- itnim = bfad_os_get_itnim(im_port, starget->id);
+ itnim = bfad_get_itnim(im_port, starget->id);
if (itnim)
node_name = bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim);
/*
* FC transport template entry, get SCSI target pwwn.
*/
-void
+static void
bfad_im_get_starget_port_name(struct scsi_target *starget)
{
struct Scsi_Host *shost;
bfad = im_port->bfad;
spin_lock_irqsave(&bfad->bfad_lock, flags);
- itnim = bfad_os_get_itnim(im_port, starget->id);
+ itnim = bfad_get_itnim(im_port, starget->id);
if (itnim)
port_name = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
/*
* FC transport template entry, get SCSI host port ID.
*/
-void
+static void
bfad_im_get_host_port_id(struct Scsi_Host *shost)
{
struct bfad_im_port_s *im_port =
struct bfad_port_s *port = im_port->port;
fc_host_port_id(shost) =
- bfa_os_hton3b(bfa_fcs_lport_get_fcid(port->fcs_port));
+ bfa_hton3b(bfa_fcs_lport_get_fcid(port->fcs_port));
}
/*
wait_for_completion(vport->comp_del);
free_scsi_host:
- bfad_os_scsi_host_free(bfad, im_port);
+ bfad_scsi_host_free(bfad, im_port);
kfree(vport);
memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len);
spin_lock_irqsave(&bfad->bfad_lock, flags);
- rc = bfa_debug_fwtrc(&bfad->bfa,
+ rc = bfa_ioc_debug_fwtrc(&bfad->bfa.ioc,
fw_debug->debug_buffer,
&fw_debug->buffer_len);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len);
spin_lock_irqsave(&bfad->bfad_lock, flags);
- rc = bfa_debug_fwsave(&bfad->bfa,
+ rc = bfa_ioc_debug_fwsave(&bfad->bfa.ioc,
fw_debug->debug_buffer,
&fw_debug->buffer_len);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
if (!debug || !debug->debug_buffer)
return 0;
- return memory_read_from_buffer(buf, nbytes, pos,
+ return simple_read_from_buffer(buf, nbytes, pos,
debug->debug_buffer, debug->buffer_len);
}
if (!bfad->regdata)
return 0;
- rc = memory_read_from_buffer(buf, nbytes, pos,
+ rc = simple_read_from_buffer(buf, nbytes, pos,
bfad->regdata, bfad->reglen);
if ((*pos + nbytes) >= bfad->reglen) {
u32 *regbuf;
void __iomem *rb, *reg_addr;
unsigned long flags;
+ void *kern_buf;
- rc = sscanf(buf, "%x:%x", &addr, &len);
+ kern_buf = kzalloc(nbytes, GFP_KERNEL);
+
+ if (!kern_buf) {
+ printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n",
+ bfad->inst_no);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
+ kfree(kern_buf);
+ return -ENOMEM;
+ }
+
+ rc = sscanf(kern_buf, "%x:%x", &addr, &len);
if (rc < 2) {
printk(KERN_INFO
"bfad[%d]: %s failed to read user buf\n",
bfad->inst_no, __func__);
+ kfree(kern_buf);
return -EINVAL;
}
+ kfree(kern_buf);
kfree(bfad->regdata);
bfad->regdata = NULL;
bfad->reglen = 0;
int addr, val, rc;
void __iomem *reg_addr;
unsigned long flags;
+ void *kern_buf;
+
+ kern_buf = kzalloc(nbytes, GFP_KERNEL);
+
+ if (!kern_buf) {
+ printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n",
+ bfad->inst_no);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
+ kfree(kern_buf);
+ return -ENOMEM;
+ }
- rc = sscanf(buf, "%x:%x", &addr, &val);
+ rc = sscanf(kern_buf, "%x:%x", &addr, &val);
if (rc < 2) {
printk(KERN_INFO
"bfad[%d]: %s failed to read user buf\n",
bfad->inst_no, __func__);
+ kfree(kern_buf);
return -EINVAL;
}
+ kfree(kern_buf);
addr &= BFA_REG_ADDRMSK(bfa); /* offset only 17 bit and word align */
return -EINVAL;
}
- reg_addr = (u32 *) ((u8 *) bfa_ioc_bar0(ioc) + addr);
+ reg_addr = (bfa_ioc_bar0(ioc)) + addr;
spin_lock_irqsave(&bfad->bfad_lock, flags);
writel(val, reg_addr);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
#ifndef __BFAD_DRV_H__
#define __BFAD_DRV_H__
-#include "bfa_os_inc.h"
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/bitops.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_transport.h>
#include "bfa_modules.h"
#include "bfa_fcs.h"
#ifdef BFA_DRIVER_VERSION
#define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION
#else
-#define BFAD_DRIVER_VERSION "2.3.2.0"
+#define BFAD_DRIVER_VERSION "2.3.2.3"
#endif
#define BFAD_PROTO_NAME FCPI_NAME
*/
#define nextLowerInt(x) \
do { \
- int i; \
+ int __i; \
(*x)--; \
- for (i = 1; i < (sizeof(int)*8); i <<= 1) \
- (*x) = (*x) | (*x) >> i; \
+ for (__i = 1; __i < (sizeof(int)*8); __i <<= 1) \
+ (*x) = (*x) | (*x) >> __i; \
(*x)++; \
(*x) = (*x) >> 1; \
} while (0)
-#define list_remove_head(list, entry, type, member) \
-do { \
- entry = NULL; \
- if (!list_empty(list)) { \
- entry = list_entry((list)->next, type, member); \
- list_del_init(&entry->member); \
- } \
+#define BFA_LOG(level, bfad, mask, fmt, arg...) \
+do { \
+ if (((mask) == 4) || (level[1] <= '4')) \
+ dev_printk(level, &((bfad)->pcidev)->dev, fmt, ##arg); \
} while (0)
-#define list_get_first(list, type, member) \
-((list_empty(list)) ? NULL : \
- list_entry((list)->next, type, member))
-
bfa_status_t bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
struct bfa_lport_cfg_s *port_cfg,
struct device *dev);
void bfad_pci_remove(struct pci_dev *pdev);
int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid);
-void bfad_os_rport_online_wait(struct bfad_s *bfad);
-int bfad_os_get_linkup_delay(struct bfad_s *bfad);
+void bfad_rport_online_wait(struct bfad_s *bfad);
+int bfad_get_linkup_delay(struct bfad_s *bfad);
int bfad_install_msix_handler(struct bfad_s *bfad);
extern struct idr bfad_im_port_index;
extern int rport_del_timeout;
extern int bfa_lun_queue_depth;
extern int bfa_io_max_sge;
-extern int log_level;
+extern int bfa_log_level;
extern int ioc_auto_recover;
extern int bfa_linkup_delay;
extern int msix_disable_cb;
#include "bfad_drv.h"
#include "bfad_im.h"
-#include "bfa_cb_ioim.h"
#include "bfa_fcs.h"
BFA_TRC_FILE(LDRV, IM);
struct scsi_transport_template *bfad_im_scsi_transport_template;
struct scsi_transport_template *bfad_im_scsi_vport_transport_template;
static void bfad_im_itnim_work_handler(struct work_struct *work);
-static int bfad_im_queuecommand(struct scsi_cmnd *cmnd,
- void (*done)(struct scsi_cmnd *));
+static int bfad_im_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmnd);
static int bfad_im_slave_alloc(struct scsi_device *sdev);
static void bfad_im_fc_rport_add(struct bfad_im_port_s *im_port,
struct bfad_itnim_s *itnim);
if (!cmnd->result && itnim &&
(bfa_lun_queue_depth > cmnd->device->queue_depth)) {
/* Queue depth adjustment for good status completion */
- bfad_os_ramp_up_qdepth(itnim, cmnd->device);
+ bfad_ramp_up_qdepth(itnim, cmnd->device);
} else if (cmnd->result == SAM_STAT_TASK_SET_FULL && itnim) {
/* qfull handling */
- bfad_os_handle_qfull(itnim, cmnd->device);
+ bfad_handle_qfull(itnim, cmnd->device);
}
}
if (itnim_data) {
itnim = itnim_data->itnim;
if (itnim)
- bfad_os_ramp_up_qdepth(itnim, cmnd->device);
+ bfad_ramp_up_qdepth(itnim, cmnd->device);
}
}
bfa_get_adapter_model(bfa, model);
memset(bfa_buf, 0, sizeof(bfa_buf));
- if (ioc->ctdev)
+ if (ioc->ctdev && !ioc->fcmode)
snprintf(bfa_buf, sizeof(bfa_buf),
"Brocade FCOE Adapter, " "model: %s hwpath: %s driver: %s",
model, bfad->pci_name, BFAD_DRIVER_VERSION);
}
bfa_trc(bfad, hal_io->iotag);
- BFA_LOG(KERN_INFO, bfad, log_level, "scsi%d: abort cmnd %p iotag %x\n",
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
+ "scsi%d: abort cmnd %p iotag %x\n",
im_port->shost->host_no, cmnd, hal_io->iotag);
(void) bfa_ioim_abort(hal_io);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
cmnd->scsi_done(cmnd);
bfa_trc(bfad, hal_io->iotag);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"scsi%d: complete abort 0x%p iotag 0x%x\n",
im_port->shost->host_no, cmnd, hal_io->iotag);
return SUCCESS;
struct bfa_tskim_s *tskim;
struct bfa_itnim_s *bfa_itnim;
bfa_status_t rc = BFA_STATUS_OK;
+ struct scsi_lun scsilun;
tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
if (!tskim) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"target reset, fail to allocate tskim\n");
rc = BFA_STATUS_FAILED;
goto out;
cmnd->host_scribble = NULL;
cmnd->SCp.Status = 0;
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
- bfa_tskim_start(tskim, bfa_itnim, (lun_t)0,
+ memset(&scsilun, 0, sizeof(scsilun));
+ bfa_tskim_start(tskim, bfa_itnim, scsilun,
FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO);
out:
return rc;
int rc = SUCCESS;
unsigned long flags;
enum bfi_tskim_status task_status;
+ struct scsi_lun scsilun;
spin_lock_irqsave(&bfad->bfad_lock, flags);
itnim = itnim_data->itnim;
tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
if (!tskim) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"LUN reset, fail to allocate tskim");
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
rc = FAILED;
cmnd->SCp.ptr = (char *)&wq;
cmnd->SCp.Status = 0;
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
- bfa_tskim_start(tskim, bfa_itnim,
- bfad_int_to_lun(cmnd->device->lun),
+ int_to_scsilun(cmnd->device->lun, &scsilun);
+ bfa_tskim_start(tskim, bfa_itnim, scsilun,
FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
task_status = cmnd->SCp.Status >> 1;
if (task_status != BFI_TSKIM_STS_OK) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"LUN reset failure, status: %d\n", task_status);
rc = FAILED;
}
spin_lock_irqsave(&bfad->bfad_lock, flags);
for (i = 0; i < MAX_FCP_TARGET; i++) {
- itnim = bfad_os_get_itnim(im_port, i);
+ itnim = bfad_get_itnim(im_port, i);
if (itnim) {
cmnd->SCp.ptr = (char *)&wq;
rc = bfad_im_target_reset_send(bfad, cmnd, itnim);
task_status = cmnd->SCp.Status >> 1;
if (task_status != BFI_TSKIM_STS_OK) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"target reset failure,"
" status: %d\n", task_status);
err_cnt++;
fcid = bfa_fcs_itnim_get_fcid(&itnim_drv->fcs_itnim);
wwn2str(wwpn_str, wwpn);
fcid2str(fcid_str, fcid);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"ITNIM FREE scsi%d: FCID: %s WWPN: %s\n",
port->im_port->shost->host_no,
fcid_str, wwpn_str);
mutex_unlock(&bfad_mutex);
- im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad);
+ im_port->shost = bfad_scsi_host_alloc(im_port, bfad);
if (!im_port->shost) {
error = 1;
goto out_free_idr;
}
/* setup host fixed attribute if the lk supports */
- bfad_os_fc_host_init(im_port);
+ bfad_fc_host_init(im_port);
return 0;
bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
{
bfa_trc(bfad, bfad->inst_no);
- BFA_LOG(KERN_INFO, bfad, log_level, "Free scsi%d\n",
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Free scsi%d\n",
im_port->shost->host_no);
fc_remove_host(im_port->shost);
bfad->im = im;
im->bfad = bfad;
- if (bfad_os_thread_workq(bfad) != BFA_STATUS_OK) {
+ if (bfad_thread_workq(bfad) != BFA_STATUS_OK) {
kfree(im);
rc = BFA_STATUS_FAILED;
}
bfad_im_probe_undo(struct bfad_s *bfad)
{
if (bfad->im) {
- bfad_os_destroy_workq(bfad->im);
+ bfad_destroy_workq(bfad->im);
kfree(bfad->im);
bfad->im = NULL;
}
}
struct Scsi_Host *
-bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
+bfad_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
{
struct scsi_host_template *sht;
}
void
-bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
+bfad_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
{
if (!(im_port->flags & BFAD_PORT_DELETE))
flush_workqueue(bfad->im->drv_workq);
}
void
-bfad_os_destroy_workq(struct bfad_im_s *im)
+bfad_destroy_workq(struct bfad_im_s *im)
{
if (im && im->drv_workq) {
flush_workqueue(im->drv_workq);
}
bfa_status_t
-bfad_os_thread_workq(struct bfad_s *bfad)
+bfad_thread_workq(struct bfad_s *bfad)
{
struct bfad_im_s *im = bfad->im;
}
void
-bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
+bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
{
struct scsi_device *tmp_sdev;
}
void
-bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
+bfad_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
{
struct scsi_device *tmp_sdev;
}
struct bfad_itnim_s *
-bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id)
+bfad_get_itnim(struct bfad_im_port_s *im_port, int id)
{
struct bfad_itnim_s *itnim = NULL;
if (!ioc_attr)
return 0;
- bfa_get_attr(bfa, ioc_attr);
+ bfa_ioc_get_attr(&bfa->ioc, ioc_attr);
if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) {
if (ioc_attr->adapter_attr.is_mezz) {
supported_speed |= FC_PORTSPEED_8GBIT |
}
void
-bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
+bfad_fc_host_init(struct bfad_im_port_s *im_port)
{
struct Scsi_Host *host = im_port->shost;
struct bfad_s *bfad = im_port->bfad;
rport_ids.port_name =
cpu_to_be64(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
rport_ids.port_id =
- bfa_os_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim));
+ bfa_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim));
rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
itnim->fc_rport = fc_rport =
fcid2str(fcid_str, fcid);
list_add_tail(&itnim->list_entry,
&im_port->itnim_mapped_list);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"ITNIM ONLINE Target: %d:0:%d "
"FCID: %s WWPN: %s\n",
im_port->shost->host_no,
wwn2str(wwpn_str, wwpn);
fcid2str(fcid_str, fcid);
list_del(&itnim->list_entry);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"ITNIM OFFLINE Target: %d:0:%d "
"FCID: %s WWPN: %s\n",
im_port->shost->host_no,
* Scsi_Host template entry, queue a SCSI command to the BFAD.
*/
static int
-bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
+bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
{
struct bfad_im_port_s *im_port =
(struct bfad_im_port_s *) cmnd->device->host->hostdata[0];
return 0;
}
+static DEF_SCSI_QCMD(bfad_im_queuecommand)
+
void
-bfad_os_rport_online_wait(struct bfad_s *bfad)
+bfad_rport_online_wait(struct bfad_s *bfad)
{
int i;
int rport_delay = 10;
}
int
-bfad_os_get_linkup_delay(struct bfad_s *bfad)
+bfad_get_linkup_delay(struct bfad_s *bfad)
{
u8 nwwns = 0;
wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX];
char drv_workq_name[KOBJ_NAME_LEN];
};
-struct Scsi_Host *bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port,
+struct Scsi_Host *bfad_scsi_host_alloc(struct bfad_im_port_s *im_port,
struct bfad_s *);
-bfa_status_t bfad_os_thread_workq(struct bfad_s *bfad);
-void bfad_os_destroy_workq(struct bfad_im_s *im);
-void bfad_os_fc_host_init(struct bfad_im_port_s *im_port);
-void bfad_os_scsi_host_free(struct bfad_s *bfad,
+bfa_status_t bfad_thread_workq(struct bfad_s *bfad);
+void bfad_destroy_workq(struct bfad_im_s *im);
+void bfad_fc_host_init(struct bfad_im_port_s *im_port);
+void bfad_scsi_host_free(struct bfad_s *bfad,
struct bfad_im_port_s *im_port);
-void bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim,
+void bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim,
struct scsi_device *sdev);
-void bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev);
-struct bfad_itnim_s *bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id);
+void bfad_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev);
+struct bfad_itnim_s *bfad_get_itnim(struct bfad_im_port_s *im_port, int id);
extern struct scsi_host_template bfad_im_scsi_host_template;
extern struct scsi_host_template bfad_im_vport_template;
*/
union bfi_addr_u {
struct {
- u32 addr_lo;
- u32 addr_hi;
+ __be32 addr_lo;
+ __be32 addr_hi;
} a32;
};
* Scatter Gather Element
*/
struct bfi_sge_s {
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 flags:2,
rsvd:2,
sg_len:28;
*/
struct bfi_pbc_blun_s {
wwn_t tgt_pwwn;
- lun_t tgt_lun;
+ struct scsi_lun tgt_lun;
};
/*
#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
+#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG
#define CPE_Q_DEPTH(__n) \
(CPE_Q0_DEPTH + (__n) * (CPE_Q1_DEPTH - CPE_Q0_DEPTH))
#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
+#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG
#define CPE_DEPTH_Q(__n) \
(CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0))
(RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0))
#define RME_CI_PTR_Q(__n) \
(RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0))
-#define HQM_QSET_RXQ_DRBL_P0(__n) (HQM_QSET0_RXQ_DRBL_P0 + (__n) \
- * (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0))
-#define HQM_QSET_TXQ_DRBL_P0(__n) (HQM_QSET0_TXQ_DRBL_P0 + (__n) \
- * (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0))
-#define HQM_QSET_IB_DRBL_1_P0(__n) (HQM_QSET0_IB_DRBL_1_P0 + (__n) \
- * (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0))
-#define HQM_QSET_IB_DRBL_2_P0(__n) (HQM_QSET0_IB_DRBL_2_P0 + (__n) \
- * (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0))
-#define HQM_QSET_RXQ_DRBL_P1(__n) (HQM_QSET0_RXQ_DRBL_P1 + (__n) \
- * (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1))
-#define HQM_QSET_TXQ_DRBL_P1(__n) (HQM_QSET0_TXQ_DRBL_P1 + (__n) \
- * (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1))
-#define HQM_QSET_IB_DRBL_1_P1(__n) (HQM_QSET0_IB_DRBL_1_P1 + (__n) \
- * (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1))
-#define HQM_QSET_IB_DRBL_2_P1(__n) (HQM_QSET0_IB_DRBL_2_P1 + (__n) \
- * (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1))
+#define HQM_QSET_RXQ_DRBL_P0(__n) \
+ (HQM_QSET0_RXQ_DRBL_P0 + (__n) * \
+ (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0))
+#define HQM_QSET_TXQ_DRBL_P0(__n) \
+ (HQM_QSET0_TXQ_DRBL_P0 + (__n) * \
+ (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0))
+#define HQM_QSET_IB_DRBL_1_P0(__n) \
+ (HQM_QSET0_IB_DRBL_1_P0 + (__n) * \
+ (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0))
+#define HQM_QSET_IB_DRBL_2_P0(__n) \
+ (HQM_QSET0_IB_DRBL_2_P0 + (__n) * \
+ (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0))
+#define HQM_QSET_RXQ_DRBL_P1(__n) \
+ (HQM_QSET0_RXQ_DRBL_P1 + (__n) * \
+ (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1))
+#define HQM_QSET_TXQ_DRBL_P1(__n) \
+ (HQM_QSET0_TXQ_DRBL_P1 + (__n) * \
+ (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1))
+#define HQM_QSET_IB_DRBL_1_P1(__n) \
+ (HQM_QSET0_IB_DRBL_1_P1 + (__n) * \
+ (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1))
+#define HQM_QSET_IB_DRBL_2_P1(__n) \
+ (HQM_QSET0_IB_DRBL_2_P1 + (__n) * \
+ (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1))
#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
*/
union bfi_addr_u req_cq_ba[BFI_IOC_MAX_CQS];
union bfi_addr_u req_shadow_ci[BFI_IOC_MAX_CQS];
- u16 req_cq_elems[BFI_IOC_MAX_CQS];
+ __be16 req_cq_elems[BFI_IOC_MAX_CQS];
union bfi_addr_u rsp_cq_ba[BFI_IOC_MAX_CQS];
union bfi_addr_u rsp_shadow_pi[BFI_IOC_MAX_CQS];
- u16 rsp_cq_elems[BFI_IOC_MAX_CQS];
+ __be16 rsp_cq_elems[BFI_IOC_MAX_CQS];
union bfi_addr_u stats_addr; /* DMA-able address for stats */
union bfi_addr_u cfgrsp_addr; /* config response dma address */
struct bfi_mhdr_s mh; /* common msg header */
u8 coalesce; /* enable intr coalescing */
u8 rsvd[3];
- u16 delay; /* delay timer 0..1125us */
- u16 latency; /* latency timer 0..225us */
+ __be16 delay; /* delay timer 0..1125us */
+ __be16 latency; /* latency timer 0..225us */
};
struct bfi_mhdr_s mh; /* common msg header */
u8 status; /* port enable status */
u8 rsvd[3];
- u32 msgtag; /* msgtag for reply */
+ struct bfa_port_cfg_s port_cfg;/* port configuration */
+ u32 msgtag; /* msgtag for reply */
};
/*
struct bfa_port_cfg_s port_cfg; /* port configuration */
union bfi_addr_u stats_dma_addr; /* DMA address for stats */
u32 msgtag; /* msgtag for reply */
- u32 rsvd2;
+ u8 use_flash_cfg; /* get prot cfg from flash */
+ u8 rsvd2[3];
};
/*
*/
struct bfi_fcport_set_svc_params_req_s {
struct bfi_mhdr_s mh; /* msg header */
- u16 tx_bbcredit; /* Tx credits */
+ __be16 tx_bbcredit; /* Tx credits */
u16 rsvd;
};
u8 state; /* bfa_trunk_link_state_t */
u8 speed; /* bfa_port_speed_t */
u8 rsvd;
- u32 deskew;
+ __be32 deskew;
};
#define BFI_FCPORT_MAX_LINKS 2
*/
struct bfi_fcxp_send_req_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 fcxp_tag; /* driver request tag */
- u16 max_frmsz; /* max send frame size */
- u16 vf_id; /* vsan tag if applicable */
+ __be16 fcxp_tag; /* driver request tag */
+ __be16 max_frmsz; /* max send frame size */
+ __be16 vf_id; /* vsan tag if applicable */
u16 rport_fw_hndl; /* FW Handle for the remote port */
u8 class; /* FC class used for req/rsp */
u8 rsp_timeout; /* timeout in secs, 0-no response */
u8 cts; /* continue sequence */
u8 lp_tag; /* lport tag */
struct fchs_s fchs; /* request FC header structure */
- u32 req_len; /* request payload length */
- u32 rsp_maxlen; /* max response length expected */
+ __be32 req_len; /* request payload length */
+ __be32 rsp_maxlen; /* max response length expected */
struct bfi_sge_s req_sge[BFA_FCXP_MAX_SGES]; /* request buf */
struct bfi_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; /* response buf */
};
*/
struct bfi_fcxp_send_rsp_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 fcxp_tag; /* send request tag */
+ __be16 fcxp_tag; /* send request tag */
u8 req_status; /* request status */
u8 rsvd;
- u32 rsp_len; /* actual response length */
- u32 residue_len; /* residual response length */
+ __be32 rsp_len; /* actual response length */
+ __be32 residue_len; /* residual response length */
struct fchs_s fchs; /* response FC header structure */
};
struct bfi_uf_buf_post_s {
struct bfi_mhdr_s mh; /* Common msg header */
u16 buf_tag; /* buffer tag */
- u16 buf_len; /* total buffer length */
+ __be16 buf_len; /* total buffer length */
struct bfi_sge_s sge[BFA_UF_MAX_SGES]; /* buffer DMA SGEs */
};
enum bfi_lps_h2i_msgs {
BFI_LPS_H2I_LOGIN_REQ = 1,
BFI_LPS_H2I_LOGOUT_REQ = 2,
+ BFI_LPS_H2I_N2N_PID_REQ = 3,
};
enum bfi_lps_i2h_msgs {
struct bfi_mhdr_s mh; /* common msg header */
u8 lp_tag;
u8 alpa;
- u16 pdu_size;
+ __be16 pdu_size;
wwn_t pwwn;
wwn_t nwwn;
u8 fdisc;
u8 lsrjt_expl;
wwn_t port_name;
wwn_t node_name;
- u16 bb_credit;
+ __be16 bb_credit;
u8 f_port;
u8 npiv_en;
u32 lp_pid:24;
u8 rsvd[3];
};
+struct bfi_lps_n2n_pid_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 lp_tag;
+ u32 lp_pid:24;
+};
+
union bfi_lps_h2i_msg_u {
struct bfi_mhdr_s *msg;
struct bfi_lps_login_req_s *login_req;
struct bfi_lps_logout_req_s *logout_req;
+ struct bfi_lps_n2n_pid_req_s *n2n_pid_req;
};
union bfi_lps_i2h_msg_u {
struct bfi_rport_create_req_s {
struct bfi_mhdr_s mh; /* common msg header */
u16 bfa_handle; /* host rport handle */
- u16 max_frmsz; /* max rcv pdu size */
+ __be16 max_frmsz; /* max rcv pdu size */
u32 pid:24, /* remote port ID */
lp_tag:8; /* local port tag */
u32 local_pid:24, /* local port ID */
*/
struct bfi_ioim_req_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 io_tag; /* I/O tag */
+ __be16 io_tag; /* I/O tag */
u16 rport_hdl; /* itnim/rport firmware handle */
struct fcp_cmnd_s cmnd; /* IO request info */
*/
struct bfi_ioim_rsp_s {
struct bfi_mhdr_s mh; /* common msg header */
- u16 io_tag; /* completed IO tag */
+ __be16 io_tag; /* completed IO tag */
u16 bfa_rport_hndl; /* releated rport handle */
u8 io_status; /* IO completion status */
u8 reuse_io_tag; /* IO tag can be reused */
u8 sns_len; /* scsi sense length */
u8 resid_flags; /* IO residue flags */
u8 rsvd_a;
- u32 residue; /* IO residual length in bytes */
+ __be32 residue; /* IO residual length in bytes */
u32 rsvd_b[3];
};
struct bfi_ioim_abort_req_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 io_tag; /* I/O tag */
+ __be16 io_tag; /* I/O tag */
u16 abort_tag; /* unique request tag */
};
struct bfi_tskim_req_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 tsk_tag; /* task management tag */
+ __be16 tsk_tag; /* task management tag */
u16 itn_fhdl; /* itn firmware handle */
- lun_t lun; /* LU number */
+ struct scsi_lun lun; /* LU number */
u8 tm_flags; /* see enum fcp_tm_cmnd */
u8 t_secs; /* Timeout value in seconds */
u8 rsvd[2];
struct bfi_tskim_abortreq_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 tsk_tag; /* task management tag */
+ __be16 tsk_tag; /* task management tag */
u16 rsvd;
};
struct bfi_tskim_rsp_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 tsk_tag; /* task mgmt cmnd tag */
+ __be16 tsk_tag; /* task mgmt cmnd tag */
u8 tsk_status; /* @ref bfi_tskim_status */
u8 rsvd;
};
/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#ifndef __57XX_ISCSI_CONSTANTS_H_
#define __57XX_ISCSI_CONSTANTS_H_
/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#ifndef __57XX_ISCSI_HSI_LINUX_LE__
#define __57XX_ISCSI_HSI_LINUX_LE__
/* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#ifndef _BNX2I_H_
EP_STATE_OFLD_FAILED = 0x8000000,
EP_STATE_CONNECT_FAILED = 0x10000000,
EP_STATE_DISCONN_TIMEDOUT = 0x20000000,
+ EP_STATE_OFLD_FAILED_CID_BUSY = 0x80000000,
};
/**
* Function Prototypes
*/
extern void bnx2i_identify_device(struct bnx2i_hba *hba);
-extern void bnx2i_register_device(struct bnx2i_hba *hba);
extern void bnx2i_ulp_init(struct cnic_dev *dev);
extern void bnx2i_ulp_exit(struct cnic_dev *dev);
extern void bnx2i_start(void *handle);
extern void bnx2i_stop(void *handle);
-extern void bnx2i_reg_dev_all(void);
-extern void bnx2i_unreg_dev_all(void);
extern struct bnx2i_hba *get_adapter_list_head(void);
struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba,
struct iscsi_task *mtask);
extern void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba,
struct bnx2i_cmd *cmd);
-extern void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba,
- struct bnx2i_endpoint *ep);
-extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn);
-extern void bnx2i_send_conn_destroy(struct bnx2i_hba *hba,
+extern int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba,
struct bnx2i_endpoint *ep);
+extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn);
+extern int bnx2i_send_conn_destroy(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep);
extern int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba,
struct bnx2i_endpoint *ep);
/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include <linux/gfp.h>
struct bnx2i_cmd *bnx2i_cmd;
struct bnx2i_tmf_request *tmfabort_wqe;
u32 dword;
+ u32 scsi_lun[2];
bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data;
tmfabort_hdr = (struct iscsi_tm *)mtask->hdr;
default:
tmfabort_wqe->ref_itt = RESERVED_ITT;
}
- memcpy(tmfabort_wqe->lun, tmfabort_hdr->lun, sizeof(struct scsi_lun));
+ memcpy(scsi_lun, tmfabort_hdr->lun, sizeof(struct scsi_lun));
+ tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]);
+ tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]);
+
tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn);
tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
* this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate
* iscsi connection context clean-up process
*/
-void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+int bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
struct kwqe *kwqe_arr[2];
struct iscsi_kwqe_conn_destroy conn_cleanup;
+ int rc = -EINVAL;
memset(&conn_cleanup, 0x00, sizeof(struct iscsi_kwqe_conn_destroy));
kwqe_arr[0] = (struct kwqe *) &conn_cleanup;
if (hba->cnic && hba->cnic->submit_kwqes)
- hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
+
+ return rc;
}
*
* 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
*/
-static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
- struct bnx2i_endpoint *ep)
+static int bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep)
{
struct kwqe *kwqe_arr[2];
struct iscsi_kwqe_conn_offload1 ofld_req1;
dma_addr_t dma_addr;
int num_kwqes = 2;
u32 *ptbl;
+ int rc = -EINVAL;
ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
ofld_req1.hdr.flags =
ofld_req2.num_additional_wqes = 0;
if (hba->cnic && hba->cnic->submit_kwqes)
- hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
}
*
* 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
*/
-static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
- struct bnx2i_endpoint *ep)
+static int bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep)
{
struct kwqe *kwqe_arr[5];
struct iscsi_kwqe_conn_offload1 ofld_req1;
dma_addr_t dma_addr;
int num_kwqes = 2;
u32 *ptbl;
+ int rc = -EINVAL;
ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
ofld_req1.hdr.flags =
num_kwqes += 1;
if (hba->cnic && hba->cnic->submit_kwqes)
- hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
}
/**
*
* this routine prepares and posts CONN_OFLD_REQ1/2 KWQE
*/
-void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
+ int rc;
+
if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
- bnx2i_5771x_send_conn_ofld_req(hba, ep);
+ rc = bnx2i_5771x_send_conn_ofld_req(hba, ep);
else
- bnx2i_570x_send_conn_ofld_req(hba, ep);
+ rc = bnx2i_570x_send_conn_ofld_req(hba, ep);
+
+ return rc;
}
task = iscsi_itt_to_task(conn,
nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
if (task)
- iscsi_put_task(task);
+ __iscsi_put_task(task);
spin_unlock(&session->lock);
}
struct iscsi_task *task;
struct bnx2i_nop_in_msg *nop_in;
struct iscsi_nopin *hdr;
- u32 itt;
int tgt_async_nop = 0;
nop_in = (struct bnx2i_nop_in_msg *)cqe;
- itt = nop_in->itt & ISCSI_NOP_IN_MSG_INDEX;
spin_lock(&session->lock);
hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
hdr->exp_cmdsn = cpu_to_be32(nop_in->exp_cmd_sn);
hdr->ttt = cpu_to_be32(nop_in->ttt);
- if (itt == (u16) RESERVED_ITT) {
+ if (nop_in->itt == (u16) RESERVED_ITT) {
bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
hdr->itt = RESERVED_ITT;
tgt_async_nop = 1;
}
/* this is a response to one of our nop-outs */
- task = iscsi_itt_to_task(conn, itt);
+ task = iscsi_itt_to_task(conn,
+ (itt_t) (nop_in->itt & ISCSI_NOP_IN_MSG_INDEX));
if (task) {
hdr->flags = ISCSI_FLAG_CMD_FINAL;
hdr->itt = task->hdr->itt;
if (nopin->cq_req_sn != qp->cqe_exp_seq_sn)
break;
- if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx)))
+ if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx))) {
+ if (nopin->op_code == ISCSI_OP_NOOP_IN &&
+ nopin->itt == (u16) RESERVED_ITT) {
+ printk(KERN_ALERT "bnx2i: Unsolicited "
+ "NOP-In detected for suspended "
+ "connection dev=%s!\n",
+ bnx2i_conn->hba->netdev->name);
+ bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
+ goto cqe_out;
+ }
break;
-
+ }
tgt_async_msg = 0;
switch (nopin->op_code) {
printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
nopin->op_code);
}
-
if (!tgt_async_msg)
bnx2i_conn->ep->num_active_cmds--;
-
+cqe_out:
/* clear out in production version only, till beta keep opcode
* field intact, will be helpful in debugging (context dump)
* nopin->op_code = 0;
}
if (ofld_kcqe->completion_status) {
+ ep->state = EP_STATE_OFLD_FAILED;
if (ofld_kcqe->completion_status ==
ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE)
- printk(KERN_ALERT "bnx2i: unable to allocate"
- " iSCSI context resources\n");
- ep->state = EP_STATE_OFLD_FAILED;
+ printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - unable "
+ "to allocate iSCSI context resources\n",
+ hba->netdev->name);
+ else if (ofld_kcqe->completion_status ==
+ ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE)
+ printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
+ "opcode\n", hba->netdev->name);
+ else if (ofld_kcqe->completion_status ==
+ ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY)
+ /* error status code valid only for 5771x chipset */
+ ep->state = EP_STATE_OFLD_FAILED_CID_BUSY;
+ else
+ printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
+ "error code %d\n", hba->netdev->name,
+ ofld_kcqe->completion_status);
} else {
ep->state = EP_STATE_OFLD_COMPL;
cid_addr = ofld_kcqe->iscsi_conn_context_id;
static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk)
{
struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+ u32 old_state = ep->state;
ep->state = EP_STATE_TCP_RST_RCVD;
- if (ep->conn)
- bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
+ if (old_state == EP_STATE_DISCONN_START)
+ wake_up_interruptible(&ep->ofld_wait);
+ else
+ if (ep->conn)
+ bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
}
/* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include "bnx2i.h"
static u32 adapter_count;
#define DRV_MODULE_NAME "bnx2i"
-#define DRV_MODULE_VERSION "2.1.3"
-#define DRV_MODULE_RELDATE "Aug 10, 2010"
+#define DRV_MODULE_VERSION "2.6.2.2"
+#define DRV_MODULE_RELDATE "Nov 23, 2010"
static char version[] __devinitdata =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
u64 iscsi_error_mask = 0x00;
-static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) ;
-
/**
* bnx2i_identify_device - identifies NetXtreme II device type
{
struct bnx2i_hba *hba = handle;
int conns_active;
+ int wait_delay = 1 * HZ;
/* check if cleanup happened in GOING_DOWN context */
- if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
- &hba->adapter_state))
+ if (!test_and_set_bit(ADAPTER_STATE_GOING_DOWN,
+ &hba->adapter_state)) {
iscsi_host_for_each_session(hba->shost,
bnx2i_drop_session);
-
+ wait_delay = hba->hba_shutdown_tmo;
+ }
+ /* Wait for inflight offload connection tasks to complete before
+ * proceeding. Forcefully terminate all connection recovery in
+ * progress at the earliest, either in bind(), send_pdu(LOGIN),
+ * or conn_start()
+ */
+ wait_event_interruptible_timeout(hba->eh_wait,
+ (list_empty(&hba->ep_ofld_list) &&
+ list_empty(&hba->ep_destroy_list)),
+ 10 * HZ);
/* Wait for all endpoints to be torn down, Chip will be reset once
* control returns to network driver. So it is required to cleanup and
* release all connection resources before returning from this routine.
conns_active = hba->ofld_conns_active;
wait_event_interruptible_timeout(hba->eh_wait,
(hba->ofld_conns_active != conns_active),
- hba->hba_shutdown_tmo);
+ wait_delay);
if (hba->ofld_conns_active == conns_active)
break;
}
/* This flag should be cleared last so that ep_disconnect() gracefully
* cleans up connection context
*/
+ clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
}
-/**
- * bnx2i_register_device - register bnx2i adapter instance with the cnic driver
- * @hba: Adapter instance to register
- *
- * registers bnx2i adapter instance with the cnic driver while holding the
- * adapter structure lock
- */
-void bnx2i_register_device(struct bnx2i_hba *hba)
-{
- int rc;
-
- if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
- test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
- return;
- }
-
- rc = hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
-
- if (!rc)
- set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-}
-
-
-/**
- * bnx2i_reg_dev_all - registers all adapter instances with the cnic driver
- *
- * registers all bnx2i adapter instances with the cnic driver while holding
- * the global resource lock
- */
-void bnx2i_reg_dev_all(void)
-{
- struct bnx2i_hba *hba, *temp;
-
- mutex_lock(&bnx2i_dev_lock);
- list_for_each_entry_safe(hba, temp, &adapter_list, link)
- bnx2i_register_device(hba);
- mutex_unlock(&bnx2i_dev_lock);
-}
-
-
-/**
- * bnx2i_unreg_one_device - unregister adapter instance with the cnic driver
- * @hba: Adapter instance to unregister
- *
- * registers bnx2i adapter instance with the cnic driver while holding
- * the adapter structure lock
- */
-static void bnx2i_unreg_one_device(struct bnx2i_hba *hba)
-{
- if (hba->ofld_conns_active ||
- !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) ||
- test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state))
- return;
-
- hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
-
- /* ep_disconnect could come before NETDEV_DOWN, driver won't
- * see NETDEV_DOWN as it already unregistered itself.
- */
- hba->adapter_state = 0;
- clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-}
-
-/**
- * bnx2i_unreg_dev_all - unregisters all bnx2i instances with the cnic driver
- *
- * unregisters all bnx2i adapter instances with the cnic driver while holding
- * the global resource lock
- */
-void bnx2i_unreg_dev_all(void)
-{
- struct bnx2i_hba *hba, *temp;
-
- mutex_lock(&bnx2i_dev_lock);
- list_for_each_entry_safe(hba, temp, &adapter_list, link)
- bnx2i_unreg_one_device(hba);
- mutex_unlock(&bnx2i_dev_lock);
-}
-
/**
* bnx2i_init_one - initialize an adapter instance and allocate memory resources
/*
* bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include <linux/slab.h>
bnx2i_ep->state = EP_STATE_IDLE;
bnx2i_ep->hba->ofld_conns_active--;
- bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid);
+ if (bnx2i_ep->ep_iscsi_cid != (u16) -1)
+ bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid);
+
if (bnx2i_ep->conn) {
bnx2i_ep->conn->ep = NULL;
bnx2i_ep->conn = NULL;
ep = iscsi_lookup_endpoint(transport_fd);
if (!ep)
return -EINVAL;
+ /*
+ * Forcefully terminate all in progress connection recovery at the
+ * earliest, either in bind(), send_pdu(LOGIN), or conn_start()
+ */
+ if (bnx2i_adapter_ready(hba))
+ return -EIO;
bnx2i_ep = ep->dd_data;
if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
hba->netdev->name);
return -EEXIST;
}
-
bnx2i_ep->conn = bnx2i_conn;
bnx2i_conn->ep = bnx2i_ep;
bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid;
struct bnx2i_conn *bnx2i_conn = conn->dd_data;
int len = 0;
+ if (!(bnx2i_conn && bnx2i_conn->ep && bnx2i_conn->ep->hba))
+ goto out;
+
switch (param) {
case ISCSI_PARAM_CONN_PORT:
- if (bnx2i_conn->ep)
+ mutex_lock(&bnx2i_conn->ep->hba->net_dev_lock);
+ if (bnx2i_conn->ep->cm_sk)
len = sprintf(buf, "%hu\n",
bnx2i_conn->ep->cm_sk->dst_port);
+ mutex_unlock(&bnx2i_conn->ep->hba->net_dev_lock);
break;
case ISCSI_PARAM_CONN_ADDRESS:
- if (bnx2i_conn->ep)
+ mutex_lock(&bnx2i_conn->ep->hba->net_dev_lock);
+ if (bnx2i_conn->ep->cm_sk)
len = sprintf(buf, "%pI4\n",
&bnx2i_conn->ep->cm_sk->dst_ip);
+ mutex_unlock(&bnx2i_conn->ep->hba->net_dev_lock);
break;
default:
return iscsi_conn_get_param(cls_conn, param, buf);
}
-
+out:
return len;
}
struct bnx2i_hba *hba;
struct cnic_dev *cnic = NULL;
- bnx2i_reg_dev_all();
-
hba = get_adapter_list_head();
if (hba && hba->cnic)
cnic = hba->cnic->cm_select_dev(desti, CNIC_ULP_ISCSI);
static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
struct bnx2i_endpoint *ep)
{
- if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
+ if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) && ep->cm_sk)
hba->cnic->cm_destroy(ep->cm_sk);
- if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state))
- ep->state = EP_STATE_DISCONN_COMPL;
-
if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) &&
ep->state == EP_STATE_DISCONN_TIMEDOUT) {
- printk(KERN_ALERT "bnx2i - ERROR - please submit GRC Dump,"
- " NW/PCIe trace, driver msgs to developers"
- " for analysis\n");
- return 1;
+ if (ep->conn && ep->conn->cls_conn &&
+ ep->conn->cls_conn->dd_data) {
+ struct iscsi_conn *conn = ep->conn->cls_conn->dd_data;
+
+ /* Must suspend all rx queue activity for this ep */
+ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
+ }
+ /* CONN_DISCONNECT timeout may or may not be an issue depending
+ * on what transcribed in TCP layer, different targets behave
+ * differently
+ */
+ printk(KERN_ALERT "bnx2i (%s): - WARN - CONN_DISCON timed out, "
+ "please submit GRC Dump, NW/PCIe trace, "
+ "driver msgs to developers for analysis\n",
+ hba->netdev->name);
}
ep->state = EP_STATE_CLEANUP_START;
bnx2i_ep_destroy_list_add(hba, ep);
/* destroy iSCSI context, wait for it to complete */
- bnx2i_send_conn_destroy(hba, ep);
+ if (bnx2i_send_conn_destroy(hba, ep))
+ ep->state = EP_STATE_CLEANUP_CMPL;
+
wait_event_interruptible(ep->ofld_wait,
(ep->state != EP_STATE_CLEANUP_START));
if (shost) {
/* driver is given scsi host to work with */
hba = iscsi_host_priv(shost);
- /* Register the device with cnic if not already done so */
- bnx2i_register_device(hba);
} else
/*
* check if the given destination can be reached through
*/
hba = bnx2i_check_route(dst_addr);
- if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) {
+ if (!hba) {
rc = -EINVAL;
goto nohba;
}
+ mutex_lock(&hba->net_dev_lock);
+ if (bnx2i_adapter_ready(hba) || !hba->cid_que.cid_free_cnt) {
+ rc = -EPERM;
+ goto check_busy;
+ }
cnic = hba->cnic;
- mutex_lock(&hba->net_dev_lock);
ep = bnx2i_alloc_ep(hba);
if (!ep) {
rc = -ENOMEM;
}
bnx2i_ep = ep->dd_data;
- if (bnx2i_adapter_ready(hba)) {
- rc = -EPERM;
- goto net_if_down;
- }
-
bnx2i_ep->num_active_cmds = 0;
iscsi_cid = bnx2i_alloc_iscsi_cid(hba);
if (iscsi_cid == -1) {
- printk(KERN_ALERT "alloc_ep: unable to allocate iscsi cid\n");
+ printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate "
+ "iscsi cid\n", hba->netdev->name);
rc = -ENOMEM;
- goto iscsi_cid_err;
+ bnx2i_free_ep(ep);
+ goto check_busy;
}
bnx2i_ep->hba_age = hba->age;
rc = bnx2i_alloc_qp_resc(hba, bnx2i_ep);
if (rc != 0) {
- printk(KERN_ALERT "bnx2i: ep_conn, alloc QP resc error\n");
+ printk(KERN_ALERT "bnx2i (%s): ep_conn - alloc QP resc error"
+ "\n", hba->netdev->name);
rc = -ENOMEM;
goto qp_resc_err;
}
bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
add_timer(&bnx2i_ep->ofld_timer);
- bnx2i_send_conn_ofld_req(hba, bnx2i_ep);
+ if (bnx2i_send_conn_ofld_req(hba, bnx2i_ep)) {
+ if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) {
+ printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n",
+ hba->netdev->name, bnx2i_ep->ep_iscsi_cid);
+ rc = -EBUSY;
+ } else
+ rc = -ENOSPC;
+ printk(KERN_ALERT "bnx2i (%s): unable to send conn offld kwqe"
+ "\n", hba->netdev->name);
+ bnx2i_ep_ofld_list_del(hba, bnx2i_ep);
+ goto conn_failed;
+ }
/* Wait for CNIC hardware to setup conn context and return 'cid' */
wait_event_interruptible(bnx2i_ep->ofld_wait,
bnx2i_ep_ofld_list_del(hba, bnx2i_ep);
if (bnx2i_ep->state != EP_STATE_OFLD_COMPL) {
- rc = -ENOSPC;
+ if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) {
+ printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n",
+ hba->netdev->name, bnx2i_ep->ep_iscsi_cid);
+ rc = -EBUSY;
+ } else
+ rc = -ENOSPC;
goto conn_failed;
}
iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep);
if (rc) {
rc = -EINVAL;
- goto conn_failed;
+ /* Need to terminate and cleanup the connection */
+ goto release_ep;
}
bnx2i_ep->cm_sk->rcv_buf = 256 * 1024;
return ERR_PTR(rc);
}
conn_failed:
-net_if_down:
-iscsi_cid_err:
bnx2i_free_qp_resc(hba, bnx2i_ep);
qp_resc_err:
bnx2i_free_ep(ep);
check_busy:
mutex_unlock(&hba->net_dev_lock);
nohba:
- bnx2i_unreg_dev_all();
return ERR_PTR(rc);
}
cnic_dev_10g = 1;
switch (bnx2i_ep->state) {
- case EP_STATE_CONNECT_START:
+ case EP_STATE_CONNECT_FAILED:
case EP_STATE_CLEANUP_FAILED:
case EP_STATE_OFLD_FAILED:
case EP_STATE_DISCONN_TIMEDOUT:
ret = 0;
break;
+ case EP_STATE_CONNECT_START:
case EP_STATE_CONNECT_COMPL:
case EP_STATE_ULP_UPDATE_START:
case EP_STATE_ULP_UPDATE_COMPL:
ret = 1;
break;
case EP_STATE_TCP_RST_RCVD:
- ret = 0;
- break;
- case EP_STATE_CONNECT_FAILED:
if (cnic_dev_10g)
- ret = 1;
- else
ret = 0;
+ else
+ ret = 1;
break;
default:
ret = 0;
if (!cnic)
return 0;
- if (bnx2i_ep->state == EP_STATE_IDLE)
+ if (bnx2i_ep->state == EP_STATE_IDLE ||
+ bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT)
return 0;
if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
if (session->state == ISCSI_STATE_LOGGING_OUT) {
if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
/* Logout sent, but no resp */
- printk(KERN_ALERT "bnx2i - WARNING "
- "logout response was not "
- "received!\n");
+ printk(KERN_ALERT "bnx2i (%s): WARNING"
+ " logout response was not "
+ "received!\n",
+ bnx2i_ep->hba->netdev->name);
} else if (bnx2i_ep->state ==
EP_STATE_LOGOUT_RESP_RCVD)
close = 1;
else
close_ret = cnic->cm_abort(bnx2i_ep->cm_sk);
- /* No longer allow CFC delete if cm_close/abort fails the request */
if (close_ret)
- printk(KERN_ALERT "bnx2i: %s close/abort(%d) returned %d\n",
+ printk(KERN_ALERT "bnx2i (%s): close/abort(%d) returned %d\n",
bnx2i_ep->hba->netdev->name, close, close_ret);
else
/* wait for option-2 conn teardown */
destroy_conn:
bnx2i_ep_active_list_del(hba, bnx2i_ep);
if (bnx2i_tear_down_conn(hba, bnx2i_ep))
- ret = -EINVAL;
+ return -EINVAL;
out:
bnx2i_ep->state = EP_STATE_IDLE;
return ret;
mutex_lock(&hba->net_dev_lock);
- if (bnx2i_ep->state == EP_STATE_IDLE)
- goto return_bnx2i_ep;
+ if (bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT)
+ goto out;
- if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
+ if (bnx2i_ep->state == EP_STATE_IDLE)
goto free_resc;
- if (bnx2i_ep->hba_age != hba->age)
+ if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) ||
+ (bnx2i_ep->hba_age != hba->age)) {
+ bnx2i_ep_active_list_del(hba, bnx2i_ep);
goto free_resc;
+ }
/* Do all chip cleanup here */
if (bnx2i_hw_ep_disconnect(bnx2i_ep)) {
}
free_resc:
bnx2i_free_qp_resc(hba, bnx2i_ep);
-return_bnx2i_ep:
+
if (bnx2i_conn)
bnx2i_conn->ep = NULL;
bnx2i_free_ep(ep);
+out:
mutex_unlock(&hba->net_dev_lock);
- if (!hba->ofld_conns_active)
- bnx2i_unreg_dev_all();
wake_up_interruptible(&hba->eh_wait);
}
/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2004 - 2009 Broadcom Corporation
+ * Copyright (c) 2004 - 2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include "bnx2i.h"
* and is expected to be held on return.
*
**/
-static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct DeviceCtlBlk *dcb;
struct ScsiReqBlk *srb;
return 0;
}
+static DEF_SCSI_QCMD(dc395x_queue_command)
/*
* Return the disk geometry for the given SCSI device.
sdev = q->queuedata;
if (sdev && sdev->scsi_dh_data)
scsi_dh = sdev->scsi_dh_data->scsi_dh;
- if (!scsi_dh || !get_device(&sdev->sdev_gendev))
+ if (!scsi_dh || !get_device(&sdev->sdev_gendev) ||
+ sdev->sdev_state == SDEV_CANCEL ||
+ sdev->sdev_state == SDEV_DEL)
err = SCSI_DH_NOSYS;
+ if (sdev->sdev_state == SDEV_OFFLINE)
+ err = SCSI_DH_DEV_OFFLINED;
spin_unlock_irqrestore(q->queue_lock, flags);
- if (err)
+ if (err) {
+ if (fn)
+ fn(data, err);
return err;
+ }
if (scsi_dh->activate)
err = scsi_dh->activate(sdev, fn, data);
return 0;
}
-static int adpt_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
+static int adpt_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
{
adpt_hba* pHba = NULL;
struct adpt_device* pDev = NULL; /* dpt per device information */
return adpt_scsi_to_i2o(pHba, cmd, pDev);
}
+static DEF_SCSI_QCMD(adpt_queue)
+
static int adpt_bios_param(struct scsi_device *sdev, struct block_device *dev,
sector_t capacity, int geom[])
{
*/
static int adpt_detect(struct scsi_host_template * sht);
-static int adpt_queue(struct scsi_cmnd * cmd, void (*cmdcomplete) (struct scsi_cmnd *));
+static int adpt_queue(struct Scsi_Host *h, struct scsi_cmnd * cmd);
static int adpt_abort(struct scsi_cmnd * cmd);
static int adpt_reset(struct scsi_cmnd* cmd);
static int adpt_release(struct Scsi_Host *host);
static int dtc_biosparam(struct scsi_device *, struct block_device *,
sector_t, int*);
static int dtc_detect(struct scsi_host_template *);
-static int dtc_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int dtc_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int dtc_bus_reset(Scsi_Cmnd *);
#ifndef CMD_PER_LUN
static int eata2x_detect(struct scsi_host_template *);
static int eata2x_release(struct Scsi_Host *);
-static int eata2x_queuecommand(struct scsi_cmnd *,
- void (*done) (struct scsi_cmnd *));
+static int eata2x_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int eata2x_eh_abort(struct scsi_cmnd *);
static int eata2x_eh_host_reset(struct scsi_cmnd *);
static int eata2x_bios_param(struct scsi_device *, struct block_device *,
}
-static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
+static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt,
void (*done) (struct scsi_cmnd *))
{
struct Scsi_Host *shost = SCpnt->device->host;
return 0;
}
+static DEF_SCSI_QCMD(eata2x_queuecommand)
+
static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
{
struct Scsi_Host *shost = SCarg->device->host;
return 0;
}
-static int eata_pio_queue(struct scsi_cmnd *cmd,
+static int eata_pio_queue_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
unsigned int x, y;
return 0;
}
+static DEF_SCSI_QCMD(eata_pio_queue)
+
static int eata_pio_abort(struct scsi_cmnd *cmd)
{
unsigned int loop = 100;
scsi_track_queue_full(dev, lp->num_tagged - 1);
}
-static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int esp_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct scsi_device *dev = cmd->device;
struct esp *esp = shost_priv(dev->host);
return 0;
}
+static DEF_SCSI_QCMD(esp_queuecommand)
+
static int esp_check_gross_error(struct esp *esp)
{
if (esp->sreg & ESP_STAT_SPAM) {
/* Cleanup the fc_lport */
fc_lport_destroy(lport);
- fc_fcp_destroy(lport);
/* Stop the transmit retry timer */
del_timer_sync(&port->timer);
fc_remove_host(lport->host);
scsi_remove_host(lport->host);
+ /* Destroy lport scsi_priv */
+ fc_fcp_destroy(lport);
+
/* There are no more rports or I/O, free the EM */
fc_exch_mgr_free(lport);
static void fcoe_ctlr_timeout(unsigned long);
static void fcoe_ctlr_timer_work(struct work_struct *);
static void fcoe_ctlr_recv_work(struct work_struct *);
+static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *);
static void fcoe_ctlr_vn_start(struct fcoe_ctlr *);
static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *);
fip->mode = mode;
INIT_LIST_HEAD(&fip->fcfs);
mutex_init(&fip->ctlr_mutex);
+ spin_lock_init(&fip->ctlr_lock);
fip->flogi_oxid = FC_XID_UNKNOWN;
setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
}
EXPORT_SYMBOL(fcoe_ctlr_destroy);
+/**
+ * fcoe_ctlr_announce() - announce new FCF selection
+ * @fip: The FCoE controller
+ *
+ * Also sets the destination MAC for FCoE and control packets
+ *
+ * Called with neither ctlr_mutex nor ctlr_lock held.
+ */
+static void fcoe_ctlr_announce(struct fcoe_ctlr *fip)
+{
+ struct fcoe_fcf *sel;
+ struct fcoe_fcf *fcf;
+
+ mutex_lock(&fip->ctlr_mutex);
+ spin_lock_bh(&fip->ctlr_lock);
+
+ kfree_skb(fip->flogi_req);
+ fip->flogi_req = NULL;
+ list_for_each_entry(fcf, &fip->fcfs, list)
+ fcf->flogi_sent = 0;
+
+ spin_unlock_bh(&fip->ctlr_lock);
+ sel = fip->sel_fcf;
+
+ if (sel && !compare_ether_addr(sel->fcf_mac, fip->dest_addr))
+ goto unlock;
+ if (!is_zero_ether_addr(fip->dest_addr)) {
+ printk(KERN_NOTICE "libfcoe: host%d: "
+ "FIP Fibre-Channel Forwarder MAC %pM deselected\n",
+ fip->lp->host->host_no, fip->dest_addr);
+ memset(fip->dest_addr, 0, ETH_ALEN);
+ }
+ if (sel) {
+ printk(KERN_INFO "libfcoe: host%d: FIP selected "
+ "Fibre-Channel Forwarder MAC %pM\n",
+ fip->lp->host->host_no, sel->fcf_mac);
+ memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
+ fip->map_dest = 0;
+ }
+unlock:
+ mutex_unlock(&fip->ctlr_mutex);
+}
+
/**
* fcoe_ctlr_fcoe_size() - Return the maximum FCoE size required for VN_Port
* @fip: The FCoE controller to get the maximum FCoE size from
* The caller must check that the length is a multiple of 4.
* The SKB must have enough headroom (28 bytes) and tailroom (8 bytes).
* The the skb must also be an fc_frame.
+ *
+ * This is called from the lower-level driver with spinlocks held,
+ * so we must not take a mutex here.
*/
int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
struct sk_buff *skb)
switch (op) {
case ELS_FLOGI:
op = FIP_DT_FLOGI;
- break;
+ if (fip->mode == FIP_MODE_VN2VN)
+ break;
+ spin_lock_bh(&fip->ctlr_lock);
+ kfree_skb(fip->flogi_req);
+ fip->flogi_req = skb;
+ fip->flogi_req_send = 1;
+ spin_unlock_bh(&fip->ctlr_lock);
+ schedule_work(&fip->timer_work);
+ return -EINPROGRESS;
case ELS_FDISC:
if (ntoh24(fh->fh_s_id))
return 0;
}
mtu_valid = fcoe_ctlr_mtu_valid(fcf);
fcf->time = jiffies;
- if (!found) {
- LIBFCOE_FIP_DBG(fip, "New FCF for fab %16.16llx "
- "map %x val %d\n",
- fcf->fabric_name, fcf->fc_map, mtu_valid);
- }
+ if (!found)
+ LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n",
+ fcf->fabric_name, fcf->fcf_mac);
/*
* If this advertisement is not solicited and our max receive size
if (first && time_after(jiffies, fip->sol_time + sol_tov))
fcoe_ctlr_solicit(fip, NULL);
+ /*
+ * Put this FCF at the head of the list for priority among equals.
+ * This helps in the case of an NPV switch which insists we use
+ * the FCF that answers multicast solicitations, not the others that
+ * are sending periodic multicast advertisements.
+ */
+ if (mtu_valid) {
+ list_del(&fcf->list);
+ list_add(&fcf->list, &fip->fcfs);
+ }
+
/*
* If this is the first validated FCF, note the time and
* set a timer to trigger selection.
els_op = *(u8 *)(fh + 1);
if ((els_dtype == FIP_DT_FLOGI || els_dtype == FIP_DT_FDISC) &&
- sub == FIP_SC_REP && els_op == ELS_LS_ACC &&
- fip->mode != FIP_MODE_VN2VN) {
- if (!is_valid_ether_addr(granted_mac)) {
- LIBFCOE_FIP_DBG(fip,
- "Invalid MAC address %pM in FIP ELS\n",
- granted_mac);
- goto drop;
- }
- memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
+ sub == FIP_SC_REP && fip->mode != FIP_MODE_VN2VN) {
+ if (els_op == ELS_LS_ACC) {
+ if (!is_valid_ether_addr(granted_mac)) {
+ LIBFCOE_FIP_DBG(fip,
+ "Invalid MAC address %pM in FIP ELS\n",
+ granted_mac);
+ goto drop;
+ }
+ memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
- if (fip->flogi_oxid == ntohs(fh->fh_ox_id))
- fip->flogi_oxid = FC_XID_UNKNOWN;
+ if (fip->flogi_oxid == ntohs(fh->fh_ox_id)) {
+ fip->flogi_oxid = FC_XID_UNKNOWN;
+ if (els_dtype == FIP_DT_FLOGI)
+ fcoe_ctlr_announce(fip);
+ }
+ } else if (els_dtype == FIP_DT_FLOGI &&
+ !fcoe_ctlr_flogi_retry(fip))
+ goto drop; /* retrying FLOGI so drop reject */
}
if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) &&
* fcoe_ctlr_select() - Select the best FCF (if possible)
* @fip: The FCoE controller
*
+ * Returns the selected FCF, or NULL if none are usable.
+ *
* If there are conflicting advertisements, no FCF can be chosen.
*
+ * If there is already a selected FCF, this will choose a better one or
+ * an equivalent one that hasn't already been sent a FLOGI.
+ *
* Called with lock held.
*/
-static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
+static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;
- struct fcoe_fcf *best = NULL;
+ struct fcoe_fcf *best = fip->sel_fcf;
+ struct fcoe_fcf *first;
+
+ first = list_first_entry(&fip->fcfs, struct fcoe_fcf, list);
list_for_each_entry(fcf, &fip->fcfs, list) {
- LIBFCOE_FIP_DBG(fip, "consider FCF for fab %16.16llx "
- "VFID %d map %x val %d\n",
- fcf->fabric_name, fcf->vfid,
- fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));
+ LIBFCOE_FIP_DBG(fip, "consider FCF fab %16.16llx "
+ "VFID %d mac %pM map %x val %d "
+ "sent %u pri %u\n",
+ fcf->fabric_name, fcf->vfid, fcf->fcf_mac,
+ fcf->fc_map, fcoe_ctlr_mtu_valid(fcf),
+ fcf->flogi_sent, fcf->pri);
+ if (fcf->fabric_name != first->fabric_name ||
+ fcf->vfid != first->vfid ||
+ fcf->fc_map != first->fc_map) {
+ LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
+ "or FC-MAP\n");
+ return NULL;
+ }
+ if (fcf->flogi_sent)
+ continue;
if (!fcoe_ctlr_fcf_usable(fcf)) {
LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx "
"map %x %svalid %savailable\n",
"" : "un");
continue;
}
- if (!best) {
- best = fcf;
- continue;
- }
- if (fcf->fabric_name != best->fabric_name ||
- fcf->vfid != best->vfid ||
- fcf->fc_map != best->fc_map) {
- LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
- "or FC-MAP\n");
- return;
- }
- if (fcf->pri < best->pri)
+ if (!best || fcf->pri < best->pri || best->flogi_sent)
best = fcf;
}
fip->sel_fcf = best;
+ if (best) {
+ LIBFCOE_FIP_DBG(fip, "using FCF mac %pM\n", best->fcf_mac);
+ fip->port_ka_time = jiffies +
+ msecs_to_jiffies(FIP_VN_KA_PERIOD);
+ fip->ctlr_ka_time = jiffies + best->fka_period;
+ if (time_before(fip->ctlr_ka_time, fip->timer.expires))
+ mod_timer(&fip->timer, fip->ctlr_ka_time);
+ }
+ return best;
+}
+
+/**
+ * fcoe_ctlr_flogi_send_locked() - send FIP-encapsulated FLOGI to current FCF
+ * @fip: The FCoE controller
+ *
+ * Returns non-zero error if it could not be sent.
+ *
+ * Called with ctlr_mutex and ctlr_lock held.
+ * Caller must verify that fip->sel_fcf is not NULL.
+ */
+static int fcoe_ctlr_flogi_send_locked(struct fcoe_ctlr *fip)
+{
+ struct sk_buff *skb;
+ struct sk_buff *skb_orig;
+ struct fc_frame_header *fh;
+ int error;
+
+ skb_orig = fip->flogi_req;
+ if (!skb_orig)
+ return -EINVAL;
+
+ /*
+ * Clone and send the FLOGI request. If clone fails, use original.
+ */
+ skb = skb_clone(skb_orig, GFP_ATOMIC);
+ if (!skb) {
+ skb = skb_orig;
+ fip->flogi_req = NULL;
+ }
+ fh = (struct fc_frame_header *)skb->data;
+ error = fcoe_ctlr_encaps(fip, fip->lp, FIP_DT_FLOGI, skb,
+ ntoh24(fh->fh_d_id));
+ if (error) {
+ kfree_skb(skb);
+ return error;
+ }
+ fip->send(fip, skb);
+ fip->sel_fcf->flogi_sent = 1;
+ return 0;
+}
+
+/**
+ * fcoe_ctlr_flogi_retry() - resend FLOGI request to a new FCF if possible
+ * @fip: The FCoE controller
+ *
+ * Returns non-zero error code if there's no FLOGI request to retry or
+ * no alternate FCF available.
+ */
+static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip)
+{
+ struct fcoe_fcf *fcf;
+ int error;
+
+ mutex_lock(&fip->ctlr_mutex);
+ spin_lock_bh(&fip->ctlr_lock);
+ LIBFCOE_FIP_DBG(fip, "re-sending FLOGI - reselect\n");
+ fcf = fcoe_ctlr_select(fip);
+ if (!fcf || fcf->flogi_sent) {
+ kfree_skb(fip->flogi_req);
+ fip->flogi_req = NULL;
+ error = -ENOENT;
+ } else {
+ fcoe_ctlr_solicit(fip, NULL);
+ error = fcoe_ctlr_flogi_send_locked(fip);
+ }
+ spin_unlock_bh(&fip->ctlr_lock);
+ mutex_unlock(&fip->ctlr_mutex);
+ return error;
+}
+
+
+/**
+ * fcoe_ctlr_flogi_send() - Handle sending of FIP FLOGI.
+ * @fip: The FCoE controller that timed out
+ *
+ * Done here because fcoe_ctlr_els_send() can't get mutex.
+ *
+ * Called with ctlr_mutex held. The caller must not hold ctlr_lock.
+ */
+static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip)
+{
+ struct fcoe_fcf *fcf;
+
+ spin_lock_bh(&fip->ctlr_lock);
+ fcf = fip->sel_fcf;
+ if (!fcf || !fip->flogi_req_send)
+ goto unlock;
+
+ LIBFCOE_FIP_DBG(fip, "sending FLOGI\n");
+
+ /*
+ * If this FLOGI is being sent due to a timeout retry
+ * to the same FCF as before, select a different FCF if possible.
+ */
+ if (fcf->flogi_sent) {
+ LIBFCOE_FIP_DBG(fip, "sending FLOGI - reselect\n");
+ fcf = fcoe_ctlr_select(fip);
+ if (!fcf || fcf->flogi_sent) {
+ LIBFCOE_FIP_DBG(fip, "sending FLOGI - clearing\n");
+ list_for_each_entry(fcf, &fip->fcfs, list)
+ fcf->flogi_sent = 0;
+ fcf = fcoe_ctlr_select(fip);
+ }
+ }
+ if (fcf) {
+ fcoe_ctlr_flogi_send_locked(fip);
+ fip->flogi_req_send = 0;
+ } else /* XXX */
+ LIBFCOE_FIP_DBG(fip, "No FCF selected - defer send\n");
+unlock:
+ spin_unlock_bh(&fip->ctlr_lock);
}
/**
sel = fip->sel_fcf;
if (!sel && fip->sel_time) {
if (time_after_eq(jiffies, fip->sel_time)) {
- fcoe_ctlr_select(fip);
- sel = fip->sel_fcf;
+ sel = fcoe_ctlr_select(fip);
fip->sel_time = 0;
} else if (time_after(next_timer, fip->sel_time))
next_timer = fip->sel_time;
}
- if (sel != fcf) {
- fcf = sel; /* the old FCF may have been freed */
- if (sel) {
- printk(KERN_INFO "libfcoe: host%d: FIP selected "
- "Fibre-Channel Forwarder MAC %pM\n",
- fip->lp->host->host_no, sel->fcf_mac);
- memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
- fip->map_dest = 0;
- fip->port_ka_time = jiffies +
- msecs_to_jiffies(FIP_VN_KA_PERIOD);
- fip->ctlr_ka_time = jiffies + sel->fka_period;
- if (time_after(next_timer, fip->ctlr_ka_time))
- next_timer = fip->ctlr_ka_time;
- } else {
- printk(KERN_NOTICE "libfcoe: host%d: "
- "FIP Fibre-Channel Forwarder timed out. "
- "Starting FCF discovery.\n",
- fip->lp->host->host_no);
- reset = 1;
- }
- }
+ if (sel && fip->flogi_req_send)
+ fcoe_ctlr_flogi_send(fip);
+ else if (!sel && fcf)
+ reset = 1;
if (sel && !sel->fd_flags) {
if (time_after_eq(jiffies, fip->ctlr_ka_time)) {
case FIP_ST_LINK_WAIT:
goto unlock;
default:
- WARN(1, "unexpected state %d", fip->state);
+ WARN(1, "unexpected state %d\n", fip->state);
goto unlock;
}
mod_timer(&fip->timer, next_time);
return 0;
}
-static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int fd_mcs_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
{
struct Scsi_Host *shpnt = SCpnt->device->host;
return 0;
}
+static DEF_SCSI_QCMD(fd_mcs_queue)
+
#if DEBUG_ABORT || DEBUG_RESET
static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
{
return IRQ_HANDLED;
}
-static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
+static int fdomain_16x0_queue_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
if (in_command) {
return 0;
}
+static DEF_SCSI_QCMD(fdomain_16x0_queue)
+
#if DEBUG_ABORT
static void print_info(struct scsi_cmnd *SCpnt)
{
void fnic_update_mac(struct fc_lport *, u8 *new);
void fnic_update_mac_locked(struct fnic *, u8 *new);
-int fnic_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+int fnic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
int fnic_abort_cmd(struct scsi_cmnd *);
int fnic_device_reset(struct scsi_cmnd *);
int fnic_host_reset(struct scsi_cmnd *);
* Routine to send a scsi cdb
* Called with host_lock held and interrupts disabled.
*/
-int fnic_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
{
struct fc_lport *lp;
struct fc_rport *rport;
return ret;
}
+DEF_SCSI_QCMD(fnic_queuecommand)
+
/*
* fnic_fcpio_fw_reset_cmpl_handler
* Routine to handle fw reset completion
static int generic_NCR5380_abort(Scsi_Cmnd *);
static int generic_NCR5380_detect(struct scsi_host_template *);
static int generic_NCR5380_release_resources(struct Scsi_Host *);
-static int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int generic_NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int generic_NCR5380_bus_reset(Scsi_Cmnd *);
static const char* generic_NCR5380_info(struct Scsi_Host *);
unsigned long arg);
static void gdth_flush(gdth_ha_str *ha);
-static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *));
+static int gdth_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
struct gdth_cmndinfo *cmndinfo);
static void gdth_scsi_done(struct scsi_cmnd *scp);
}
-static int gdth_queuecommand(struct scsi_cmnd *scp,
+static int gdth_queuecommand_lck(struct scsi_cmnd *scp,
void (*done)(struct scsi_cmnd *))
{
gdth_ha_str *ha = shost_priv(scp->device->host);
return __gdth_queuecommand(ha, scp, cmndinfo);
}
+static DEF_SCSI_QCMD(gdth_queuecommand)
+
static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
struct gdth_cmndinfo *cmndinfo)
{
#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/compat.h>
#include <linux/blktrace_api.h>
#include <linux/uaccess.h>
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3252},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3253},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3254},
-#define PCI_DEVICE_ID_HP_CISSF 0x333f
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F},
- {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
- {PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
};
{0x3249103C, "Smart Array P812", &SA5_access},
{0x324a103C, "Smart Array P712m", &SA5_access},
{0x324b103C, "Smart Array P711m", &SA5_access},
- {0x3233103C, "StorageWorks P1210m", &SA5_access},
- {0x333F103C, "StorageWorks P1210m", &SA5_access},
{0x3250103C, "Smart Array", &SA5_access},
{0x3250113C, "Smart Array", &SA5_access},
{0x3250123C, "Smart Array", &SA5_access},
void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
int cmd_type);
-static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *));
+static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static void hpsa_scan_start(struct Scsi_Host *);
static int hpsa_scan_finished(struct Scsi_Host *sh,
unsigned long elapsed_time);
static inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1,
struct hpsa_scsi_dev_t *dev2)
{
- if ((is_logical_dev_addr_mode(dev1->scsi3addr) ||
- (dev1->lun != -1 && dev2->lun != -1)) &&
- dev1->devtype != 0x0C)
- return (memcmp(dev1, dev2, sizeof(*dev1)) == 0);
-
/* we compare everything except lun and target as these
* are not yet assigned. Compare parts likely
* to differ first
return 0;
if (memcmp(dev1->vendor, dev2->vendor, sizeof(dev1->vendor)) != 0)
return 0;
- if (memcmp(dev1->revision, dev2->revision, sizeof(dev1->revision)) != 0)
- return 0;
if (dev1->devtype != dev2->devtype)
return 0;
- if (dev1->raid_level != dev2->raid_level)
- return 0;
if (dev1->bus != dev2->bus)
return 0;
return 1;
sizeof(this_device->vendor));
memcpy(this_device->model, &inq_buff[16],
sizeof(this_device->model));
- memcpy(this_device->revision, &inq_buff[32],
- sizeof(this_device->revision));
memset(this_device->device_id, 0,
sizeof(this_device->device_id));
hpsa_get_device_id(h, scsi3addr, this_device->device_id,
}
-static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
+static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct ctlr_info *h;
return 0;
}
+static DEF_SCSI_QCMD(hpsa_scsi_queue_command)
+
static void hpsa_scan_start(struct Scsi_Host *sh)
{
struct ctlr_info *h = shost_to_hba(sh);
unsigned char device_id[16]; /* from inquiry pg. 0x83 */
unsigned char vendor[8]; /* bytes 8-15 of inquiry data */
unsigned char model[16]; /* bytes 16-31 of inquiry data */
- unsigned char revision[4]; /* bytes 32-35 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
};
MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba);
}
-static int hptiop_queuecommand(struct scsi_cmnd *scp,
+static int hptiop_queuecommand_lck(struct scsi_cmnd *scp,
void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = scp->device->host;
return 0;
}
+static DEF_SCSI_QCMD(hptiop_queuecommand)
+
static const char *hptiop_info(struct Scsi_Host *host)
{
return driver_name_long;
#include <scsi/scsi_host.h>
/* Common forward declarations for all Linux-versions: */
-static int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int ibmmca_queuecommand (struct Scsi_Host *, struct scsi_cmnd *);
static int ibmmca_abort (Scsi_Cmnd *);
static int ibmmca_host_reset (Scsi_Cmnd *);
static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
}
/* The following routine is the SCSI command queue for the midlevel driver */
-static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int ibmmca_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
{
unsigned int ldn;
unsigned int scsi_cmd;
return 0;
}
+static DEF_SCSI_QCMD(ibmmca_queuecommand)
+
static int __ibmmca_abort(Scsi_Cmnd * cmd)
{
/* Abort does not work, as the adapter never generates an interrupt on
* Returns:
* 0 on success / other on failure
**/
-static int ibmvfc_queuecommand(struct scsi_cmnd *cmnd,
+static int ibmvfc_queuecommand_lck(struct scsi_cmnd *cmnd,
void (*done) (struct scsi_cmnd *))
{
struct ibmvfc_host *vhost = shost_priv(cmnd->device->host);
return 0;
}
+static DEF_SCSI_QCMD(ibmvfc_queuecommand)
+
/**
* ibmvfc_sync_completion - Signal that a synchronous command has completed
* @evt: ibmvfc event struct
}
static const struct ibmvfc_async_desc ae_desc [] = {
- { IBMVFC_AE_ELS_PLOGI, "PLOGI", IBMVFC_DEFAULT_LOG_LEVEL + 1 },
- { IBMVFC_AE_ELS_LOGO, "LOGO", IBMVFC_DEFAULT_LOG_LEVEL + 1 },
- { IBMVFC_AE_ELS_PRLO, "PRLO", IBMVFC_DEFAULT_LOG_LEVEL + 1 },
- { IBMVFC_AE_SCN_NPORT, "N-Port SCN", IBMVFC_DEFAULT_LOG_LEVEL + 1 },
- { IBMVFC_AE_SCN_GROUP, "Group SCN", IBMVFC_DEFAULT_LOG_LEVEL + 1 },
- { IBMVFC_AE_SCN_DOMAIN, "Domain SCN", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_SCN_FABRIC, "Fabric SCN", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_LINK_UP, "Link Up", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_LINK_DOWN, "Link Down", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_LINK_DEAD, "Link Dead", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_HALT, "Halt", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_RESUME, "Resume", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_ADAPTER_FAILED, "Adapter Failed", IBMVFC_DEFAULT_LOG_LEVEL },
+ { "PLOGI", IBMVFC_AE_ELS_PLOGI, IBMVFC_DEFAULT_LOG_LEVEL + 1 },
+ { "LOGO", IBMVFC_AE_ELS_LOGO, IBMVFC_DEFAULT_LOG_LEVEL + 1 },
+ { "PRLO", IBMVFC_AE_ELS_PRLO, IBMVFC_DEFAULT_LOG_LEVEL + 1 },
+ { "N-Port SCN", IBMVFC_AE_SCN_NPORT, IBMVFC_DEFAULT_LOG_LEVEL + 1 },
+ { "Group SCN", IBMVFC_AE_SCN_GROUP, IBMVFC_DEFAULT_LOG_LEVEL + 1 },
+ { "Domain SCN", IBMVFC_AE_SCN_DOMAIN, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Fabric SCN", IBMVFC_AE_SCN_FABRIC, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Link Up", IBMVFC_AE_LINK_UP, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Link Down", IBMVFC_AE_LINK_DOWN, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Link Dead", IBMVFC_AE_LINK_DEAD, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Halt", IBMVFC_AE_HALT, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Resume", IBMVFC_AE_RESUME, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Adapter Failed", IBMVFC_AE_ADAPTER_FAILED, IBMVFC_DEFAULT_LOG_LEVEL },
};
static const struct ibmvfc_async_desc unknown_ae = {
- 0, "Unknown async", IBMVFC_DEFAULT_LOG_LEVEL
+ "Unknown async", 0, IBMVFC_DEFAULT_LOG_LEVEL
};
/**
};
struct ibmvfc_async_desc {
- enum ibmvfc_async_event ae;
const char *desc;
+ enum ibmvfc_async_event ae;
int log_level;
};
* @cmd: struct scsi_cmnd to be executed
* @done: Callback function to be called when cmd is completed
*/
-static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
+static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,
void (*done) (struct scsi_cmnd *))
{
struct srp_cmd *srp_cmd;
return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
}
+static DEF_SCSI_QCMD(ibmvscsi_queuecommand)
+
/* ------------------------------------------------------------
* Routines for driver initialization
*/
return 0;
}
-static int imm_queuecommand(struct scsi_cmnd *cmd,
+static int imm_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
imm_struct *dev = imm_dev(cmd->device->host);
return 0;
}
+static DEF_SCSI_QCMD(imm_queuecommand)
+
/*
* Apparently the disk->capacity attribute is off by 1 sector
* for all disk drives. We add the one here, but it should really
static void in2000_execute(struct Scsi_Host *instance);
-static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
{
struct Scsi_Host *instance;
struct IN2000_hostdata *hostdata;
return 0;
}
+static DEF_SCSI_QCMD(in2000_queuecommand)
+
/*
flags)
static int in2000_detect(struct scsi_host_template *) in2000__INIT;
-static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int in2000_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int in2000_abort(Scsi_Cmnd *);
static void in2000_setup(char *, int *) in2000__INIT;
static int in2000_biosparam(struct scsi_device *, struct block_device *,
* will cause the mid layer to call us again later with the command)
*/
-static int i91u_queuecommand(struct scsi_cmnd *cmd,
+static int i91u_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata;
return 0;
}
+static DEF_SCSI_QCMD(i91u_queuecommand)
+
/**
* i91u_bus_reset - reset the SCSI bus
* @cmnd: Command block we want to trigger the reset for
}
},
{ /* CRoC */
- .mailbox = 0x00040,
+ .mailbox = 0x00044,
.cache_line_size = 0x20,
{
.set_interrupt_mask_reg = 0x00010,
sizeof(res->res_path));
res->bus = 0;
+ memcpy(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun,
+ sizeof(res->dev_lun.scsi_lun));
res->lun = scsilun_to_int(&res->dev_lun);
if (res->type == IPR_RES_TYPE_GENERIC_SCSI) {
ioa_cfg->max_devs_supported);
set_bit(res->target, ioa_cfg->target_ids);
}
-
- memcpy(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun,
- sizeof(res->dev_lun.scsi_lun));
} else if (res->type == IPR_RES_TYPE_IOAFP) {
res->bus = IPR_IOAFP_VIRTUAL_BUS;
res->target = 0;
if (res->ioa_cfg->sis64) {
if (!memcmp(&res->dev_id, &cfgtew->u.cfgte64->dev_id,
sizeof(cfgtew->u.cfgte64->dev_id)) &&
- !memcmp(&res->lun, &cfgtew->u.cfgte64->lun,
+ !memcmp(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun,
sizeof(cfgtew->u.cfgte64->lun))) {
return 1;
}
return;
}
+ if (ioa_cfg->sis64) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ ssleep(IPR_DUMP_DELAY_SECONDS);
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ }
+
start_addr = readl(ioa_cfg->ioa_mailbox);
if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(start_addr)) {
* SCSI_MLQUEUE_DEVICE_BUSY if device is busy
* SCSI_MLQUEUE_HOST_BUSY if host is busy
**/
-static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
+static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd,
void (*done) (struct scsi_cmnd *))
{
struct ipr_ioa_cfg *ioa_cfg;
return 0;
}
+static DEF_SCSI_QCMD(ipr_queuecommand)
+
/**
* ipr_ioctl - IOCTL handler
* @sdev: scsi device struct
list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
}
+/**
+ * ipr_reset_get_unit_check_job - Call to get the unit check buffer.
+ * @ipr_cmd: ipr command struct
+ *
+ * Description: This function will call to get the unit check buffer.
+ *
+ * Return value:
+ * IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_get_unit_check_job(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+ ENTER;
+ ioa_cfg->ioa_unit_checked = 0;
+ ipr_get_unit_check_buffer(ioa_cfg);
+ ipr_cmd->job_step = ipr_reset_alert;
+ ipr_reset_start_timer(ipr_cmd, 0);
+
+ LEAVE;
+ return IPR_RC_JOB_RETURN;
+}
+
/**
* ipr_reset_restore_cfg_space - Restore PCI config space.
* @ipr_cmd: ipr command struct
}
if (ioa_cfg->ioa_unit_checked) {
- ioa_cfg->ioa_unit_checked = 0;
- ipr_get_unit_check_buffer(ioa_cfg);
- ipr_cmd->job_step = ipr_reset_alert;
- ipr_reset_start_timer(ipr_cmd, 0);
- return IPR_RC_JOB_RETURN;
+ if (ioa_cfg->sis64) {
+ ipr_cmd->job_step = ipr_reset_get_unit_check_job;
+ ipr_reset_start_timer(ipr_cmd, IPR_DUMP_DELAY_TIMEOUT);
+ return IPR_RC_JOB_RETURN;
+ } else {
+ ioa_cfg->ioa_unit_checked = 0;
+ ipr_get_unit_check_buffer(ioa_cfg);
+ ipr_cmd->job_step = ipr_reset_alert;
+ ipr_reset_start_timer(ipr_cmd, 0);
+ return IPR_RC_JOB_RETURN;
+ }
}
if (ioa_cfg->in_ioa_bringdown) {
#define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ)
#define IPR_PCI_RESET_TIMEOUT (HZ / 2)
#define IPR_DUMP_TIMEOUT (15 * HZ)
+#define IPR_DUMP_DELAY_SECONDS 4
+#define IPR_DUMP_DELAY_TIMEOUT (IPR_DUMP_DELAY_SECONDS * HZ)
/*
* SCSI Literals
static int ips_release(struct Scsi_Host *);
static int ips_eh_abort(struct scsi_cmnd *);
static int ips_eh_reset(struct scsi_cmnd *);
-static int ips_queue(struct scsi_cmnd *, void (*)(struct scsi_cmnd *));
+static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *);
static const char *ips_info(struct Scsi_Host *);
static irqreturn_t do_ipsintr(int, void *);
static int ips_hainit(ips_ha_t *);
/* Linux obtains io_request_lock before calling this function */
/* */
/****************************************************************************/
-static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
+static int ips_queue_lck(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
{
ips_ha_t *ha;
ips_passthru_t *pt;
return (0);
}
+static DEF_SCSI_QCMD(ips_queue)
+
/****************************************************************************/
/* */
/* Routine Name: ips_biosparam */
struct fc_exch_pool {
u16 next_index;
u16 total_exches;
+
+ /* two cache of free slot in exch array */
+ u16 left;
+ u16 right;
+
spinlock_t lock;
struct list_head ex_list;
};
atomic_t non_bls_resp;
} stats;
};
-#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq)
/**
* struct fc_exch_mgr_anchor - primary structure for list of EMs
static void fc_exch_delete(struct fc_exch *ep)
{
struct fc_exch_pool *pool;
+ u16 index;
pool = ep->pool;
spin_lock_bh(&pool->lock);
WARN_ON(pool->total_exches <= 0);
pool->total_exches--;
- fc_exch_ptr_set(pool, (ep->xid - ep->em->min_xid) >> fc_cpu_order,
- NULL);
+
+ /* update cache of free slot */
+ index = (ep->xid - ep->em->min_xid) >> fc_cpu_order;
+ if (pool->left == FC_XID_UNKNOWN)
+ pool->left = index;
+ else if (pool->right == FC_XID_UNKNOWN)
+ pool->right = index;
+ else
+ pool->next_index = index;
+
+ fc_exch_ptr_set(pool, index, NULL);
list_del(&ep->ex_list);
spin_unlock_bh(&pool->lock);
fc_exch_release(ep); /* drop hold for exch in mp */
if (e_stat & ESB_ST_ABNORMAL)
rc = fc_exch_done_locked(ep);
spin_unlock_bh(&ep->ex_lock);
- if (!rc)
- fc_exch_delete(ep);
if (resp)
resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg);
+ if (!rc) {
+ /* delete the exchange if it's already being aborted */
+ fc_exch_delete(ep);
+ return;
+ }
fc_seq_exch_abort(sp, 2 * ep->r_a_tov);
goto done;
}
pool = per_cpu_ptr(mp->pool, cpu);
spin_lock_bh(&pool->lock);
put_cpu();
+
+ /* peek cache of free slot */
+ if (pool->left != FC_XID_UNKNOWN) {
+ index = pool->left;
+ pool->left = FC_XID_UNKNOWN;
+ goto hit;
+ }
+ if (pool->right != FC_XID_UNKNOWN) {
+ index = pool->right;
+ pool->right = FC_XID_UNKNOWN;
+ goto hit;
+ }
+
index = pool->next_index;
/* allocate new exch from pool */
while (fc_exch_ptr_get(pool, index)) {
goto err;
}
pool->next_index = index == mp->pool_max_index ? 0 : index + 1;
-
+hit:
fc_exch_hold(ep); /* hold for exch in mp */
spin_lock_init(&ep->ex_lock);
/*
list_for_each_entry(ema, &lport->ema_list, ema_list)
if ((!ema->match || ema->match(fp)) &&
- fc_seq_lookup_recip(lport, ema->mp, fp) != FC_RJT_NONE)
+ fc_seq_lookup_recip(lport, ema->mp, fp) == FC_RJT_NONE)
break;
return fr_seq(fp);
}
}
if (ep->esb_stat & ESB_ST_COMPLETE) {
atomic_inc(&mp->stats.xid_not_found);
- goto out;
+ goto rel;
}
if (ep->rxid == FC_XID_UNKNOWN)
ep->rxid = ntohs(fh->fh_rx_id);
goto free_mempool;
for_each_possible_cpu(cpu) {
pool = per_cpu_ptr(mp->pool, cpu);
+ pool->left = FC_XID_UNKNOWN;
+ pool->right = FC_XID_UNKNOWN;
spin_lock_init(&pool->lock);
INIT_LIST_HEAD(&pool->ex_list);
}
#define FC_SRB_READ (1 << 1)
#define FC_SRB_WRITE (1 << 0)
+/* constant added to e_d_tov timeout to get rec_tov value */
+#define REC_TOV_CONST 1
+
/*
* The SCp.ptr should be tested and set under the scsi_pkt_queue lock
*/
static void fc_fcp_complete_locked(struct fc_fcp_pkt *);
static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *);
static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *);
-static void fc_fcp_recovery(struct fc_fcp_pkt *);
+static void fc_fcp_recovery(struct fc_fcp_pkt *, u8 code);
static void fc_fcp_timeout(unsigned long);
static void fc_fcp_rec(struct fc_fcp_pkt *);
static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *);
#define FC_DATA_UNDRUN 7
#define FC_ERROR 8
#define FC_HRD_ERROR 9
-#define FC_CMD_RECOVERY 10
+#define FC_CRC_ERROR 10
+#define FC_TIMED_OUT 11
/*
* Error recovery timeout values.
*/
-#define FC_SCSI_ER_TIMEOUT (10 * HZ)
#define FC_SCSI_TM_TOV (10 * HZ)
-#define FC_SCSI_REC_TOV (2 * HZ)
#define FC_HOST_RESET_TIMEOUT (30 * HZ)
#define FC_CAN_QUEUE_PERIOD (60 * HZ)
void *buf;
struct scatterlist *sg;
u32 nents;
+ u8 host_bcode = FC_COMPLETE;
fh = fc_frame_header_get(fp);
offset = ntohl(fh->fh_parm_offset);
buf = fc_frame_payload_get(fp, 0);
/*
- * if this I/O is ddped then clear it
- * and initiate recovery since data
- * frames are expected to be placed
- * directly in that case.
+ * if this I/O is ddped then clear it and initiate recovery since data
+ * frames are expected to be placed directly in that case.
+ *
+ * Indicate error to scsi-ml because something went wrong with the
+ * ddp handling to get us here.
*/
if (fsp->xfer_ddp != FC_XID_UNKNOWN) {
fc_fcp_ddp_done(fsp);
+ FC_FCP_DBG(fsp, "DDP I/O in fc_fcp_recv_data set ERROR\n");
+ host_bcode = FC_ERROR;
goto err;
}
if (offset + len > fsp->data_len) {
goto crc_err;
FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx "
"data_len %x\n", len, offset, fsp->data_len);
+
+ /* Data is corrupted indicate scsi-ml should retry */
+ host_bcode = FC_DATA_OVRRUN;
goto err;
}
if (offset != fsp->xfer_len)
* If so, we need to retry the entire operation.
* Otherwise, ignore it.
*/
- if (fsp->state & FC_SRB_DISCONTIG)
+ if (fsp->state & FC_SRB_DISCONTIG) {
+ host_bcode = FC_CRC_ERROR;
goto err;
+ }
return;
}
}
fc_fcp_complete_locked(fsp);
return;
err:
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, host_bcode);
}
/**
}
lport->tt.exch_done(seq);
}
- fc_io_compl(fsp);
+ /*
+ * Some resets driven by SCSI are not I/Os and do not have
+ * SCSI commands associated with the requests. We should not
+ * call I/O completion if we do not have a SCSI command.
+ */
+ if (fsp->cmd)
+ fc_io_compl(fsp);
}
/**
return rc;
}
+/**
+ * get_fsp_rec_tov() - Helper function to get REC_TOV
+ * @fsp: the FCP packet
+ */
+static inline unsigned int get_fsp_rec_tov(struct fc_fcp_pkt *fsp)
+{
+ struct fc_rport *rport;
+ struct fc_rport_libfc_priv *rpriv;
+
+ rport = fsp->rport;
+ rpriv = rport->dd_data;
+
+ return rpriv->e_d_tov + REC_TOV_CONST;
+}
+
/**
* fc_fcp_cmd_send() - Send a FCP command
* @lport: The local port to send the command on
struct fc_rport_libfc_priv *rpriv;
const size_t len = sizeof(fsp->cdb_cmd);
int rc = 0;
+ unsigned int rec_tov;
if (fc_fcp_lock_pkt(fsp))
return 0;
fsp->seq_ptr = seq;
fc_fcp_pkt_hold(fsp); /* hold for fc_fcp_pkt_destroy */
+ rec_tov = get_fsp_rec_tov(fsp);
+
setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp);
- fc_fcp_timer_set(fsp,
- (fsp->tgt_flags & FC_RP_FLAGS_REC_SUPPORTED) ?
- FC_SCSI_REC_TOV : FC_SCSI_ER_TIMEOUT);
+
+ if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED)
+ fc_fcp_timer_set(fsp, rec_tov);
+
unlock:
fc_fcp_unlock_pkt(fsp);
return rc;
{
struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data;
struct fc_lport *lport = fsp->lp;
+ unsigned int rec_tov;
+
if (lport->tt.fcp_cmd_send(lport, fsp, fc_tm_done)) {
if (fsp->recov_retry++ >= FC_MAX_RECOV_RETRY)
return;
if (fc_fcp_lock_pkt(fsp))
return;
+ rec_tov = get_fsp_rec_tov(fsp);
setup_timer(&fsp->timer, fc_lun_reset_send, (unsigned long)fsp);
- fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
+ fc_fcp_timer_set(fsp, rec_tov);
fc_fcp_unlock_pkt(fsp);
}
}
*
* scsi-eh will escalate for when either happens.
*/
- return;
+ goto out;
}
if (fc_fcp_lock_pkt(fsp))
- return;
+ goto out;
/*
* raced with eh timeout handler.
*/
- if (!fsp->seq_ptr || !fsp->wait_for_comp) {
- spin_unlock_bh(&fsp->scsi_pkt_lock);
- return;
- }
+ if (!fsp->seq_ptr || !fsp->wait_for_comp)
+ goto out_unlock;
fh = fc_frame_header_get(fp);
if (fh->fh_type != FC_TYPE_BLS)
fc_fcp_resp(fsp, fp);
fsp->seq_ptr = NULL;
fsp->lp->tt.exch_done(seq);
- fc_frame_free(fp);
+out_unlock:
fc_fcp_unlock_pkt(fsp);
+out:
+ fc_frame_free(fp);
}
/**
if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED)
fc_fcp_rec(fsp);
- else if (time_after_eq(fsp->last_pkt_time + (FC_SCSI_ER_TIMEOUT / 2),
- jiffies))
- fc_fcp_timer_set(fsp, FC_SCSI_ER_TIMEOUT);
else if (fsp->state & FC_SRB_RCV_STATUS)
fc_fcp_complete_locked(fsp);
else
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_TIMED_OUT);
fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO;
unlock:
fc_fcp_unlock_pkt(fsp);
fc_fcp_complete_locked(fsp);
return;
}
+
fp = fc_fcp_frame_alloc(lport, sizeof(struct fc_els_rec));
if (!fp)
goto retry;
FC_FCTL_REQ, 0);
if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC,
fc_fcp_rec_resp, fsp,
- jiffies_to_msecs(FC_SCSI_REC_TOV))) {
+ 2 * lport->r_a_tov)) {
fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */
return;
}
retry:
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
- fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
+ fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp));
else
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_TIMED_OUT);
}
/**
* making progress.
*/
rpriv->flags &= ~FC_RP_FLAGS_REC_SUPPORTED;
- fc_fcp_timer_set(fsp, FC_SCSI_ER_TIMEOUT);
break;
case ELS_RJT_LOGIC:
case ELS_RJT_UNAB:
fc_fcp_retry_cmd(fsp);
break;
}
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_ERROR);
break;
}
} else if (opcode == ELS_LS_ACC) {
}
fc_fcp_srr(fsp, r_ctl, offset);
} else if (e_stat & ESB_ST_SEQ_INIT) {
-
+ unsigned int rec_tov = get_fsp_rec_tov(fsp);
/*
* The remote port has the initiative, so just
* keep waiting for it to complete.
*/
- fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
+ fc_fcp_timer_set(fsp, rec_tov);
} else {
/*
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
fc_fcp_rec(fsp);
else
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_ERROR);
break;
}
fc_fcp_unlock_pkt(fsp);
* fc_fcp_recovery() - Handler for fcp_pkt recovery
* @fsp: The FCP pkt that needs to be aborted
*/
-static void fc_fcp_recovery(struct fc_fcp_pkt *fsp)
+static void fc_fcp_recovery(struct fc_fcp_pkt *fsp, u8 code)
{
- fsp->status_code = FC_CMD_RECOVERY;
+ fsp->status_code = code;
fsp->cdb_status = 0;
fsp->io_status = 0;
/*
struct fcp_srr *srr;
struct fc_frame *fp;
u8 cdb_op;
+ unsigned int rec_tov;
rport = fsp->rport;
rpriv = rport->dd_data;
rpriv->local_port->port_id, FC_TYPE_FCP,
FC_FCTL_REQ, 0);
+ rec_tov = get_fsp_rec_tov(fsp);
seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL,
- fsp, jiffies_to_msecs(FC_SCSI_REC_TOV));
+ fsp, jiffies_to_msecs(rec_tov));
if (!seq)
goto retry;
{
struct fc_fcp_pkt *fsp = arg;
struct fc_frame_header *fh;
+ unsigned int rec_tov;
if (IS_ERR(fp)) {
fc_fcp_srr_error(fsp, fp);
switch (fc_frame_payload_op(fp)) {
case ELS_LS_ACC:
fsp->recov_retry = 0;
- fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
+ rec_tov = get_fsp_rec_tov(fsp);
+ fc_fcp_timer_set(fsp, rec_tov);
break;
case ELS_LS_RJT:
default:
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_ERROR);
break;
}
fc_fcp_unlock_pkt(fsp);
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
fc_fcp_rec(fsp);
else
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_TIMED_OUT);
break;
case -FC_EX_CLOSED: /* e.g., link failure */
/* fall through */
* This is the i/o strategy routine, called by the SCSI layer. This routine
* is called with the host_lock held.
*/
-int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
+static int fc_queuecommand_lck(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
{
struct fc_lport *lport;
struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
fsp->req_flags = FC_SRB_READ;
stats->InputRequests++;
- stats->InputMegabytes = fsp->data_len;
+ stats->InputBytes += fsp->data_len;
} else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) {
fsp->req_flags = FC_SRB_WRITE;
stats->OutputRequests++;
- stats->OutputMegabytes = fsp->data_len;
+ stats->OutputBytes += fsp->data_len;
} else {
fsp->req_flags = 0;
stats->ControlRequests++;
}
put_cpu();
- fsp->tgt_flags = rpriv->flags;
-
init_timer(&fsp->timer);
fsp->timer.data = (unsigned long)fsp;
spin_lock_irq(lport->host->host_lock);
return rc;
}
+
+DEF_SCSI_QCMD(fc_queuecommand)
EXPORT_SYMBOL(fc_queuecommand);
/**
break;
case FC_CMD_ABORTED:
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
- "due to FC_CMD_ABORTED\n");
+ "due to FC_CMD_ABORTED\n");
sc_cmd->result = (DID_ERROR << 16) | fsp->io_status;
break;
- case FC_CMD_RECOVERY:
- sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
- break;
case FC_CMD_RESET:
+ FC_FCP_DBG(fsp, "Returning DID_RESET to scsi-ml "
+ "due to FC_CMD_RESET\n");
sc_cmd->result = (DID_RESET << 16);
break;
case FC_HRD_ERROR:
+ FC_FCP_DBG(fsp, "Returning DID_NO_CONNECT to scsi-ml "
+ "due to FC_HRD_ERROR\n");
sc_cmd->result = (DID_NO_CONNECT << 16);
break;
+ case FC_CRC_ERROR:
+ FC_FCP_DBG(fsp, "Returning DID_PARITY to scsi-ml "
+ "due to FC_CRC_ERROR\n");
+ sc_cmd->result = (DID_PARITY << 16);
+ break;
+ case FC_TIMED_OUT:
+ FC_FCP_DBG(fsp, "Returning DID_BUS_BUSY to scsi-ml "
+ "due to FC_TIMED_OUT\n");
+ sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
+ break;
default:
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
"due to unknown error\n");
fsp = CMD_SP(sc_cmd);
if (!fsp) {
/* command completed while scsi eh was setting up */
- spin_unlock_irqrestore(lport->host->host_lock, flags);
+ spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
return SUCCESS;
}
/* grab a ref so the fsp and sc_cmd cannot be relased from under us */
#define FC_FCP_DBG(pkt, fmt, args...) \
FC_CHECK_LOGGING(FC_FCP_LOGGING, \
- printk(KERN_INFO "host%u: fcp: %6.6x: " fmt, \
+ { \
+ if ((pkt)->seq_ptr) { \
+ struct fc_exch *_ep = NULL; \
+ _ep = fc_seq_exch((pkt)->seq_ptr); \
+ printk(KERN_INFO "host%u: fcp: %6.6x: " \
+ "xid %04x-%04x: " fmt, \
(pkt)->lp->host->host_no, \
- pkt->rport->port_id, ##args))
+ (pkt)->rport->port_id, \
+ (_ep)->oxid, (_ep)->rxid, ##args); \
+ } else { \
+ printk(KERN_INFO "host%u: fcp: %6.6x: " fmt, \
+ (pkt)->lp->host->host_no, \
+ (pkt)->rport->port_id, ##args); \
+ } \
+ })
#define FC_EXCH_DBG(exch, fmt, args...) \
FC_CHECK_LOGGING(FC_EXCH_LOGGING, \
struct fc_lport *lport = shost_priv(shost);
struct timespec v0, v1;
unsigned int cpu;
+ u64 fcp_in_bytes = 0;
+ u64 fcp_out_bytes = 0;
fcoe_stats = &lport->host_stats;
memset(fcoe_stats, 0, sizeof(struct fc_host_statistics));
fcoe_stats->fcp_input_requests += stats->InputRequests;
fcoe_stats->fcp_output_requests += stats->OutputRequests;
fcoe_stats->fcp_control_requests += stats->ControlRequests;
- fcoe_stats->fcp_input_megabytes += stats->InputMegabytes;
- fcoe_stats->fcp_output_megabytes += stats->OutputMegabytes;
+ fcp_in_bytes += stats->InputBytes;
+ fcp_out_bytes += stats->OutputBytes;
fcoe_stats->link_failure_count += stats->LinkFailureCount;
}
+ fcoe_stats->fcp_input_megabytes = div_u64(fcp_in_bytes, 1000000);
+ fcoe_stats->fcp_output_megabytes = div_u64(fcp_out_bytes, 1000000);
fcoe_stats->lip_count = -1;
fcoe_stats->nos_count = -1;
fcoe_stats->loss_of_sync_count = -1;
info->sg = job->reply_payload.sg_list;
if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp,
- NULL, info, tov))
+ NULL, info, tov)) {
+ kfree(info);
return -ECOMM;
+ }
return 0;
}
info->sg = job->reply_payload.sg_list;
if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp,
- NULL, info, tov))
+ NULL, info, tov)) {
+ kfree(info);
return -ECOMM;
+ }
return 0;
}
FC_RPORT_DBG(rdata, "Received a FLOGI %s\n", fc_els_resp_type(fp));
if (fp == ERR_PTR(-FC_EX_CLOSED))
- return;
+ goto put;
mutex_lock(&rdata->rp_mutex);
fc_frame_free(fp);
err:
mutex_unlock(&rdata->rp_mutex);
+put:
kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
return;
bad:
}
EXPORT_SYMBOL_GPL(__iscsi_get_task);
-static void __iscsi_put_task(struct iscsi_task *task)
+void __iscsi_put_task(struct iscsi_task *task)
{
if (atomic_dec_and_test(&task->refcount))
iscsi_free_task(task);
}
+EXPORT_SYMBOL_GPL(__iscsi_put_task);
void iscsi_put_task(struct iscsi_task *task)
{
FAILURE_SESSION_NOT_READY,
};
-int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+static int iscsi_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
{
struct iscsi_cls_session *cls_session;
struct Scsi_Host *host;
spin_lock(host->host_lock);
return 0;
}
+
+DEF_SCSI_QCMD(iscsi_queuecommand)
EXPORT_SYMBOL_GPL(iscsi_queuecommand);
int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
#include <scsi/scsi_transport_sas.h>
#include "../scsi_sas_internal.h"
+static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy *phy)
+{
+ struct sas_ha_struct *sas_ha = phy->ha;
+
+ if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,
+ SAS_ADDR_SIZE) != 0 || (sas_ha->strict_wide_ports &&
+ memcmp(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE) != 0))
+ return false;
+ return true;
+}
+
/**
* sas_form_port -- add this phy to a port
* @phy: the phy of interest
unsigned long flags;
if (port) {
- if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,
- SAS_ADDR_SIZE) != 0)
+ if (!phy_is_wideport_member(port, phy))
sas_deform_port(phy);
else {
SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
port = sas_ha->sas_port[i];
spin_lock(&port->phy_list_lock);
if (*(u64 *) port->sas_addr &&
- memcmp(port->attached_sas_addr,
- phy->attached_sas_addr, SAS_ADDR_SIZE) == 0 &&
- port->num_phys > 0) {
+ phy_is_wideport_member(port, phy) && port->num_phys > 0) {
/* wide port */
SAS_DPRINTK("phy%d matched wide port%d\n", phy->id,
port->id);
* Note: XXX: Remove the host unlock/lock pair when SCSI Core can
* call us without holding an IRQ spinlock...
*/
-int sas_queuecommand(struct scsi_cmnd *cmd,
+static int sas_queuecommand_lck(struct scsi_cmnd *cmd,
void (*scsi_done)(struct scsi_cmnd *))
__releases(host->host_lock)
__acquires(dev->sata_dev.ap->lock)
return res;
}
+DEF_SCSI_QCMD(sas_queuecommand)
+
static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
{
struct sas_task *task = TO_SAS_TASK(cmd);
#define UNSOL_VALID 0x00000001
};
+#define LPFC_USER_LINK_SPEED_AUTO 0 /* auto select (default)*/
+#define LPFC_USER_LINK_SPEED_1G 1 /* 1 Gigabaud */
+#define LPFC_USER_LINK_SPEED_2G 2 /* 2 Gigabaud */
+#define LPFC_USER_LINK_SPEED_4G 4 /* 4 Gigabaud */
+#define LPFC_USER_LINK_SPEED_8G 8 /* 8 Gigabaud */
+#define LPFC_USER_LINK_SPEED_10G 10 /* 10 Gigabaud */
+#define LPFC_USER_LINK_SPEED_16G 16 /* 16 Gigabaud */
+#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_16G
+#define LPFC_USER_LINK_SPEED_BITMAP ((1 << LPFC_USER_LINK_SPEED_16G) | \
+ (1 << LPFC_USER_LINK_SPEED_10G) | \
+ (1 << LPFC_USER_LINK_SPEED_8G) | \
+ (1 << LPFC_USER_LINK_SPEED_4G) | \
+ (1 << LPFC_USER_LINK_SPEED_2G) | \
+ (1 << LPFC_USER_LINK_SPEED_1G) | \
+ (1 << LPFC_USER_LINK_SPEED_AUTO))
+#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16"
+
struct lpfc_hba {
/* SCSI interface function jump table entries */
int (*lpfc_new_scsi_buf)
(struct lpfc_vport *, int);
struct lpfc_scsi_buf * (*lpfc_get_scsi_buf)
- (struct lpfc_hba *);
+ (struct lpfc_hba *, struct lpfc_nodelist *);
int (*lpfc_scsi_prep_dma_buf)
(struct lpfc_hba *, struct lpfc_scsi_buf *);
void (*lpfc_scsi_unprep_dma_buf)
uint32_t hba_flag; /* hba generic flags */
#define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */
#define DEFER_ERATT 0x2 /* Deferred error attention in progress */
-#define HBA_FCOE_SUPPORT 0x4 /* HBA function supports FCOE */
+#define HBA_FCOE_MODE 0x4 /* HBA function in FCoE Mode */
#define HBA_SP_QUEUE_EVT 0x8 /* Slow-path qevt posted to worker thread*/
#define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */
#define FCP_XRI_ABORT_EVENT 0x20
#define HBA_FIP_SUPPORT 0x800 /* FIP support in HBA */
#define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */
#define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */
+#define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */
uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
struct lpfc_dmabuf slim2p;
/* HBA Config Parameters */
uint32_t cfg_ack0;
uint32_t cfg_enable_npiv;
+ uint32_t cfg_enable_rrq;
uint32_t cfg_topology;
uint32_t cfg_link_speed;
uint32_t cfg_cr_delay;
uint32_t total_scsi_bufs;
struct list_head lpfc_iocb_list;
uint32_t total_iocbq_bufs;
+ struct list_head active_rrq_list;
spinlock_t hbalock;
/* pci_mem_pools */
mempool_t *mbox_mem_pool;
mempool_t *nlp_mem_pool;
+ mempool_t *rrq_pool;
struct fc_host_statistics link_stats;
enum intr_type_t intr_type;
unsigned long skipped_hb;
struct timer_list hb_tmofunc;
uint8_t hb_outstanding;
+ struct timer_list rrq_tmr;
enum hba_temp_state over_temp_state;
/* ndlp reference management */
spinlock_t ndlp_lock;
#define LPFC_MIN_DEVLOSS_TMO 1
#define LPFC_MAX_DEVLOSS_TMO 255
-#define LPFC_MAX_LINK_SPEED 8
-#define LPFC_LINK_SPEED_BITMAP 0x00000117
-#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8"
-
/**
* lpfc_jedec_to_ascii - Hex to ascii convertor according to JEDEC rules
* @incr: integer to convert.
if (phba->sli.sli_flag & LPFC_MENLO_MAINT)
len += snprintf(buf + len, PAGE_SIZE-len,
" Menlo Maint Mode\n");
- else if (phba->fc_topology == TOPOLOGY_LOOP) {
+ else if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
if (vport->fc_flag & FC_PUBLIC_LOOP)
len += snprintf(buf + len, PAGE_SIZE-len,
" Public Loop\n");
lpfc_param_init(enable_npiv, 1, 0, 1);
static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
+int lpfc_enable_rrq;
+module_param(lpfc_enable_rrq, int, 0);
+MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality");
+lpfc_param_show(enable_rrq);
+lpfc_param_init(enable_rrq, 0, 0, 1);
+static DEVICE_ATTR(lpfc_enable_rrq, S_IRUGO, lpfc_enable_rrq_show, NULL);
+
/*
# lpfc_suppress_link_up: Bring link up at initialization
# 0x0 = bring link up (issue MBX_INIT_LINK)
/*
# lpfc_link_speed: Link speed selection for initializing the Fibre Channel
# connection.
-# 0 = auto select (default)
-# 1 = 1 Gigabaud
-# 2 = 2 Gigabaud
-# 4 = 4 Gigabaud
-# 8 = 8 Gigabaud
-# Value range is [0,8]. Default value is 0.
+# Value range is [0,16]. Default value is 0.
*/
-
/**
* lpfc_link_speed_set - Set the adapters link speed
* @phba: lpfc_hba pointer.
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- int val = 0;
+ int val = LPFC_USER_LINK_SPEED_AUTO;
int nolip = 0;
const char *val_buf = buf;
int err;
if (sscanf(val_buf, "%i", &val) != 1)
return -EINVAL;
- if (((val == LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
- ((val == LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
- ((val == LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
- ((val == LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
- ((val == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)))
+ if (((val == LPFC_USER_LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb))) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2879 lpfc_link_speed attribute cannot be set "
+ "to %d. Speed is not supported by this port.\n",
+ val);
return -EINVAL;
-
- if ((val >= 0 && val <= 8)
- && (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
+ }
+ if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) &&
+ (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) {
prev_val = phba->cfg_link_speed;
phba->cfg_link_speed = val;
if (nolip)
} else
return strlen(buf);
}
-
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0469 lpfc_link_speed attribute cannot be set to %d, "
- "allowed range is [0, 8]\n",
- phba->brd_no, val);
+ "0469 lpfc_link_speed attribute cannot be set to %d, "
+ "allowed values are ["LPFC_LINK_SPEED_STRING"]\n", val);
return -EINVAL;
}
static int
lpfc_link_speed_init(struct lpfc_hba *phba, int val)
{
- if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED)
- && (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
+ if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) &&
+ (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) {
phba->cfg_link_speed = val;
return 0;
}
"0405 lpfc_link_speed attribute cannot "
"be set to %d, allowed values are "
"["LPFC_LINK_SPEED_STRING"]\n", val);
- phba->cfg_link_speed = 0;
+ phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO;
return -EINVAL;
}
static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
- lpfc_link_speed_show, lpfc_link_speed_store);
+ lpfc_link_speed_show, lpfc_link_speed_store);
/*
# lpfc_aer_support: Support PCIe device Advanced Error Reporting (AER)
LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver.");
/*
-# lpfc_enable_hba_heartbeat: Enable HBA heartbeat timer..
+# lpfc_enable_hba_heartbeat: Disable HBA heartbeat timer..
# 0 = HBA Heartbeat disabled
# 1 = HBA Heartbeat enabled (default)
# Value range is [0,1]. Default value is 1.
*/
-LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
+LPFC_ATTR_R(enable_hba_heartbeat, 0, 0, 1, "Enable HBA Heartbeat.");
/*
# lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF)
&dev_attr_lpfc_fdmi_on,
&dev_attr_lpfc_max_luns,
&dev_attr_lpfc_enable_npiv,
+ &dev_attr_lpfc_enable_rrq,
&dev_attr_nport_evt_cnt,
&dev_attr_board_mode,
&dev_attr_max_vpi,
}
break;
case MBX_READ_SPARM64:
- case MBX_READ_LA:
- case MBX_READ_LA64:
+ case MBX_READ_TOPOLOGY:
case MBX_REG_LOGIN:
case MBX_REG_LOGIN64:
case MBX_CONFIG_PORT:
if (vport->port_type == LPFC_NPIV_PORT) {
fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
} else if (lpfc_is_link_up(phba)) {
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
if (vport->fc_flag & FC_PUBLIC_LOOP)
fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
else
if (lpfc_is_link_up(phba)) {
switch(phba->fc_linkspeed) {
- case LA_1GHZ_LINK:
- fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
+ case LPFC_LINK_SPEED_1GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
break;
- case LA_2GHZ_LINK:
- fc_host_speed(shost) = FC_PORTSPEED_2GBIT;
+ case LPFC_LINK_SPEED_2GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_2GBIT;
break;
- case LA_4GHZ_LINK:
- fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
+ case LPFC_LINK_SPEED_4GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
break;
- case LA_8GHZ_LINK:
- fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
+ case LPFC_LINK_SPEED_8GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
break;
- case LA_10GHZ_LINK:
- fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
+ case LPFC_LINK_SPEED_10GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
break;
- default:
- fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
+ case LPFC_LINK_SPEED_16GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_16GBIT;
+ break;
+ default:
+ fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
break;
}
} else
spin_lock_irq(shost->host_lock);
if ((vport->fc_flag & FC_FABRIC) ||
- ((phba->fc_topology == TOPOLOGY_LOOP) &&
+ ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) &&
(vport->fc_flag & FC_PUBLIC_LOOP)))
node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn);
else
hs->invalid_crc_count -= lso->invalid_crc_count;
hs->error_frames -= lso->error_frames;
- if (phba->hba_flag & HBA_FCOE_SUPPORT) {
+ if (phba->hba_flag & HBA_FCOE_MODE) {
hs->lip_count = -1;
hs->nos_count = (phba->link_events >> 1);
hs->nos_count -= lso->link_events;
- } else if (phba->fc_topology == TOPOLOGY_LOOP) {
+ } else if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
hs->lip_count = (phba->fc_eventTag >> 1);
hs->lip_count -= lso->link_events;
hs->nos_count = -1;
lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord;
lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
lso->error_frames = pmb->un.varRdLnk.crcCnt;
- if (phba->hba_flag & HBA_FCOE_SUPPORT)
+ if (phba->hba_flag & HBA_FCOE_MODE)
lso->link_events = (phba->link_events >> 1);
else
lso->link_events = (phba->fc_eventTag >> 1);
lpfc_link_speed_init(phba, lpfc_link_speed);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
+ lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count);
struct lpfc_iocbq *cmdiocbq,
struct lpfc_iocbq *rspiocbq)
{
- unsigned long iflags;
struct bsg_job_data *dd_data;
struct fc_bsg_job *job;
IOCB_t *rsp;
int rc = 0;
spin_lock_irqsave(&phba->ct_ev_lock, flags);
- dd_data = cmdiocbq->context1;
+ dd_data = cmdiocbq->context2;
if (!dd_data) {
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
return;
}
job = iocb->set_job;
job->dd_data = NULL; /* so timeout handler does not reply */
- spin_lock_irqsave(&phba->hbalock, iflags);
- cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
- if (cmdiocbq->context2 && rspiocbq)
- memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
- &rspiocbq->iocb, sizeof(IOCB_t));
- spin_unlock_irqrestore(&phba->hbalock, iflags);
-
bmp = iocb->bmp;
- rspiocbq = iocb->rspiocbq;
rsp = &rspiocbq->iocb;
- ndlp = iocb->ndlp;
+ ndlp = cmdiocbq->context1;
pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
rsp->un.genreq64.bdl.bdeSize;
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
- lpfc_sli_release_iocbq(phba, rspiocbq);
lpfc_sli_release_iocbq(phba, cmdiocbq);
lpfc_nlp_put(ndlp);
kfree(bmp);
struct ulp_bde64 *bpl = NULL;
uint32_t timeout;
struct lpfc_iocbq *cmdiocbq = NULL;
- struct lpfc_iocbq *rspiocbq = NULL;
IOCB_t *cmd;
- IOCB_t *rsp;
struct lpfc_dmabuf *bmp = NULL;
int request_nseg;
int reply_nseg;
}
cmd = &cmdiocbq->iocb;
- rspiocbq = lpfc_sli_get_iocbq(phba);
- if (!rspiocbq) {
- rc = -ENOMEM;
- goto free_cmdiocbq;
- }
-
- rsp = &rspiocbq->iocb;
bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
if (!bmp->virt) {
rc = -ENOMEM;
- goto free_rspiocbq;
+ goto free_cmdiocbq;
}
INIT_LIST_HEAD(&bmp->list);
cmd->ulpTimeout = timeout;
cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp;
- cmdiocbq->context1 = dd_data;
- cmdiocbq->context2 = rspiocbq;
+ cmdiocbq->context1 = ndlp;
+ cmdiocbq->context2 = dd_data;
dd_data->type = TYPE_IOCB;
dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
- dd_data->context_un.iocb.rspiocbq = rspiocbq;
dd_data->context_un.iocb.set_job = job;
dd_data->context_un.iocb.bmp = bmp;
- dd_data->context_un.iocb.ndlp = ndlp;
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
creg_val = readl(phba->HCregaddr);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-free_rspiocbq:
- lpfc_sli_release_iocbq(phba, rspiocbq);
free_cmdiocbq:
lpfc_sli_release_iocbq(phba, cmdiocbq);
free_bmp:
int rc = 0;
spin_lock_irqsave(&phba->ct_ev_lock, flags);
- dd_data = cmdiocbq->context1;
+ dd_data = cmdiocbq->context2;
/* normal completion and timeout crossed paths, already done */
if (!dd_data) {
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
ctiocb->context3 = bmp;
ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp;
- ctiocb->context1 = dd_data;
- ctiocb->context2 = NULL;
+ ctiocb->context2 = dd_data;
+ ctiocb->context1 = ndlp;
dd_data->type = TYPE_IOCB;
dd_data->context_un.iocb.cmdiocbq = ctiocb;
dd_data->context_un.iocb.rspiocbq = NULL;
* This function obtains a remote port login id so the diag loopback test
* can send and receive its own unsolicited CT command.
**/
-static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi)
+static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi)
{
LPFC_MBOXQ_t *mbox;
struct lpfc_dmabuf *dmabuff;
if (!mbox)
return -ENOMEM;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ *rpi = lpfc_sli4_alloc_rpi(phba);
status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID,
- (uint8_t *)&phba->pport->fc_sparam, mbox, 0);
+ (uint8_t *)&phba->pport->fc_sparam, mbox, *rpi);
if (status) {
mempool_free(mbox, phba->mbox_mem_pool);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba, *rpi);
return -ENOMEM;
}
kfree(dmabuff);
if (status != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba, *rpi);
return -ENODEV;
}
mempool_free(mbox, phba->mbox_mem_pool);
return -EIO;
}
-
mempool_free(mbox, phba->mbox_mem_pool);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba, rpi);
return 0;
}
uint32_t size;
uint32_t full_size;
size_t segment_len = 0, segment_offset = 0, current_offset = 0;
- uint16_t rpi;
+ uint16_t rpi = 0;
struct lpfc_iocbq *cmdiocbq, *rspiocbq;
IOCB_t *cmd, *rsp;
struct lpfc_sli_ct_request *ctreq;
goto loopback_test_exit;
}
- if (size >= BUF_SZ_4K) {
+ if (full_size >= BUF_SZ_4K) {
/*
* Allocate memory for ioctl data. If buffer is bigger than 64k,
* then we allocate 64k and re-use that buffer over and over to
* problem with GET_FCPTARGETMAPPING...
*/
if (size <= (64 * 1024))
- total_mem = size;
+ total_mem = full_size;
else
total_mem = 64 * 1024;
} else
sg_copy_to_buffer(job->request_payload.sg_list,
job->request_payload.sg_cnt,
ptr, size);
-
rc = lpfcdiag_loop_self_reg(phba, &rpi);
if (rc)
goto loopback_test_exit;
phba->wait_4_mlo_maint_flg = 1;
} else if (mb->un.varWords[0] == SETVAR_MLORST) {
phba->link_flag &= ~LS_LOOPBACK_MODE;
- phba->fc_topology = TOPOLOGY_PT_PT;
+ phba->fc_topology = LPFC_TOPOLOGY_PT_PT;
}
break;
case MBX_READ_SPARM64:
- case MBX_READ_LA:
- case MBX_READ_LA64:
+ case MBX_READ_TOPOLOGY:
case MBX_REG_LOGIN:
case MBX_REG_LOGIN64:
case MBX_CONFIG_PORT:
void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *, struct lpfc_dmabuf *);
+int lpfc_read_topology(struct lpfc_hba *, LPFC_MBOXQ_t *, struct lpfc_dmabuf *);
void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_issue_clear_la(struct lpfc_hba *, struct lpfc_vport *);
void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
- LPFC_MBOXQ_t *, uint32_t);
+ LPFC_MBOXQ_t *, uint16_t);
void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_linkdown_port(struct lpfc_vport *);
void lpfc_port_link_failure(struct lpfc_vport *);
-void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_read_topology(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
void lpfc_retry_pport_discovery(struct lpfc_hba *);
int lpfc_els_chk_latt(struct lpfc_vport *);
int lpfc_els_abort_flogi(struct lpfc_hba *);
int lpfc_initial_flogi(struct lpfc_vport *);
+void lpfc_issue_init_vfi(struct lpfc_vport *);
int lpfc_initial_fdisc(struct lpfc_vport *);
int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t);
int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
int __lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
struct lpfc_iocbq *, uint32_t);
uint32_t lpfc_drain_txq(struct lpfc_hba *);
-
-
+void lpfc_clr_rrq_active(struct lpfc_hba *, uint16_t, struct lpfc_node_rrq *);
+int lpfc_test_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *, uint16_t);
+void lpfc_handle_rrq_active(struct lpfc_hba *);
+int lpfc_send_rrq(struct lpfc_hba *, struct lpfc_node_rrq *);
+int lpfc_set_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *,
+ uint16_t, uint16_t, uint16_t);
+void lpfc_cleanup_wt_rrqs(struct lpfc_hba *);
+void lpfc_cleanup_vports_rrqs(struct lpfc_vport *);
+struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,
+ uint32_t);
#include "lpfc_vport.h"
#include "lpfc_debugfs.h"
-#define HBA_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver
- * incapable of reporting */
-#define HBA_PORTSPEED_1GBIT 1 /* 1 GBit/sec */
-#define HBA_PORTSPEED_2GBIT 2 /* 2 GBit/sec */
-#define HBA_PORTSPEED_4GBIT 8 /* 4 GBit/sec */
-#define HBA_PORTSPEED_8GBIT 16 /* 8 GBit/sec */
-#define HBA_PORTSPEED_10GBIT 4 /* 10 GBit/sec */
-#define HBA_PORTSPEED_NOT_NEGOTIATED 5 /* Speed not established */
+/* FDMI Port Speed definitions */
+#define HBA_PORTSPEED_1GBIT 0x0001 /* 1 GBit/sec */
+#define HBA_PORTSPEED_2GBIT 0x0002 /* 2 GBit/sec */
+#define HBA_PORTSPEED_4GBIT 0x0008 /* 4 GBit/sec */
+#define HBA_PORTSPEED_10GBIT 0x0004 /* 10 GBit/sec */
+#define HBA_PORTSPEED_8GBIT 0x0010 /* 8 GBit/sec */
+#define HBA_PORTSPEED_16GBIT 0x0020 /* 16 GBit/sec */
+#define HBA_PORTSPEED_UNKNOWN 0x0800 /* Unknown */
#define FOURBYTES 4
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
ae->un.SupportSpeed = 0;
+ if (phba->lmt & LMT_16Gb)
+ ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT;
if (phba->lmt & LMT_10Gb)
- ae->un.SupportSpeed = HBA_PORTSPEED_10GBIT;
+ ae->un.SupportSpeed |= HBA_PORTSPEED_10GBIT;
if (phba->lmt & LMT_8Gb)
ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT;
if (phba->lmt & LMT_4Gb)
ae->ad.bits.AttrType = be16_to_cpu(PORT_SPEED);
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
switch(phba->fc_linkspeed) {
- case LA_1GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
+ case LPFC_LINK_SPEED_1GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
break;
- case LA_2GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
+ case LPFC_LINK_SPEED_2GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
break;
- case LA_4GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
+ case LPFC_LINK_SPEED_4GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
break;
- case LA_8GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
+ case LPFC_LINK_SPEED_8GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
break;
- case LA_10GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
+ case LPFC_LINK_SPEED_10GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
break;
- default:
- ae->un.PortSpeed =
- HBA_PORTSPEED_UNKNOWN;
+ case LPFC_LINK_SPEED_16GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_16GBIT;
+ break;
+ default:
+ ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN;
break;
}
pab->ab.EntryCnt++;
} un;
};
+#define LPFC_SLI4_MAX_XRI 1024 /* Used to make the ndlp's xri_bitmap */
+#define XRI_BITMAP_ULONGS (LPFC_SLI4_MAX_XRI / BITS_PER_LONG)
+struct lpfc_node_rrqs {
+ unsigned long xri_bitmap[XRI_BITMAP_ULONGS];
+};
+
struct lpfc_nodelist {
struct list_head nlp_listp;
struct lpfc_name nlp_portname;
atomic_t cmd_pending;
uint32_t cmd_qdepth;
unsigned long last_change_time;
+ struct lpfc_node_rrqs active_rrqs;
struct lpfc_scsicmd_bkt *lat_data; /* Latency data */
};
+struct lpfc_node_rrq {
+ struct list_head list;
+ uint16_t xritag;
+ uint16_t send_rrq;
+ uint16_t rxid;
+ uint32_t nlp_DID; /* FC D_ID of entry */
+ struct lpfc_vport *vport;
+ struct lpfc_nodelist *ndlp;
+ unsigned long rrq_stop_time;
+};
/* Defines for nlp_flag (uint32) */
#define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */
#define NLP_NODEV_REMOVE 0x08000000 /* Defer removal till discovery ends */
#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */
#define NLP_SC_REQ 0x20000000 /* Target requires authentication */
-#define NLP_RPI_VALID 0x80000000 /* nlp_rpi is valid */
+#define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */
/* ndlp usage management macros */
#define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \
err = 4;
goto fail;
}
- rc = lpfc_reg_rpi(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, 0);
+ rc = lpfc_reg_rpi(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
+ ndlp->nlp_rpi);
if (rc) {
err = 5;
goto fail_free_mbox;
phba->fc_edtovResol = sp->cmn.edtovResolution;
phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_PUBLIC_LOOP;
spin_unlock_irq(shost->host_lock);
if (lpfc_els_retry(phba, cmdiocb, rspiocb))
goto out;
+ /* FLOGI failure */
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0100 FLOGI failure Status:x%x/x%x TMO:x%x\n",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout);
+
/* FLOGI failed, so there is no fabric */
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
*/
if (phba->alpa_map[0] == 0) {
vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (!(vport->fc_flag & FC_VFI_REGISTERED) ||
+ (vport->fc_prevDID != vport->fc_myDID))) {
+ if (vport->fc_flag & FC_VFI_REGISTERED)
+ lpfc_sli4_unreg_all_rpis(vport);
+ lpfc_issue_reg_vfi(vport);
+ lpfc_nlp_put(ndlp);
+ goto out;
+ }
}
-
- /* FLOGI failure */
- lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
- "0100 FLOGI failure Status:x%x/x%x TMO:x%x\n",
- irsp->ulpStatus, irsp->un.ulpWord[4],
- irsp->ulpTimeout);
goto flogifail;
}
spin_lock_irq(shost->host_lock);
*/
if (sp->cmn.fPort)
rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
- else if (!(phba->hba_flag & HBA_FCOE_SUPPORT))
+ else if (!(phba->hba_flag & HBA_FCOE_MODE))
rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
else {
lpfc_printf_vlog(vport, KERN_ERR,
if (sp->cmn.fcphHigh < FC_PH3)
sp->cmn.fcphHigh = FC_PH3;
- if (phba->sli_rev == LPFC_SLI_REV4) {
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_0)) {
elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1);
elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1);
/* FLOGI needs to be 3 for WQE FCFI */
icmd->ulpCt_l = 0;
}
- if (phba->fc_topology != TOPOLOGY_LOOP) {
+ if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) {
icmd->un.elsreq64.myID = 0;
icmd->un.elsreq64.fl = 1;
}
uint32_t rc, keepDID = 0;
int put_node;
int put_rport;
+ struct lpfc_node_rrqs rrq;
/* Fabric nodes can have the same WWPN so we don't bother searching
* by WWPN. Just return the ndlp that was given to us.
if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp))
return ndlp;
+ memset(&rrq.xri_bitmap, 0, sizeof(new_ndlp->active_rrqs.xri_bitmap));
if (!new_ndlp) {
rc = memcmp(&ndlp->nlp_portname, name,
if (!new_ndlp)
return ndlp;
keepDID = new_ndlp->nlp_DID;
- } else
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&rrq.xri_bitmap,
+ &new_ndlp->active_rrqs.xri_bitmap,
+ sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ } else {
keepDID = new_ndlp->nlp_DID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&rrq.xri_bitmap,
+ &new_ndlp->active_rrqs.xri_bitmap,
+ sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ }
lpfc_unreg_rpi(vport, new_ndlp);
new_ndlp->nlp_DID = ndlp->nlp_DID;
new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(new_ndlp->active_rrqs.xri_bitmap,
+ &ndlp->active_rrqs.xri_bitmap,
+ sizeof(ndlp->active_rrqs.xri_bitmap));
if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
/* Two ndlps cannot have the same did on the nodelist */
ndlp->nlp_DID = keepDID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&ndlp->active_rrqs.xri_bitmap,
+ &rrq.xri_bitmap,
+ sizeof(ndlp->active_rrqs.xri_bitmap));
lpfc_drop_node(vport, ndlp);
}
else {
lpfc_unreg_rpi(vport, ndlp);
/* Two ndlps cannot have the same did */
ndlp->nlp_DID = keepDID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&ndlp->active_rrqs.xri_bitmap,
+ &rrq.xri_bitmap,
+ sizeof(ndlp->active_rrqs.xri_bitmap));
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
/* Since we are swapping the ndlp passed in with the new one
* and the did has already been swapped, copy over the
}
}
+/**
+ * lpfc_cmpl_els_rrq - Completion handled for els RRQs.
+ * @phba: pointer to lpfc hba data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @rspiocb: pointer to lpfc response iocb data structure.
+ *
+ * This routine will call the clear rrq function to free the rrq and
+ * clear the xri's bit in the ndlp's xri_bitmap. If the ndlp does not
+ * exist then the clear_rrq is still called because the rrq needs to
+ * be freed.
+ **/
+
+static void
+lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ IOCB_t *irsp;
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_node_rrq *rrq;
+
+ /* we pass cmdiocb to state machine which needs rspiocb as well */
+ rrq = cmdiocb->context_un.rrq;
+ cmdiocb->context_un.rsp_iocb = rspiocb;
+
+ irsp = &rspiocb->iocb;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "RRQ cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->un.elsreq64.remoteID);
+
+ ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || ndlp != rrq->ndlp) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2882 RRQ completes to NPort x%x "
+ "with no ndlp. Data: x%x x%x x%x\n",
+ irsp->un.elsreq64.remoteID,
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpIoTag);
+ goto out;
+ }
+
+ /* rrq completes to NPort <nlp_DID> */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2880 RRQ completes to NPort x%x "
+ "Data: x%x x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout, rrq->xritag, rrq->rxid);
+
+ if (irsp->ulpStatus) {
+ /* Check for retry */
+ /* RRQ failed Don't print the vport to vport rjts */
+ if (irsp->ulpStatus != IOSTAT_LS_RJT ||
+ (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) &&
+ ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) ||
+ (phba)->pport->cfg_log_verbose & LOG_ELS)
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2881 RRQ failure DID:%06X Status:x%x/x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
+ }
+out:
+ if (rrq)
+ lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ lpfc_els_free_iocb(phba, cmdiocb);
+ return;
+}
/**
* lpfc_cmpl_els_plogi - Completion callback function for plogi
* @phba: pointer to lpfc hba data structure.
if (cmd == ELS_CMD_FLOGI) {
if (PCI_DEVICE_ID_HORNET ==
phba->pcidev->device) {
- phba->fc_topology = TOPOLOGY_LOOP;
+ phba->fc_topology = LPFC_TOPOLOGY_LOOP;
phba->pport->fc_myDID = 0;
phba->alpa_map[0] = 0;
phba->alpa_map[1] = 0;
retry = 1;
if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) &&
- (phba->fc_topology != TOPOLOGY_LOOP) &&
+ (phba->fc_topology != LPFC_TOPOLOGY_LOOP) &&
!lpfc_error_lost_link(irsp)) {
/* FLOGI retry policy */
retry = 1;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
- /*
- * This routine is used to register and unregister in previous SLI
- * modes.
- */
- if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
- (phba->sli_rev == LPFC_SLI_REV4))
- lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
-
pmb->context1 = NULL;
pmb->context2 = NULL;
return 0;
}
+/**
+ * lpfc_els_clear_rrq - Clear the rq that this rrq describes.
+ * @vport: pointer to a virtual N_Port data structure.
+ * @iocb: pointer to the lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * Return
+ **/
+static void
+lpfc_els_clear_rrq(struct lpfc_vport *vport,
+ struct lpfc_iocbq *iocb, struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_hba *phba = vport->phba;
+ uint8_t *pcmd;
+ struct RRQ *rrq;
+ uint16_t rxid;
+ struct lpfc_node_rrq *prrq;
+
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) iocb->context2)->virt);
+ pcmd += sizeof(uint32_t);
+ rrq = (struct RRQ *)pcmd;
+ rxid = bf_get(rrq_oxid, rrq);
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2883 Clear RRQ for SID:x%x OXID:x%x RXID:x%x"
+ " x%x x%x\n",
+ bf_get(rrq_did, rrq),
+ bf_get(rrq_oxid, rrq),
+ rxid,
+ iocb->iotag, iocb->iocb.ulpContext);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Clear RRQ: did:x%x flg:x%x exchg:x%.08x",
+ ndlp->nlp_DID, ndlp->nlp_flag, rrq->rrq_exchg);
+ prrq = lpfc_get_active_rrq(vport, rxid, ndlp->nlp_DID);
+ if (prrq)
+ lpfc_clr_rrq_active(phba, rxid, prrq);
+ return;
+}
+
/**
* lpfc_els_rsp_echo_acc - Issue echo acc response
* @vport: pointer to a virtual N_Port data structure.
lpfc_set_disctmo(vport);
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/* We should never receive a FLOGI in loop mode, ignore it */
did = icmd->un.elsreq64.remoteID;
struct lpfc_nodelist *ndlp)
{
lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+ if (vport->phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_els_clear_rrq(vport, cmdiocb, ndlp);
}
/**
pcmd += sizeof(uint32_t); /* Skip past command */
rps_rsp = (RPS_RSP *)pcmd;
- if (phba->fc_topology != TOPOLOGY_LOOP)
+ if (phba->fc_topology != LPFC_TOPOLOGY_LOOP)
status = 0x10;
else
status = 0x8;
return 0;
}
+/* lpfc_issue_els_rrq - Process an unsolicited rps iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: pointer to a node-list data structure.
+ * @did: DID of the target.
+ * @rrq: Pointer to the rrq struct.
+ *
+ * Build a ELS RRQ command and send it to the target. If the issue_iocb is
+ * Successful the the completion handler will clear the RRQ.
+ *
+ * Return codes
+ * 0 - Successfully sent rrq els iocb.
+ * 1 - Failed to send rrq els iocb.
+ **/
+static int
+lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ uint32_t did, struct lpfc_node_rrq *rrq)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct RRQ *els_rrq;
+ IOCB_t *icmd;
+ struct lpfc_iocbq *elsiocb;
+ uint8_t *pcmd;
+ uint16_t cmdsize;
+ int ret;
+
+
+ if (ndlp != rrq->ndlp)
+ ndlp = rrq->ndlp;
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+ return 1;
+
+ /* If ndlp is not NULL, we will bump the reference count on it */
+ cmdsize = (sizeof(uint32_t) + sizeof(struct RRQ));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, did,
+ ELS_CMD_RRQ);
+ if (!elsiocb)
+ return 1;
+
+ icmd = &elsiocb->iocb;
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+ /* For RRQ request, remainder of payload is Exchange IDs */
+ *((uint32_t *) (pcmd)) = ELS_CMD_RRQ;
+ pcmd += sizeof(uint32_t);
+ els_rrq = (struct RRQ *) pcmd;
+
+ bf_set(rrq_oxid, els_rrq, rrq->xritag);
+ bf_set(rrq_rxid, els_rrq, rrq->rxid);
+ bf_set(rrq_did, els_rrq, vport->fc_myDID);
+ els_rrq->rrq = cpu_to_be32(els_rrq->rrq);
+ els_rrq->rrq_exchg = cpu_to_be32(els_rrq->rrq_exchg);
+
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue RRQ: did:x%x",
+ did, rrq->xritag, rrq->rxid);
+ elsiocb->context_un.rrq = rrq;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rrq;
+ ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
+
+ if (ret == IOCB_ERROR) {
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * lpfc_send_rrq - Sends ELS RRQ if needed.
+ * @phba: pointer to lpfc hba data structure.
+ * @rrq: pointer to the active rrq.
+ *
+ * This routine will call the lpfc_issue_els_rrq if the rrq is
+ * still active for the xri. If this function returns a failure then
+ * the caller needs to clean up the RRQ by calling lpfc_clr_active_rrq.
+ *
+ * Returns 0 Success.
+ * 1 Failure.
+ **/
+int
+lpfc_send_rrq(struct lpfc_hba *phba, struct lpfc_node_rrq *rrq)
+{
+ struct lpfc_nodelist *ndlp = lpfc_findnode_did(rrq->vport,
+ rrq->nlp_DID);
+ if (lpfc_test_rrq_active(phba, ndlp, rrq->xritag))
+ return lpfc_issue_els_rrq(rrq->vport, ndlp,
+ rrq->nlp_DID, rrq);
+ else
+ return 1;
+}
+
/**
* lpfc_els_rsp_rpl_acc - Issue an accept rpl els command
* @vport: pointer to a host virtual N_Port data structure.
(memcmp(&phba->fc_fabparam.portName, &fp->FportName,
sizeof(struct lpfc_name)))) {
/* This port has switched fabrics. FLOGI is required */
- lpfc_initial_flogi(vport);
+ lpfc_issue_init_vfi(vport);
} else {
/* FAN verified - skip FLOGI */
vport->fc_myDID = vport->fc_prevDID;
cmd, did, vport->port_state);
/* Unsupported ELS command, reject */
- rjt_err = LSRJT_INVALID_CMD;
+ rjt_err = LSRJT_CMD_UNSUPPORTED;
/* Unknown ELS command <elsCmd> received from NPORT <did> */
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
if (!ndlp) {
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp) {
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
lpfc_disc_start(vport);
return;
}
} else if (!NLP_CHK_NODE_ACT(ndlp)) {
ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE);
if (!ndlp) {
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
lpfc_disc_start(vport);
return;
}
}
if (vport->cfg_fdmi_on) {
- ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
- GFP_KERNEL);
+ /* If this is the first time, allocate an ndlp and initialize
+ * it. Otherwise, make sure the node is enabled and then do the
+ * login.
+ */
+ ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID);
+ if (!ndlp_fdmi) {
+ ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
+ GFP_KERNEL);
+ if (ndlp_fdmi) {
+ lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
+ ndlp_fdmi->nlp_type |= NLP_FABRIC;
+ } else
+ return;
+ }
+ if (!NLP_CHK_NODE_ACT(ndlp_fdmi))
+ ndlp_fdmi = lpfc_enable_node(vport,
+ ndlp_fdmi,
+ NLP_STE_NPR_NODE);
+
if (ndlp_fdmi) {
- lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
- ndlp_fdmi->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp_fdmi,
- NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
- 0);
+ NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0);
}
}
- return;
}
/**
spin_unlock_irq(shost->host_lock);
if (vport->port_type == LPFC_PHYSICAL_PORT
&& !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
- lpfc_initial_flogi(vport);
+ lpfc_issue_init_vfi(vport);
else
lpfc_initial_fdisc(vport);
break;
vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;
vport->fc_flag |= FC_FABRIC;
- if (vport->phba->fc_topology == TOPOLOGY_LOOP)
+ if (vport->phba->fc_topology == LPFC_TOPOLOGY_LOOP)
vport->fc_flag |= FC_PUBLIC_LOOP;
spin_unlock_irq(shost->host_lock);
icmd->un.elsreq64.myID = 0;
icmd->un.elsreq64.fl = 1;
- if (phba->sli_rev == LPFC_SLI_REV4) {
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_0)) {
/* FDISC needs to be 1 for WQE VPI */
elsiocb->iocb.ulpCt_h = (SLI4_CT_VPI >> 1) & 1;
elsiocb->iocb.ulpCt_l = SLI4_CT_VPI & 1 ;
struct sli4_wcqe_xri_aborted *axri)
{
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
+ uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
+
struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
unsigned long iflag = 0;
+ struct lpfc_nodelist *ndlp;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
&phba->sli4_hba.lpfc_abts_els_sgl_list, list) {
if (sglq_entry->sli4_xritag == xri) {
list_del(&sglq_entry->list);
+ ndlp = sglq_entry->ndlp;
+ sglq_entry->ndlp = NULL;
list_add_tail(&sglq_entry->list,
&phba->sli4_hba.lpfc_sgl_list);
sglq_entry->state = SGL_FREED;
spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
/* Check if TXQ queue needs to be serviced */
if (pring->txq_cnt)
/* Process SLI4 events */
if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
+ if (phba->hba_flag & HBA_RRQ_ACTIVE)
+ lpfc_handle_rrq_active(phba);
if (phba->hba_flag & FCP_XRI_ABORT_EVENT)
lpfc_sli4_fcp_xri_abort_event_proc(phba);
if (phba->hba_flag & ELS_XRI_ABORT_EVENT)
struct lpfc_vport **vports;
int i;
+ lpfc_cleanup_wt_rrqs(phba);
phba->link_state = LPFC_LINK_UP;
/* Unblock fabric iocbs if they are blocked */
mempool_free(pmb, phba->mbox_mem_pool);
- if (phba->fc_topology == TOPOLOGY_LOOP &&
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP &&
vport->fc_flag & FC_PUBLIC_LOOP &&
!(vport->fc_flag & FC_LBIT)) {
/* Need to wait for FAN - use discovery timer
/* Start discovery by sending a FLOGI. port_state is identically
* LPFC_FLOGI while waiting for FLOGI cmpl
*/
- if (vport->port_state != LPFC_FLOGI) {
+ if (vport->port_state != LPFC_FLOGI)
lpfc_initial_flogi(vport);
- }
return;
out:
if (vport->port_state != LPFC_FLOGI) {
phba->hba_flag |= FCF_RR_INPROG;
spin_unlock_irq(&phba->hbalock);
- lpfc_initial_flogi(vport);
+ lpfc_issue_init_vfi(vport);
goto out;
}
spin_unlock_irq(&phba->hbalock);
if (phba->pport->port_state != LPFC_FLOGI) {
phba->hba_flag |= FCF_RR_INPROG;
spin_unlock_irq(&phba->hbalock);
- lpfc_initial_flogi(phba->pport);
+ lpfc_issue_init_vfi(phba->pport);
return;
}
spin_unlock_irq(&phba->hbalock);
phba->fcf.current_rec.fcf_indx, fcf_index);
/* Wait 500 ms before retrying FLOGI to current FCF */
msleep(500);
- lpfc_initial_flogi(phba->pport);
+ lpfc_issue_init_vfi(phba->pport);
goto out;
}
lpfc_sli4_mbox_cmd_free(phba, mboxq);
}
+/**
+ * lpfc_init_vfi_cmpl - Completion handler for init_vfi mbox command.
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to mailbox data structure.
+ *
+ * This function handles completion of init vfi mailbox command.
+ */
+void
+lpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+ struct lpfc_vport *vport = mboxq->vport;
+
+ if (mboxq->u.mb.mbxStatus && (mboxq->u.mb.mbxStatus != 0x4002)) {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_MBOX,
+ "2891 Init VFI mailbox failed 0x%x\n",
+ mboxq->u.mb.mbxStatus);
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ return;
+ }
+ lpfc_initial_flogi(vport);
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ return;
+}
+
+/**
+ * lpfc_issue_init_vfi - Issue init_vfi mailbox command.
+ * @vport: pointer to lpfc_vport data structure.
+ *
+ * This function issue a init_vfi mailbox command to initialize the VFI and
+ * VPI for the physical port.
+ */
+void
+lpfc_issue_init_vfi(struct lpfc_vport *vport)
+{
+ LPFC_MBOXQ_t *mboxq;
+ int rc;
+ struct lpfc_hba *phba = vport->phba;
+
+ mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mboxq) {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_MBOX, "2892 Failed to allocate "
+ "init_vfi mailbox\n");
+ return;
+ }
+ lpfc_init_vfi(mboxq, vport);
+ mboxq->mbox_cmpl = lpfc_init_vfi_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_MBOX, "2893 Failed to issue init_vfi mailbox\n");
+ mempool_free(mboxq, vport->phba->mbox_mem_pool);
+ }
+}
+
/**
* lpfc_init_vpi_cmpl - Completion handler for init_vpi mbox command.
* @phba: pointer to lpfc hba data structure.
FC_VPORT_FAILED);
continue;
}
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
lpfc_vport_set_state(vports[i],
FC_VPORT_LINKDOWN);
continue;
"2018 REG_VFI mbxStatus error x%x "
"HBA state x%x\n",
mboxq->u.mb.mbxStatus, vport->port_state);
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/* FLOGI failed, use loop map to make discovery list */
lpfc_disc_list_loopmap(vport);
/* Start discovery */
spin_unlock_irq(shost->host_lock);
if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
- lpfc_start_fdiscs(phba);
- lpfc_do_scr_ns_plogi(phba, vport);
+ /* For private loop just start discovery and we are done. */
+ if ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) &&
+ (phba->alpa_map[0] == 0) &&
+ !(vport->fc_flag & FC_PUBLIC_LOOP)) {
+ /* Use loop map to make discovery list */
+ lpfc_disc_list_loopmap(vport);
+ /* Start discovery */
+ lpfc_disc_start(vport);
+ } else {
+ lpfc_start_fdiscs(phba);
+ lpfc_do_scr_ns_plogi(phba, vport);
+ }
}
fail_free_mem:
}
static void
-lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
+lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
{
struct lpfc_vport *vport = phba->pport;
LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL;
struct fcf_record *fcf_record;
spin_lock_irq(&phba->hbalock);
- switch (la->UlnkSpeed) {
- case LA_1GHZ_LINK:
- phba->fc_linkspeed = LA_1GHZ_LINK;
- break;
- case LA_2GHZ_LINK:
- phba->fc_linkspeed = LA_2GHZ_LINK;
- break;
- case LA_4GHZ_LINK:
- phba->fc_linkspeed = LA_4GHZ_LINK;
- break;
- case LA_8GHZ_LINK:
- phba->fc_linkspeed = LA_8GHZ_LINK;
- break;
- case LA_10GHZ_LINK:
- phba->fc_linkspeed = LA_10GHZ_LINK;
+ switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
+ case LPFC_LINK_SPEED_1GHZ:
+ case LPFC_LINK_SPEED_2GHZ:
+ case LPFC_LINK_SPEED_4GHZ:
+ case LPFC_LINK_SPEED_8GHZ:
+ case LPFC_LINK_SPEED_10GHZ:
+ case LPFC_LINK_SPEED_16GHZ:
+ phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
break;
default:
- phba->fc_linkspeed = LA_UNKNW_LINK;
+ phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
break;
}
- phba->fc_topology = la->topology;
+ phba->fc_topology = bf_get(lpfc_mbx_read_top_topology, la);
phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
/* if npiv is enabled and this adapter supports npiv log
"1309 Link Up Event npiv not supported in loop "
"topology\n");
/* Get Loop Map information */
- if (la->il)
+ if (bf_get(lpfc_mbx_read_top_il, la))
vport->fc_flag |= FC_LBIT;
- vport->fc_myDID = la->granted_AL_PA;
- i = la->un.lilpBde64.tus.f.bdeSize;
+ vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la);
+ i = la->lilpBde64.tus.f.bdeSize;
if (i == 0) {
phba->alpa_map[0] = 0;
goto out;
}
- if (!(phba->hba_flag & HBA_FCOE_SUPPORT)) {
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!cfglink_mbox)
goto out;
/*
- * This routine handles processing a READ_LA mailbox
+ * This routine handles processing a READ_TOPOLOGY mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
* as the completion routine when the command is
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- READ_LA_VAR *la;
+ struct lpfc_mbx_read_top *la;
MAILBOX_t *mb = &pmb->u.mb;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
mb->mbxStatus, vport->port_state);
lpfc_mbx_issue_link_down(phba);
phba->link_state = LPFC_HBA_ERROR;
- goto lpfc_mbx_cmpl_read_la_free_mbuf;
+ goto lpfc_mbx_cmpl_read_topology_free_mbuf;
}
- la = (READ_LA_VAR *) &pmb->u.mb.un.varReadLA;
+ la = (struct lpfc_mbx_read_top *) &pmb->u.mb.un.varReadTop;
memcpy(&phba->alpa_map[0], mp->virt, 128);
spin_lock_irq(shost->host_lock);
- if (la->pb)
+ if (bf_get(lpfc_mbx_read_top_pb, la))
vport->fc_flag |= FC_BYPASSED_MODE;
else
vport->fc_flag &= ~FC_BYPASSED_MODE;
if ((phba->fc_eventTag < la->eventTag) ||
(phba->fc_eventTag == la->eventTag)) {
phba->fc_stat.LinkMultiEvent++;
- if (la->attType == AT_LINK_UP)
+ if (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP)
if (phba->fc_eventTag != 0)
lpfc_linkdown(phba);
}
phba->fc_eventTag = la->eventTag;
spin_lock_irq(&phba->hbalock);
- if (la->mm)
+ if (bf_get(lpfc_mbx_read_top_mm, la))
phba->sli.sli_flag |= LPFC_MENLO_MAINT;
else
phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;
spin_unlock_irq(&phba->hbalock);
phba->link_events++;
- if (la->attType == AT_LINK_UP && (!la->mm)) {
+ if ((bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP) &&
+ (!bf_get(lpfc_mbx_read_top_mm, la))) {
phba->fc_stat.LinkUp++;
if (phba->link_flag & LS_LOOPBACK_MODE) {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1306 Link Up Event in loop back mode "
"x%x received Data: x%x x%x x%x x%x\n",
la->eventTag, phba->fc_eventTag,
- la->granted_AL_PA, la->UlnkSpeed,
+ bf_get(lpfc_mbx_read_top_alpa_granted,
+ la),
+ bf_get(lpfc_mbx_read_top_link_spd, la),
phba->alpa_map[0]);
} else {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1303 Link Up Event x%x received "
"Data: x%x x%x x%x x%x x%x x%x %d\n",
la->eventTag, phba->fc_eventTag,
- la->granted_AL_PA, la->UlnkSpeed,
+ bf_get(lpfc_mbx_read_top_alpa_granted,
+ la),
+ bf_get(lpfc_mbx_read_top_link_spd, la),
phba->alpa_map[0],
- la->mm, la->fa,
+ bf_get(lpfc_mbx_read_top_mm, la),
+ bf_get(lpfc_mbx_read_top_fa, la),
phba->wait_4_mlo_maint_flg);
}
lpfc_mbx_process_link_up(phba, la);
- } else if (la->attType == AT_LINK_DOWN) {
+ } else if (bf_get(lpfc_mbx_read_top_att_type, la) ==
+ LPFC_ATT_LINK_DOWN) {
phba->fc_stat.LinkDown++;
if (phba->link_flag & LS_LOOPBACK_MODE) {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"Data: x%x x%x x%x x%x x%x\n",
la->eventTag, phba->fc_eventTag,
phba->pport->port_state, vport->fc_flag,
- la->mm, la->fa);
+ bf_get(lpfc_mbx_read_top_mm, la),
+ bf_get(lpfc_mbx_read_top_fa, la));
}
lpfc_mbx_issue_link_down(phba);
}
- if (la->mm && la->attType == AT_LINK_UP) {
+ if ((bf_get(lpfc_mbx_read_top_mm, la)) &&
+ (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP)) {
if (phba->link_state != LPFC_LINK_DOWN) {
phba->fc_stat.LinkDown++;
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
}
}
- if (la->fa) {
- if (la->mm)
+ if (bf_get(lpfc_mbx_read_top_fa, la)) {
+ if (bf_get(lpfc_mbx_read_top_mm, la))
lpfc_issue_clear_la(phba, vport);
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
- "1311 fa %d\n", la->fa);
+ "1311 fa %d\n",
+ bf_get(lpfc_mbx_read_top_fa, la));
}
-lpfc_mbx_cmpl_read_la_free_mbuf:
+lpfc_mbx_cmpl_read_topology_free_mbuf:
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
- if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL ||
- ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) {
+ if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL ||
+ ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) {
/* We rcvd a rscn after issuing this
* mbox reg login, we may have cycled
* back through the state and be
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
spin_unlock_irq(shost->host_lock);
- if (phba->sli_rev == LPFC_SLI_REV4)
- lpfc_sli4_free_rpi(phba,
- pmb->u.mb.un.varRegLogin.rpi);
-
} else
/* Good status, call state machine */
lpfc_disc_state_machine(vport, ndlp, pmb,
spin_unlock_irq(shost->host_lock);
vport->unreg_vpi_cmpl = VPORT_OK;
mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_cleanup_vports_rrqs(vport);
/*
* This shost reference might have been taken at the beginning of
* lpfc_vport_delete()
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/* FLOGI failed, use loop map to make discovery list */
lpfc_disc_list_loopmap(vport);
}
ndlp->nlp_rpi = mb->un.varWords[0];
- ndlp->nlp_flag |= NLP_RPI_VALID;
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
/* If no other thread is using the ndlp, free it */
lpfc_nlp_not_used(ndlp);
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/*
* RegLogin failed, use loop map to make discovery
* list
}
ndlp->nlp_rpi = mb->un.varWords[0];
- ndlp->nlp_flag |= NLP_RPI_VALID;
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
NLP_INT_NODE_ACT(ndlp);
atomic_set(&ndlp->cmd_pending, 0);
ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
+ if (vport->phba->sli_rev == LPFC_SLI_REV4)
+ ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba);
}
struct lpfc_nodelist *
* by firmware with a no rpi error.
*/
psli = &phba->sli;
- if (ndlp->nlp_flag & NLP_RPI_VALID) {
+ if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
/* Now process each ring */
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
LPFC_MBOXQ_t *mbox;
int rc;
- if (ndlp->nlp_flag & NLP_RPI_VALID) {
+ if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mbox) {
lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
}
lpfc_no_rpi(phba, ndlp);
- ndlp->nlp_rpi = 0;
- ndlp->nlp_flag &= ~NLP_RPI_VALID;
+ if (phba->sli_rev != LPFC_SLI_REV4)
+ ndlp->nlp_rpi = 0;
+ ndlp->nlp_flag &= ~NLP_RPI_REGISTERED;
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
return 1;
}
int i;
vports = lpfc_create_vport_work_array(phba);
+ if (!vports) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "2884 Vport array allocation failed \n");
+ return;
+ }
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
shost = lpfc_shost_from_vport(vports[i]);
spin_lock_irq(shost->host_lock);
list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
- if (ndlp->nlp_flag & NLP_RPI_VALID) {
+ if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
/* The mempool_alloc might sleep */
spin_unlock_irq(shost->host_lock);
lpfc_unreg_rpi(vports[i], ndlp);
kfree(mp);
}
list_del(&mb->list);
- if (phba->sli_rev == LPFC_SLI_REV4)
- lpfc_sli4_free_rpi(phba,
- mb->u.mb.un.varRegLogin.rpi);
mempool_free(mb, phba->mbox_mem_pool);
/* We shall not invoke the lpfc_nlp_put to decrement
* the ndlp reference count as we are in the process
lpfc_cancel_retry_delay_tmo(vport, ndlp);
if ((ndlp->nlp_flag & NLP_DEFER_RM) &&
- !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) &&
- !(ndlp->nlp_flag & NLP_RPI_VALID)) {
+ !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) &&
+ !(ndlp->nlp_flag & NLP_RPI_REGISTERED)) {
/* For this case we need to cleanup the default rpi
* allocated by the firmware.
*/
if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))
!= NULL) {
rc = lpfc_reg_rpi(phba, vport->vpi, ndlp->nlp_DID,
- (uint8_t *) &vport->fc_sparam, mbox, 0);
+ (uint8_t *) &vport->fc_sparam, mbox, ndlp->nlp_rpi);
if (rc) {
mempool_free(mbox, phba->mbox_mem_pool);
}
if (!lpfc_is_link_up(phba))
return;
- if (phba->fc_topology != TOPOLOGY_LOOP)
+ if (phba->fc_topology != LPFC_TOPOLOGY_LOOP)
return;
/* Check for loop map present or not */
}
}
if (vport->port_state != LPFC_FLOGI) {
- lpfc_initial_flogi(vport);
+ if (phba->sli_rev <= LPFC_SLI_REV3)
+ lpfc_initial_flogi(vport);
+ else
+ lpfc_issue_init_vfi(vport);
return;
}
break;
pmb->context2 = NULL;
ndlp->nlp_rpi = mb->un.varWords[0];
- ndlp->nlp_flag |= NLP_RPI_VALID;
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
spin_lock_irqsave(&phba->ndlp_lock, flags);
NLP_CLR_NODE_ACT(ndlp);
spin_unlock_irqrestore(&phba->ndlp_lock, flags);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi);
/* free ndlp memory for final ndlp release */
if (NLP_CHK_FREE_REQ(ndlp)) {
vports = lpfc_create_vport_work_array(phba);
+ /* If driver cannot allocate memory, indicate fcf is in use */
+ if (!vports)
+ return 1;
+
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
shost = lpfc_shost_from_vport(vports[i]);
spin_lock_irq(shost->host_lock);
"logged in\n",
ndlp->nlp_rpi, ndlp->nlp_DID,
ndlp->nlp_flag);
- if (ndlp->nlp_flag & NLP_RPI_VALID)
+ if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
ret = 1;
}
}
* registered, do nothing.
*/
spin_lock_irq(&phba->hbalock);
- if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
+ if (!(phba->hba_flag & HBA_FCOE_MODE) ||
!(phba->fcf.fcf_flag & FCF_REGISTERED) ||
!(phba->hba_flag & HBA_FIP_SUPPORT) ||
(phba->fcf.fcf_flag & FCF_DISCOVERY) ||
uint32_t crcCnt;
};
+struct RRQ { /* Structure is in Big Endian format */
+ uint32_t rrq;
+#define rrq_rsvd_SHIFT 24
+#define rrq_rsvd_MASK 0x000000ff
+#define rrq_rsvd_WORD rrq
+#define rrq_did_SHIFT 0
+#define rrq_did_MASK 0x00ffffff
+#define rrq_did_WORD rrq
+ uint32_t rrq_exchg;
+#define rrq_oxid_SHIFT 16
+#define rrq_oxid_MASK 0xffff
+#define rrq_oxid_WORD rrq_exchg
+#define rrq_rxid_SHIFT 0
+#define rrq_rxid_MASK 0xffff
+#define rrq_rxid_WORD rrq_exchg
+};
+
+
struct RTV_RSP { /* Structure is in Big Endian format */
uint32_t ratov;
uint32_t edtov;
#define PCI_VENDOR_ID_EMULEX 0x10df
#define PCI_DEVICE_ID_FIREFLY 0x1ae5
#define PCI_DEVICE_ID_PROTEUS_VF 0xe100
+#define PCI_DEVICE_ID_BALIUS 0xe131
#define PCI_DEVICE_ID_PROTEUS_PF 0xe180
+#define PCI_DEVICE_ID_LANCER_FC 0xe200
+#define PCI_DEVICE_ID_LANCER_FCOE 0xe260
#define PCI_DEVICE_ID_SAT_SMB 0xf011
#define PCI_DEVICE_ID_SAT_MID 0xf015
#define PCI_DEVICE_ID_RFLY 0xf095
#define PCI_DEVICE_ID_SAT 0xf100
#define PCI_DEVICE_ID_SAT_SCSP 0xf111
#define PCI_DEVICE_ID_SAT_DCSP 0xf112
+#define PCI_DEVICE_ID_FALCON 0xf180
#define PCI_DEVICE_ID_SUPERFLY 0xf700
#define PCI_DEVICE_ID_DRAGONFLY 0xf800
#define PCI_DEVICE_ID_CENTAUR 0xf900
#define PCI_VENDOR_ID_SERVERENGINE 0x19a2
#define PCI_DEVICE_ID_TIGERSHARK 0x0704
#define PCI_DEVICE_ID_TOMCAT 0x0714
-#define PCI_DEVICE_ID_FALCON 0xf180
-#define PCI_DEVICE_ID_BALIUS 0xe131
#define JEDEC_ID_ADDRESS 0x0080001c
#define FIREFLY_JEDEC_ID 0x1ACC
#define MBX_READ_LNK_STAT 0x12
#define MBX_REG_LOGIN 0x13
#define MBX_UNREG_LOGIN 0x14
-#define MBX_READ_LA 0x15
#define MBX_CLEAR_LA 0x16
#define MBX_DUMP_MEMORY 0x17
#define MBX_DUMP_CONTEXT 0x18
#define MBX_READ_SPARM64 0x8D
#define MBX_READ_RPI64 0x8F
#define MBX_REG_LOGIN64 0x93
-#define MBX_READ_LA64 0x95
+#define MBX_READ_TOPOLOGY 0x95
#define MBX_REG_VPI 0x96
#define MBX_UNREG_VPI 0x97
#define FLAGS_IMED_ABORT 0x04000 /* Bit 14 */
uint32_t link_speed;
-#define LINK_SPEED_AUTO 0 /* Auto selection */
-#define LINK_SPEED_1G 1 /* 1 Gigabaud */
-#define LINK_SPEED_2G 2 /* 2 Gigabaud */
-#define LINK_SPEED_4G 4 /* 4 Gigabaud */
-#define LINK_SPEED_8G 8 /* 8 Gigabaud */
-#define LINK_SPEED_10G 16 /* 10 Gigabaud */
+#define LINK_SPEED_AUTO 0x0 /* Auto selection */
+#define LINK_SPEED_1G 0x1 /* 1 Gigabaud */
+#define LINK_SPEED_2G 0x2 /* 2 Gigabaud */
+#define LINK_SPEED_4G 0x4 /* 4 Gigabaud */
+#define LINK_SPEED_8G 0x8 /* 8 Gigabaud */
+#define LINK_SPEED_10G 0x10 /* 10 Gigabaud */
+#define LINK_SPEED_16G 0x11 /* 16 Gigabaud */
} INIT_LINK_VAR;
#define LMT_4Gb 0x040
#define LMT_8Gb 0x080
#define LMT_10Gb 0x100
+#define LMT_16Gb 0x200
uint32_t rsvd2;
uint32_t rsvd3;
uint32_t max_xri;
#endif
} UNREG_D_ID_VAR;
-/* Structure for MB Command READ_LA (21) */
-/* Structure for MB Command READ_LA64 (0x95) */
-
-typedef struct {
+/* Structure for MB Command READ_TOPOLOGY (0x95) */
+struct lpfc_mbx_read_top {
uint32_t eventTag; /* Event tag */
-#ifdef __BIG_ENDIAN_BITFIELD
- uint32_t rsvd1:19;
- uint32_t fa:1;
- uint32_t mm:1; /* Menlo Maintenance mode enabled */
- uint32_t rx:1;
- uint32_t pb:1;
- uint32_t il:1;
- uint32_t attType:8;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint32_t attType:8;
- uint32_t il:1;
- uint32_t pb:1;
- uint32_t rx:1;
- uint32_t mm:1;
- uint32_t fa:1;
- uint32_t rsvd1:19;
-#endif
-
-#define AT_RESERVED 0x00 /* Reserved - attType */
-#define AT_LINK_UP 0x01 /* Link is up */
-#define AT_LINK_DOWN 0x02 /* Link is down */
-
-#ifdef __BIG_ENDIAN_BITFIELD
- uint8_t granted_AL_PA;
- uint8_t lipAlPs;
- uint8_t lipType;
- uint8_t topology;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint8_t topology;
- uint8_t lipType;
- uint8_t lipAlPs;
- uint8_t granted_AL_PA;
-#endif
-
-#define TOPOLOGY_PT_PT 0x01 /* Topology is pt-pt / pt-fabric */
-#define TOPOLOGY_LOOP 0x02 /* Topology is FC-AL */
-#define TOPOLOGY_LNK_MENLO_MAINTENANCE 0x05 /* maint mode zephtr to menlo */
-
- union {
- struct ulp_bde lilpBde; /* This BDE points to a 128 byte buffer
- to */
- /* store the LILP AL_PA position map into */
- struct ulp_bde64 lilpBde64;
- } un;
-
-#ifdef __BIG_ENDIAN_BITFIELD
- uint32_t Dlu:1;
- uint32_t Dtf:1;
- uint32_t Drsvd2:14;
- uint32_t DlnkSpeed:8;
- uint32_t DnlPort:4;
- uint32_t Dtx:2;
- uint32_t Drx:2;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint32_t Drx:2;
- uint32_t Dtx:2;
- uint32_t DnlPort:4;
- uint32_t DlnkSpeed:8;
- uint32_t Drsvd2:14;
- uint32_t Dtf:1;
- uint32_t Dlu:1;
-#endif
-
-#ifdef __BIG_ENDIAN_BITFIELD
- uint32_t Ulu:1;
- uint32_t Utf:1;
- uint32_t Ursvd2:14;
- uint32_t UlnkSpeed:8;
- uint32_t UnlPort:4;
- uint32_t Utx:2;
- uint32_t Urx:2;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint32_t Urx:2;
- uint32_t Utx:2;
- uint32_t UnlPort:4;
- uint32_t UlnkSpeed:8;
- uint32_t Ursvd2:14;
- uint32_t Utf:1;
- uint32_t Ulu:1;
-#endif
-
-#define LA_UNKNW_LINK 0x0 /* lnkSpeed */
-#define LA_1GHZ_LINK 0x04 /* lnkSpeed */
-#define LA_2GHZ_LINK 0x08 /* lnkSpeed */
-#define LA_4GHZ_LINK 0x10 /* lnkSpeed */
-#define LA_8GHZ_LINK 0x20 /* lnkSpeed */
-#define LA_10GHZ_LINK 0x40 /* lnkSpeed */
-
-} READ_LA_VAR;
+ uint32_t word2;
+#define lpfc_mbx_read_top_fa_SHIFT 12
+#define lpfc_mbx_read_top_fa_MASK 0x00000001
+#define lpfc_mbx_read_top_fa_WORD word2
+#define lpfc_mbx_read_top_mm_SHIFT 11
+#define lpfc_mbx_read_top_mm_MASK 0x00000001
+#define lpfc_mbx_read_top_mm_WORD word2
+#define lpfc_mbx_read_top_pb_SHIFT 9
+#define lpfc_mbx_read_top_pb_MASK 0X00000001
+#define lpfc_mbx_read_top_pb_WORD word2
+#define lpfc_mbx_read_top_il_SHIFT 8
+#define lpfc_mbx_read_top_il_MASK 0x00000001
+#define lpfc_mbx_read_top_il_WORD word2
+#define lpfc_mbx_read_top_att_type_SHIFT 0
+#define lpfc_mbx_read_top_att_type_MASK 0x000000FF
+#define lpfc_mbx_read_top_att_type_WORD word2
+#define LPFC_ATT_RESERVED 0x00 /* Reserved - attType */
+#define LPFC_ATT_LINK_UP 0x01 /* Link is up */
+#define LPFC_ATT_LINK_DOWN 0x02 /* Link is down */
+ uint32_t word3;
+#define lpfc_mbx_read_top_alpa_granted_SHIFT 24
+#define lpfc_mbx_read_top_alpa_granted_MASK 0x000000FF
+#define lpfc_mbx_read_top_alpa_granted_WORD word3
+#define lpfc_mbx_read_top_lip_alps_SHIFT 16
+#define lpfc_mbx_read_top_lip_alps_MASK 0x000000FF
+#define lpfc_mbx_read_top_lip_alps_WORD word3
+#define lpfc_mbx_read_top_lip_type_SHIFT 8
+#define lpfc_mbx_read_top_lip_type_MASK 0x000000FF
+#define lpfc_mbx_read_top_lip_type_WORD word3
+#define lpfc_mbx_read_top_topology_SHIFT 0
+#define lpfc_mbx_read_top_topology_MASK 0x000000FF
+#define lpfc_mbx_read_top_topology_WORD word3
+#define LPFC_TOPOLOGY_PT_PT 0x01 /* Topology is pt-pt / pt-fabric */
+#define LPFC_TOPOLOGY_LOOP 0x02 /* Topology is FC-AL */
+#define LPFC_TOPOLOGY_MM 0x05 /* maint mode zephtr to menlo */
+ /* store the LILP AL_PA position map into */
+ struct ulp_bde64 lilpBde64;
+#define LPFC_ALPA_MAP_SIZE 128
+ uint32_t word7;
+#define lpfc_mbx_read_top_ld_lu_SHIFT 31
+#define lpfc_mbx_read_top_ld_lu_MASK 0x00000001
+#define lpfc_mbx_read_top_ld_lu_WORD word7
+#define lpfc_mbx_read_top_ld_tf_SHIFT 30
+#define lpfc_mbx_read_top_ld_tf_MASK 0x00000001
+#define lpfc_mbx_read_top_ld_tf_WORD word7
+#define lpfc_mbx_read_top_ld_link_spd_SHIFT 8
+#define lpfc_mbx_read_top_ld_link_spd_MASK 0x000000FF
+#define lpfc_mbx_read_top_ld_link_spd_WORD word7
+#define lpfc_mbx_read_top_ld_nl_port_SHIFT 4
+#define lpfc_mbx_read_top_ld_nl_port_MASK 0x0000000F
+#define lpfc_mbx_read_top_ld_nl_port_WORD word7
+#define lpfc_mbx_read_top_ld_tx_SHIFT 2
+#define lpfc_mbx_read_top_ld_tx_MASK 0x00000003
+#define lpfc_mbx_read_top_ld_tx_WORD word7
+#define lpfc_mbx_read_top_ld_rx_SHIFT 0
+#define lpfc_mbx_read_top_ld_rx_MASK 0x00000003
+#define lpfc_mbx_read_top_ld_rx_WORD word7
+ uint32_t word8;
+#define lpfc_mbx_read_top_lu_SHIFT 31
+#define lpfc_mbx_read_top_lu_MASK 0x00000001
+#define lpfc_mbx_read_top_lu_WORD word8
+#define lpfc_mbx_read_top_tf_SHIFT 30
+#define lpfc_mbx_read_top_tf_MASK 0x00000001
+#define lpfc_mbx_read_top_tf_WORD word8
+#define lpfc_mbx_read_top_link_spd_SHIFT 8
+#define lpfc_mbx_read_top_link_spd_MASK 0x000000FF
+#define lpfc_mbx_read_top_link_spd_WORD word8
+#define lpfc_mbx_read_top_nl_port_SHIFT 4
+#define lpfc_mbx_read_top_nl_port_MASK 0x0000000F
+#define lpfc_mbx_read_top_nl_port_WORD word8
+#define lpfc_mbx_read_top_tx_SHIFT 2
+#define lpfc_mbx_read_top_tx_MASK 0x00000003
+#define lpfc_mbx_read_top_tx_WORD word8
+#define lpfc_mbx_read_top_rx_SHIFT 0
+#define lpfc_mbx_read_top_rx_MASK 0x00000003
+#define lpfc_mbx_read_top_rx_WORD word8
+#define LPFC_LINK_SPEED_UNKNOWN 0x0
+#define LPFC_LINK_SPEED_1GHZ 0x04
+#define LPFC_LINK_SPEED_2GHZ 0x08
+#define LPFC_LINK_SPEED_4GHZ 0x10
+#define LPFC_LINK_SPEED_8GHZ 0x20
+#define LPFC_LINK_SPEED_10GHZ 0x40
+#define LPFC_LINK_SPEED_16GHZ 0x80
+};
/* Structure for MB Command CLEAR_LA (22) */
READ_LNK_VAR varRdLnk; /* cmd = 18 (READ_LNK_STAT) */
REG_LOGIN_VAR varRegLogin; /* cmd = 19 (REG_LOGIN(64)) */
UNREG_LOGIN_VAR varUnregLogin; /* cmd = 20 (UNREG_LOGIN) */
- READ_LA_VAR varReadLA; /* cmd = 21 (READ_LA(64)) */
CLEAR_LA_VAR varClearLA; /* cmd = 22 (CLEAR_LA) */
DUMP_VAR varDmp; /* Warm Start DUMP mbx cmd */
UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID) */
struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ) */
struct update_cfg_var varUpdateCfg; /* cmd = 0x1B (UPDATE_CFG)*/
CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */
+ struct lpfc_mbx_read_top varReadTop; /* cmd = 0x95 (READ_TOPOLOGY) */
REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */
UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */
ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */
#define lpfc_sli_intf_valid_MASK 0x00000007
#define lpfc_sli_intf_valid_WORD word0
#define LPFC_SLI_INTF_VALID 6
-#define lpfc_sli_intf_featurelevel2_SHIFT 24
-#define lpfc_sli_intf_featurelevel2_MASK 0x0000001F
-#define lpfc_sli_intf_featurelevel2_WORD word0
-#define lpfc_sli_intf_featurelevel1_SHIFT 16
-#define lpfc_sli_intf_featurelevel1_MASK 0x000000FF
-#define lpfc_sli_intf_featurelevel1_WORD word0
-#define LPFC_SLI_INTF_FEATURELEVEL1_1 1
-#define LPFC_SLI_INTF_FEATURELEVEL1_2 2
+#define lpfc_sli_intf_sli_hint2_SHIFT 24
+#define lpfc_sli_intf_sli_hint2_MASK 0x0000001F
+#define lpfc_sli_intf_sli_hint2_WORD word0
+#define LPFC_SLI_INTF_SLI_HINT2_NONE 0
+#define lpfc_sli_intf_sli_hint1_SHIFT 16
+#define lpfc_sli_intf_sli_hint1_MASK 0x000000FF
+#define lpfc_sli_intf_sli_hint1_WORD word0
+#define LPFC_SLI_INTF_SLI_HINT1_NONE 0
+#define LPFC_SLI_INTF_SLI_HINT1_1 1
+#define LPFC_SLI_INTF_SLI_HINT1_2 2
+#define lpfc_sli_intf_if_type_SHIFT 12
+#define lpfc_sli_intf_if_type_MASK 0x0000000F
+#define lpfc_sli_intf_if_type_WORD word0
+#define LPFC_SLI_INTF_IF_TYPE_0 0
+#define LPFC_SLI_INTF_IF_TYPE_1 1
+#define LPFC_SLI_INTF_IF_TYPE_2 2
#define lpfc_sli_intf_sli_family_SHIFT 8
-#define lpfc_sli_intf_sli_family_MASK 0x000000FF
+#define lpfc_sli_intf_sli_family_MASK 0x0000000F
#define lpfc_sli_intf_sli_family_WORD word0
-#define LPFC_SLI_INTF_FAMILY_BE2 0
-#define LPFC_SLI_INTF_FAMILY_BE3 1
+#define LPFC_SLI_INTF_FAMILY_BE2 0x0
+#define LPFC_SLI_INTF_FAMILY_BE3 0x1
+#define LPFC_SLI_INTF_FAMILY_LNCR_A0 0xa
+#define LPFC_SLI_INTF_FAMILY_LNCR_B0 0xb
#define lpfc_sli_intf_slirev_SHIFT 4
#define lpfc_sli_intf_slirev_MASK 0x0000000F
#define lpfc_sli_intf_slirev_WORD word0
#define LPFC_SLI_INTF_REV_SLI3 3
#define LPFC_SLI_INTF_REV_SLI4 4
-#define lpfc_sli_intf_if_type_SHIFT 0
-#define lpfc_sli_intf_if_type_MASK 0x00000007
-#define lpfc_sli_intf_if_type_WORD word0
-#define LPFC_SLI_INTF_IF_TYPE_0 0
-#define LPFC_SLI_INTF_IF_TYPE_1 1
+#define lpfc_sli_intf_func_type_SHIFT 0
+#define lpfc_sli_intf_func_type_MASK 0x00000001
+#define lpfc_sli_intf_func_type_WORD word0
+#define LPFC_SLI_INTF_IF_TYPE_PHYS 0
+#define LPFC_SLI_INTF_IF_TYPE_VIRT 1
};
#define LPFC_SLI4_MBX_EMBED true
uint32_t word0;
};
+/* The following BAR0 Registers apply to SLI4 if_type 0 UCNAs. */
#define LPFC_UERR_STATUS_HI 0x00A4
#define LPFC_UERR_STATUS_LO 0x00A0
#define LPFC_UE_MASK_HI 0x00AC
#define LPFC_UE_MASK_LO 0x00A8
+
+/* The following BAR0 register sets are defined for if_type 0 and 2 UCNAs. */
#define LPFC_SLI_INTF 0x0058
-/* BAR0 Registers */
-#define LPFC_HST_STATE 0x00AC
-#define lpfc_hst_state_perr_SHIFT 31
-#define lpfc_hst_state_perr_MASK 0x1
-#define lpfc_hst_state_perr_WORD word0
-#define lpfc_hst_state_sfi_SHIFT 30
-#define lpfc_hst_state_sfi_MASK 0x1
-#define lpfc_hst_state_sfi_WORD word0
-#define lpfc_hst_state_nip_SHIFT 29
-#define lpfc_hst_state_nip_MASK 0x1
-#define lpfc_hst_state_nip_WORD word0
-#define lpfc_hst_state_ipc_SHIFT 28
-#define lpfc_hst_state_ipc_MASK 0x1
-#define lpfc_hst_state_ipc_WORD word0
-#define lpfc_hst_state_xrom_SHIFT 27
-#define lpfc_hst_state_xrom_MASK 0x1
-#define lpfc_hst_state_xrom_WORD word0
-#define lpfc_hst_state_dl_SHIFT 26
-#define lpfc_hst_state_dl_MASK 0x1
-#define lpfc_hst_state_dl_WORD word0
-#define lpfc_hst_state_port_status_SHIFT 0
-#define lpfc_hst_state_port_status_MASK 0xFFFF
-#define lpfc_hst_state_port_status_WORD word0
+#define LPFC_SLIPORT_IF2_SMPHR 0x0400
+#define lpfc_port_smphr_perr_SHIFT 31
+#define lpfc_port_smphr_perr_MASK 0x1
+#define lpfc_port_smphr_perr_WORD word0
+#define lpfc_port_smphr_sfi_SHIFT 30
+#define lpfc_port_smphr_sfi_MASK 0x1
+#define lpfc_port_smphr_sfi_WORD word0
+#define lpfc_port_smphr_nip_SHIFT 29
+#define lpfc_port_smphr_nip_MASK 0x1
+#define lpfc_port_smphr_nip_WORD word0
+#define lpfc_port_smphr_ipc_SHIFT 28
+#define lpfc_port_smphr_ipc_MASK 0x1
+#define lpfc_port_smphr_ipc_WORD word0
+#define lpfc_port_smphr_scr1_SHIFT 27
+#define lpfc_port_smphr_scr1_MASK 0x1
+#define lpfc_port_smphr_scr1_WORD word0
+#define lpfc_port_smphr_scr2_SHIFT 26
+#define lpfc_port_smphr_scr2_MASK 0x1
+#define lpfc_port_smphr_scr2_WORD word0
+#define lpfc_port_smphr_host_scratch_SHIFT 16
+#define lpfc_port_smphr_host_scratch_MASK 0xFF
+#define lpfc_port_smphr_host_scratch_WORD word0
+#define lpfc_port_smphr_port_status_SHIFT 0
+#define lpfc_port_smphr_port_status_MASK 0xFFFF
+#define lpfc_port_smphr_port_status_WORD word0
#define LPFC_POST_STAGE_POWER_ON_RESET 0x0000
#define LPFC_POST_STAGE_AWAITING_HOST_RDY 0x0001
#define LPFC_POST_STAGE_RC_DONE 0x0B07
#define LPFC_POST_STAGE_REBOOT_SYSTEM 0x0B08
#define LPFC_POST_STAGE_MAC_ADDRESS 0x0C00
-#define LPFC_POST_STAGE_ARMFW_READY 0xC000
-#define LPFC_POST_STAGE_ARMFW_UE 0xF000
+#define LPFC_POST_STAGE_PORT_READY 0xC000
+#define LPFC_POST_STAGE_PORT_UE 0xF000
+
+#define LPFC_SLIPORT_STATUS 0x0404
+#define lpfc_sliport_status_err_SHIFT 31
+#define lpfc_sliport_status_err_MASK 0x1
+#define lpfc_sliport_status_err_WORD word0
+#define lpfc_sliport_status_end_SHIFT 30
+#define lpfc_sliport_status_end_MASK 0x1
+#define lpfc_sliport_status_end_WORD word0
+#define lpfc_sliport_status_oti_SHIFT 29
+#define lpfc_sliport_status_oti_MASK 0x1
+#define lpfc_sliport_status_oti_WORD word0
+#define lpfc_sliport_status_rn_SHIFT 24
+#define lpfc_sliport_status_rn_MASK 0x1
+#define lpfc_sliport_status_rn_WORD word0
+#define lpfc_sliport_status_rdy_SHIFT 23
+#define lpfc_sliport_status_rdy_MASK 0x1
+#define lpfc_sliport_status_rdy_WORD word0
+#define MAX_IF_TYPE_2_RESETS 1000
+
+#define LPFC_SLIPORT_CNTRL 0x0408
+#define lpfc_sliport_ctrl_end_SHIFT 30
+#define lpfc_sliport_ctrl_end_MASK 0x1
+#define lpfc_sliport_ctrl_end_WORD word0
+#define LPFC_SLIPORT_LITTLE_ENDIAN 0
+#define LPFC_SLIPORT_BIG_ENDIAN 1
+#define lpfc_sliport_ctrl_ip_SHIFT 27
+#define lpfc_sliport_ctrl_ip_MASK 0x1
+#define lpfc_sliport_ctrl_ip_WORD word0
+#define LPFC_SLIPORT_INIT_PORT 1
+
+#define LPFC_SLIPORT_ERR_1 0x040C
+#define LPFC_SLIPORT_ERR_2 0x0410
+
+/* The following Registers apply to SLI4 if_type 0 UCNAs. They typically
+ * reside in BAR 2.
+ */
+#define LPFC_SLIPORT_IF0_SMPHR 0x00AC
-/* BAR1 Registers */
#define LPFC_IMR_MASK_ALL 0xFFFFFFFF
#define LPFC_ISCR_CLEAR_ALL 0xFFFFFFFF
#define LPFC_SLI4_INTR30 BIT30
#define LPFC_SLI4_INTR31 BIT31
-/* BAR2 Registers */
+/*
+ * The Doorbell registers defined here exist in different BAR
+ * register sets depending on the UCNA Port's reported if_type
+ * value. For UCNA ports running SLI4 and if_type 0, they reside in
+ * BAR4. For UCNA ports running SLI4 and if_type 2, they reside in
+ * BAR0. The offsets are the same so the driver must account for
+ * any base address difference.
+ */
#define LPFC_RQ_DOORBELL 0x00A0
#define lpfc_rq_doorbell_num_posted_SHIFT 16
#define lpfc_rq_doorbell_num_posted_MASK 0x3FFF
#define lpfc_rq_doorbell_num_posted_WORD word0
#define LPFC_RQ_POST_BATCH 8 /* RQEs to post at one time */
#define lpfc_rq_doorbell_id_SHIFT 0
-#define lpfc_rq_doorbell_id_MASK 0x03FF
+#define lpfc_rq_doorbell_id_MASK 0xFFFF
#define lpfc_rq_doorbell_id_WORD word0
#define LPFC_WQ_DOORBELL 0x0040
#define lpfc_wq_doorbell_id_WORD word0
#define LPFC_EQCQ_DOORBELL 0x0120
+#define lpfc_eqcq_doorbell_se_SHIFT 31
+#define lpfc_eqcq_doorbell_se_MASK 0x0001
+#define lpfc_eqcq_doorbell_se_WORD word0
+#define LPFC_EQCQ_SOLICIT_ENABLE_OFF 0
+#define LPFC_EQCQ_SOLICIT_ENABLE_ON 1
#define lpfc_eqcq_doorbell_arm_SHIFT 29
#define lpfc_eqcq_doorbell_arm_MASK 0x0001
#define lpfc_eqcq_doorbell_arm_WORD word0
#define lpfc_mq_doorbell_num_posted_MASK 0x3FFF
#define lpfc_mq_doorbell_num_posted_WORD word0
#define lpfc_mq_doorbell_id_SHIFT 0
-#define lpfc_mq_doorbell_id_MASK 0x03FF
+#define lpfc_mq_doorbell_id_MASK 0xFFFF
#define lpfc_mq_doorbell_id_WORD word0
struct lpfc_sli4_cfg_mhdr {
#define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT LPFC_TRAILER_CODE_LINK
#define lpfc_mbx_mq_create_ext_async_evt_link_MASK 0x00000001
#define lpfc_mbx_mq_create_ext_async_evt_link_WORD async_evt_bmap
-#define lpfc_mbx_mq_create_ext_async_evt_fcfste_SHIFT LPFC_TRAILER_CODE_FCOE
-#define lpfc_mbx_mq_create_ext_async_evt_fcfste_MASK 0x00000001
-#define lpfc_mbx_mq_create_ext_async_evt_fcfste_WORD async_evt_bmap
+#define lpfc_mbx_mq_create_ext_async_evt_fip_SHIFT LPFC_TRAILER_CODE_FCOE
+#define lpfc_mbx_mq_create_ext_async_evt_fip_MASK 0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_fip_WORD async_evt_bmap
#define lpfc_mbx_mq_create_ext_async_evt_group5_SHIFT LPFC_TRAILER_CODE_GRP5
#define lpfc_mbx_mq_create_ext_async_evt_group5_MASK 0x00000001
#define lpfc_mbx_mq_create_ext_async_evt_group5_WORD async_evt_bmap
+#define lpfc_mbx_mq_create_ext_async_evt_fc_SHIFT LPFC_TRAILER_CODE_FC
+#define lpfc_mbx_mq_create_ext_async_evt_fc_MASK 0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_fc_WORD async_evt_bmap
+#define lpfc_mbx_mq_create_ext_async_evt_sli_SHIFT LPFC_TRAILER_CODE_SLI
+#define lpfc_mbx_mq_create_ext_async_evt_sli_MASK 0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_sli_WORD async_evt_bmap
struct mq_context context;
struct dma_address page[LPFC_MAX_MQ_PAGE];
} request;
#define lpfc_function_mode_dal_WORD function_mode
#define lpfc_function_mode_lro_SHIFT 9
#define lpfc_function_mode_lro_MASK 0x00000001
-#define lpfc_function_mode_lro_WORD function_mode9
+#define lpfc_function_mode_lro_WORD function_mode
#define lpfc_function_mode_flex10_SHIFT 10
#define lpfc_function_mode_flex10_MASK 0x00000001
#define lpfc_function_mode_flex10_WORD function_mode
#define lpfc_init_vfi_vf_SHIFT 29
#define lpfc_init_vfi_vf_MASK 0x00000001
#define lpfc_init_vfi_vf_WORD word1
+#define lpfc_init_vfi_vp_SHIFT 28
+#define lpfc_init_vfi_vp_MASK 0x00000001
+#define lpfc_init_vfi_vp_WORD word1
#define lpfc_init_vfi_vfi_SHIFT 0
#define lpfc_init_vfi_vfi_MASK 0x0000FFFF
#define lpfc_init_vfi_vfi_WORD word1
uint32_t word2;
+#define lpfc_init_vfi_vpi_SHIFT 16
+#define lpfc_init_vfi_vpi_MASK 0x0000FFFF
+#define lpfc_init_vfi_vpi_WORD word2
#define lpfc_init_vfi_fcfi_SHIFT 0
#define lpfc_init_vfi_fcfi_MASK 0x0000FFFF
#define lpfc_init_vfi_fcfi_WORD word2
#define LPFC_TRAILER_CODE_FCOE 0x2
#define LPFC_TRAILER_CODE_DCBX 0x3
#define LPFC_TRAILER_CODE_GRP5 0x5
+#define LPFC_TRAILER_CODE_FC 0x10
+#define LPFC_TRAILER_CODE_SLI 0x11
};
struct lpfc_acqe_link {
#define LPFC_ASYNC_LINK_STATUS_UP 0x1
#define LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN 0x2
#define LPFC_ASYNC_LINK_STATUS_LOGICAL_UP 0x3
-#define lpfc_acqe_link_physical_SHIFT 0
-#define lpfc_acqe_link_physical_MASK 0x000000FF
-#define lpfc_acqe_link_physical_WORD word0
-#define LPFC_ASYNC_LINK_PORT_A 0x0
-#define LPFC_ASYNC_LINK_PORT_B 0x1
+#define lpfc_acqe_link_type_SHIFT 6
+#define lpfc_acqe_link_type_MASK 0x00000003
+#define lpfc_acqe_link_type_WORD word0
+#define lpfc_acqe_link_number_SHIFT 0
+#define lpfc_acqe_link_number_MASK 0x0000003F
+#define lpfc_acqe_link_number_WORD word0
uint32_t word1;
#define lpfc_acqe_link_fault_SHIFT 0
#define lpfc_acqe_link_fault_MASK 0x000000FF
#define LPFC_ASYNC_LINK_FAULT_NONE 0x0
#define LPFC_ASYNC_LINK_FAULT_LOCAL 0x1
#define LPFC_ASYNC_LINK_FAULT_REMOTE 0x2
-#define lpfc_acqe_qos_link_speed_SHIFT 16
-#define lpfc_acqe_qos_link_speed_MASK 0x0000FFFF
-#define lpfc_acqe_qos_link_speed_WORD word1
+#define lpfc_acqe_logical_link_speed_SHIFT 16
+#define lpfc_acqe_logical_link_speed_MASK 0x0000FFFF
+#define lpfc_acqe_logical_link_speed_WORD word1
uint32_t event_tag;
uint32_t trailer;
+#define LPFC_LINK_EVENT_TYPE_PHYSICAL 0x0
+#define LPFC_LINK_EVENT_TYPE_VIRTUAL 0x1
};
-struct lpfc_acqe_fcoe {
+struct lpfc_acqe_fip {
uint32_t index;
uint32_t word1;
-#define lpfc_acqe_fcoe_fcf_count_SHIFT 0
-#define lpfc_acqe_fcoe_fcf_count_MASK 0x0000FFFF
-#define lpfc_acqe_fcoe_fcf_count_WORD word1
-#define lpfc_acqe_fcoe_event_type_SHIFT 16
-#define lpfc_acqe_fcoe_event_type_MASK 0x0000FFFF
-#define lpfc_acqe_fcoe_event_type_WORD word1
-#define LPFC_FCOE_EVENT_TYPE_NEW_FCF 0x1
-#define LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL 0x2
-#define LPFC_FCOE_EVENT_TYPE_FCF_DEAD 0x3
-#define LPFC_FCOE_EVENT_TYPE_CVL 0x4
-#define LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD 0x5
+#define lpfc_acqe_fip_fcf_count_SHIFT 0
+#define lpfc_acqe_fip_fcf_count_MASK 0x0000FFFF
+#define lpfc_acqe_fip_fcf_count_WORD word1
+#define lpfc_acqe_fip_event_type_SHIFT 16
+#define lpfc_acqe_fip_event_type_MASK 0x0000FFFF
+#define lpfc_acqe_fip_event_type_WORD word1
uint32_t event_tag;
uint32_t trailer;
+#define LPFC_FIP_EVENT_TYPE_NEW_FCF 0x1
+#define LPFC_FIP_EVENT_TYPE_FCF_TABLE_FULL 0x2
+#define LPFC_FIP_EVENT_TYPE_FCF_DEAD 0x3
+#define LPFC_FIP_EVENT_TYPE_CVL 0x4
+#define LPFC_FIP_EVENT_TYPE_FCF_PARAM_MOD 0x5
};
struct lpfc_acqe_dcbx {
struct lpfc_acqe_grp5 {
uint32_t word0;
-#define lpfc_acqe_grp5_pport_SHIFT 0
-#define lpfc_acqe_grp5_pport_MASK 0x000000FF
-#define lpfc_acqe_grp5_pport_WORD word0
+#define lpfc_acqe_grp5_type_SHIFT 6
+#define lpfc_acqe_grp5_type_MASK 0x00000003
+#define lpfc_acqe_grp5_type_WORD word0
+#define lpfc_acqe_grp5_number_SHIFT 0
+#define lpfc_acqe_grp5_number_MASK 0x0000003F
+#define lpfc_acqe_grp5_number_WORD word0
uint32_t word1;
#define lpfc_acqe_grp5_llink_spd_SHIFT 16
#define lpfc_acqe_grp5_llink_spd_MASK 0x0000FFFF
uint32_t trailer;
};
+struct lpfc_acqe_fc_la {
+ uint32_t word0;
+#define lpfc_acqe_fc_la_speed_SHIFT 24
+#define lpfc_acqe_fc_la_speed_MASK 0x000000FF
+#define lpfc_acqe_fc_la_speed_WORD word0
+#define LPFC_FC_LA_SPEED_UNKOWN 0x0
+#define LPFC_FC_LA_SPEED_1G 0x1
+#define LPFC_FC_LA_SPEED_2G 0x2
+#define LPFC_FC_LA_SPEED_4G 0x4
+#define LPFC_FC_LA_SPEED_8G 0x8
+#define LPFC_FC_LA_SPEED_10G 0xA
+#define LPFC_FC_LA_SPEED_16G 0x10
+#define lpfc_acqe_fc_la_topology_SHIFT 16
+#define lpfc_acqe_fc_la_topology_MASK 0x000000FF
+#define lpfc_acqe_fc_la_topology_WORD word0
+#define LPFC_FC_LA_TOP_UNKOWN 0x0
+#define LPFC_FC_LA_TOP_P2P 0x1
+#define LPFC_FC_LA_TOP_FCAL 0x2
+#define LPFC_FC_LA_TOP_INTERNAL_LOOP 0x3
+#define LPFC_FC_LA_TOP_SERDES_LOOP 0x4
+#define lpfc_acqe_fc_la_att_type_SHIFT 8
+#define lpfc_acqe_fc_la_att_type_MASK 0x000000FF
+#define lpfc_acqe_fc_la_att_type_WORD word0
+#define LPFC_FC_LA_TYPE_LINK_UP 0x1
+#define LPFC_FC_LA_TYPE_LINK_DOWN 0x2
+#define LPFC_FC_LA_TYPE_NO_HARD_ALPA 0x3
+#define lpfc_acqe_fc_la_port_type_SHIFT 6
+#define lpfc_acqe_fc_la_port_type_MASK 0x00000003
+#define lpfc_acqe_fc_la_port_type_WORD word0
+#define LPFC_LINK_TYPE_ETHERNET 0x0
+#define LPFC_LINK_TYPE_FC 0x1
+#define lpfc_acqe_fc_la_port_number_SHIFT 0
+#define lpfc_acqe_fc_la_port_number_MASK 0x0000003F
+#define lpfc_acqe_fc_la_port_number_WORD word0
+ uint32_t word1;
+#define lpfc_acqe_fc_la_llink_spd_SHIFT 16
+#define lpfc_acqe_fc_la_llink_spd_MASK 0x0000FFFF
+#define lpfc_acqe_fc_la_llink_spd_WORD word1
+#define lpfc_acqe_fc_la_fault_SHIFT 0
+#define lpfc_acqe_fc_la_fault_MASK 0x000000FF
+#define lpfc_acqe_fc_la_fault_WORD word1
+#define LPFC_FC_LA_FAULT_NONE 0x0
+#define LPFC_FC_LA_FAULT_LOCAL 0x1
+#define LPFC_FC_LA_FAULT_REMOTE 0x2
+ uint32_t event_tag;
+ uint32_t trailer;
+#define LPFC_FC_LA_EVENT_TYPE_FC_LINK 0x1
+#define LPFC_FC_LA_EVENT_TYPE_SHARED_LINK 0x2
+};
+
+struct lpfc_acqe_sli {
+ uint32_t event_data1;
+ uint32_t event_data2;
+ uint32_t reserved;
+ uint32_t trailer;
+#define LPFC_SLI_EVENT_TYPE_PORT_ERROR 0x1
+#define LPFC_SLI_EVENT_TYPE_OVER_TEMP 0x2
+#define LPFC_SLI_EVENT_TYPE_NORM_TEMP 0x3
+#define LPFC_SLI_EVENT_TYPE_NVLOG_POST 0x4
+#define LPFC_SLI_EVENT_TYPE_DIAG_DUMP 0x5
+};
+
/*
* Define the bootstrap mailbox (bmbx) region used to communicate
* mailbox command between the host and port. The mailbox consists
#define wqe_rcvoxid_WORD word9
uint32_t word10;
#define wqe_ebde_cnt_SHIFT 0
-#define wqe_ebde_cnt_MASK 0x00000007
+#define wqe_ebde_cnt_MASK 0x0000000f
#define wqe_ebde_cnt_WORD word10
#define wqe_lenloc_SHIFT 7
#define wqe_lenloc_MASK 0x00000003
uint32_t relative_offset;
struct wqe_rctl_dfctl wge_ctl;
struct wqe_common wqe_com; /* words 6-11 */
- /* Note: word10 different REVISIT */
uint32_t xmit_len;
uint32_t rsvd_12_15[3];
};
/* Get the default values for Model Name and Description */
lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc);
- if ((phba->cfg_link_speed > LINK_SPEED_10G)
- || ((phba->cfg_link_speed == LINK_SPEED_1G)
+ if ((phba->cfg_link_speed > LPFC_USER_LINK_SPEED_16G)
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_1G)
&& !(phba->lmt & LMT_1Gb))
- || ((phba->cfg_link_speed == LINK_SPEED_2G)
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_2G)
&& !(phba->lmt & LMT_2Gb))
- || ((phba->cfg_link_speed == LINK_SPEED_4G)
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_4G)
&& !(phba->lmt & LMT_4Gb))
- || ((phba->cfg_link_speed == LINK_SPEED_8G)
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_8G)
&& !(phba->lmt & LMT_8Gb))
- || ((phba->cfg_link_speed == LINK_SPEED_10G)
- && !(phba->lmt & LMT_10Gb))) {
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_10G)
+ && !(phba->lmt & LMT_10Gb))
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G)
+ && !(phba->lmt & LMT_16Gb))) {
/* Reset link speed to auto */
lpfc_printf_log(phba, KERN_WARNING, LOG_LINK_EVENT,
"1302 Invalid speed for this board: "
"Reset link speed to auto: x%x\n",
phba->cfg_link_speed);
- phba->cfg_link_speed = LINK_SPEED_AUTO;
+ phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO;
}
phba->link_state = LPFC_LINK_DOWN;
mb = &pmb->u.mb;
pmb->vport = vport;
- lpfc_init_link(phba, pmb, phba->cfg_topology,
- phba->cfg_link_speed);
+ lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
lpfc_set_loopback_flag(phba);
rc = lpfc_sli_issue_mbox(phba, pmb, flag);
- if (rc != MBX_SUCCESS) {
+ if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0498 Adapter failed to init, mbxCmd x%x "
"INIT_LINK, mbxStatus x%x\n",
mb->mbxCommand, mb->mbxStatus);
- /* Clear all interrupt enable conditions */
- writel(0, phba->HCregaddr);
- readl(phba->HCregaddr); /* flush */
- /* Clear all pending interrupts */
- writel(0xffffffff, phba->HAregaddr);
- readl(phba->HAregaddr); /* flush */
+ if (phba->sli_rev <= LPFC_SLI_REV3) {
+ /* Clear all interrupt enable conditions */
+ writel(0, phba->HCregaddr);
+ readl(phba->HCregaddr); /* flush */
+ /* Clear all pending interrupts */
+ writel(0xffffffff, phba->HAregaddr);
+ readl(phba->HAregaddr); /* flush */
+ }
phba->link_state = LPFC_HBA_ERROR;
if (rc != MBX_BUSY || flag == MBX_POLL)
mempool_free(pmb, phba->mbox_mem_pool);
return;
}
+/**
+ * lpfc_rrq_timeout - The RRQ-timer timeout handler
+ * @ptr: unsigned long holds the pointer to lpfc hba data structure.
+ *
+ * This is the RRQ-timer timeout handler registered to the lpfc driver. When
+ * this timer fires, a RRQ timeout event shall be posted to the lpfc driver
+ * work-port-events bitmap and the worker thread is notified. This timeout
+ * event will be used by the worker thread to invoke the actual timeout
+ * handler routine, lpfc_rrq_handler. Any periodical operations will
+ * be performed in the timeout handler and the RRQ timeout event bit shall
+ * be cleared by the worker thread after it has taken the event bitmap out.
+ **/
+static void
+lpfc_rrq_timeout(unsigned long ptr)
+{
+ struct lpfc_hba *phba;
+ uint32_t tmo_posted;
+ unsigned long iflag;
+
+ phba = (struct lpfc_hba *)ptr;
+ spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
+ tmo_posted = phba->hba_flag & HBA_RRQ_ACTIVE;
+ if (!tmo_posted)
+ phba->hba_flag |= HBA_RRQ_ACTIVE;
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
+ if (!tmo_posted)
+ lpfc_worker_wake_up(phba);
+}
+
/**
* lpfc_hb_mbox_cmpl - The lpfc heart-beat mailbox command callback function
* @phba: pointer to lpfc hba data structure.
struct lpfc_vport *vport = phba->pport;
uint32_t event_data;
struct Scsi_Host *shost;
+ uint32_t if_type;
+ struct lpfc_register portstat_reg;
/* If the pci channel is offline, ignore possible errors, since
* we cannot communicate with the pci card anyway.
/* For now, the actual action for SLI4 device handling is not
* specified yet, just treated it as adaptor hardware failure
*/
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0143 SLI4 Adapter Hardware Error Data: x%x x%x\n",
- phba->work_status[0], phba->work_status[1]);
-
event_data = FC_REG_DUMP_EVENT;
shost = lpfc_shost_from_vport(vport);
fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(event_data), (char *) &event_data,
SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
- lpfc_sli4_offline_eratt(phba);
+ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ lpfc_sli4_offline_eratt(phba);
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ portstat_reg.word0 =
+ readl(phba->sli4_hba.u.if_type2.STATUSregaddr);
+
+ if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) {
+ /* TODO: Register for Overtemp async events. */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2889 Port Overtemperature event, "
+ "taking port\n");
+ spin_lock_irq(&phba->hbalock);
+ phba->over_temp_state = HBA_OVER_TEMP;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_sli4_offline_eratt(phba);
+ return;
+ }
+ if (bf_get(lpfc_sliport_status_rn, &portstat_reg)) {
+ /*
+ * TODO: Attempt port recovery via a port reset.
+ * When fully implemented, the driver should
+ * attempt to recover the port here and return.
+ * For now, log an error and take the port offline.
+ */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2887 Port Error: Attempting "
+ "Port Recovery\n");
+ }
+ lpfc_sli4_offline_eratt(phba);
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ break;
+ }
}
/**
lpfc_els_flush_all_cmd(phba);
psli->slistat.link_event++;
- lpfc_read_la(phba, pmb, mp);
- pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
+ lpfc_read_topology(phba, pmb, mp);
+ pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology;
pmb->vport = vport;
/* Block ELS IOCBs until we have processed this mbox command */
phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT;
m = (typeof(m)){"LPVe12002", "PCIe Shared I/O",
"Fibre Channel Adapter"};
break;
+ case PCI_DEVICE_ID_LANCER_FC:
+ oneConnect = 1;
+ m = (typeof(m)){"Undefined", "PCIe", "Fibre Channel Adapter"};
+ break;
+ case PCI_DEVICE_ID_LANCER_FCOE:
+ oneConnect = 1;
+ m = (typeof(m)){"Undefined", "PCIe", "FCoE"};
+ break;
default:
m = (typeof(m)){"Unknown", "", ""};
break;
lpfc_worker_wake_up(phba);
}
-/**
- * lpfc_sli4_fw_cfg_check - Read the firmware config and verify FCoE support
- * @phba: pointer to lpfc hba data structure.
- *
- * This function uses the QUERY_FW_CFG mailbox command to determine if the
- * firmware loaded supports FCoE. A return of zero indicates that the mailbox
- * was successful and the firmware supports FCoE. Any other return indicates
- * a error. It is assumed that this function will be called before interrupts
- * are enabled.
- **/
-static int
-lpfc_sli4_fw_cfg_check(struct lpfc_hba *phba)
-{
- int rc = 0;
- LPFC_MBOXQ_t *mboxq;
- struct lpfc_mbx_query_fw_cfg *query_fw_cfg;
- uint32_t length;
- uint32_t shdr_status, shdr_add_status;
-
- mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mboxq) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2621 Failed to allocate mbox for "
- "query firmware config cmd\n");
- return -ENOMEM;
- }
- query_fw_cfg = &mboxq->u.mqe.un.query_fw_cfg;
- length = (sizeof(struct lpfc_mbx_query_fw_cfg) -
- sizeof(struct lpfc_sli4_cfg_mhdr));
- lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
- LPFC_MBOX_OPCODE_QUERY_FW_CFG,
- length, LPFC_SLI4_MBX_EMBED);
- rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
- /* The IOCTL status is embedded in the mailbox subheader. */
- shdr_status = bf_get(lpfc_mbox_hdr_status,
- &query_fw_cfg->header.cfg_shdr.response);
- shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
- &query_fw_cfg->header.cfg_shdr.response);
- if (shdr_status || shdr_add_status || rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2622 Query Firmware Config failed "
- "mbx status x%x, status x%x add_status x%x\n",
- rc, shdr_status, shdr_add_status);
- return -EINVAL;
- }
- if (!bf_get(lpfc_function_mode_fcoe_i, query_fw_cfg)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2623 FCoE Function not supported by firmware. "
- "Function mode = %08x\n",
- query_fw_cfg->function_mode);
- return -EINVAL;
- }
- if (rc != MBX_TIMEOUT)
- mempool_free(mboxq, phba->mbox_mem_pool);
- return 0;
-}
-
/**
* lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code
* @phba: pointer to lpfc hba data structure.
switch (bf_get(lpfc_acqe_link_status, acqe_link)) {
case LPFC_ASYNC_LINK_STATUS_DOWN:
case LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN:
- att_type = AT_LINK_DOWN;
+ att_type = LPFC_ATT_LINK_DOWN;
break;
case LPFC_ASYNC_LINK_STATUS_UP:
/* Ignore physical link up events - wait for logical link up */
- att_type = AT_RESERVED;
+ att_type = LPFC_ATT_RESERVED;
break;
case LPFC_ASYNC_LINK_STATUS_LOGICAL_UP:
- att_type = AT_LINK_UP;
+ att_type = LPFC_ATT_LINK_UP;
break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0399 Invalid link attention type: x%x\n",
bf_get(lpfc_acqe_link_status, acqe_link));
- att_type = AT_RESERVED;
+ att_type = LPFC_ATT_RESERVED;
break;
}
return att_type;
switch (bf_get(lpfc_acqe_link_speed, acqe_link)) {
case LPFC_ASYNC_LINK_SPEED_ZERO:
- link_speed = LA_UNKNW_LINK;
- break;
case LPFC_ASYNC_LINK_SPEED_10MBPS:
- link_speed = LA_UNKNW_LINK;
- break;
case LPFC_ASYNC_LINK_SPEED_100MBPS:
- link_speed = LA_UNKNW_LINK;
+ link_speed = LPFC_LINK_SPEED_UNKNOWN;
break;
case LPFC_ASYNC_LINK_SPEED_1GBPS:
- link_speed = LA_1GHZ_LINK;
+ link_speed = LPFC_LINK_SPEED_1GHZ;
break;
case LPFC_ASYNC_LINK_SPEED_10GBPS:
- link_speed = LA_10GHZ_LINK;
+ link_speed = LPFC_LINK_SPEED_10GHZ;
break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0483 Invalid link-attention link speed: x%x\n",
bf_get(lpfc_acqe_link_speed, acqe_link));
- link_speed = LA_UNKNW_LINK;
+ link_speed = LPFC_LINK_SPEED_UNKNOWN;
break;
}
return link_speed;
}
/**
- * lpfc_sli4_async_link_evt - Process the asynchronous link event
+ * lpfc_sli4_async_link_evt - Process the asynchronous FCoE link event
* @phba: pointer to lpfc hba data structure.
* @acqe_link: pointer to the async link completion queue entry.
*
- * This routine is to handle the SLI4 asynchronous link event.
+ * This routine is to handle the SLI4 asynchronous FCoE link event.
**/
static void
lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
struct lpfc_dmabuf *mp;
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb;
- READ_LA_VAR *la;
+ struct lpfc_mbx_read_top *la;
uint8_t att_type;
+ int rc;
att_type = lpfc_sli4_parse_latt_type(phba, acqe_link);
- if (att_type != AT_LINK_DOWN && att_type != AT_LINK_UP)
+ if (att_type != LPFC_ATT_LINK_DOWN && att_type != LPFC_ATT_LINK_UP)
return;
phba->fcoe_eventtag = acqe_link->event_tag;
pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
/* Update link event statistics */
phba->sli.slistat.link_event++;
- /* Create pseudo lpfc_handle_latt mailbox command from link ACQE */
- lpfc_read_la(phba, pmb, mp);
+ /* Create lpfc_handle_latt mailbox command from link ACQE */
+ lpfc_read_topology(phba, pmb, mp);
+ pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology;
pmb->vport = phba->pport;
+ /* Keep the link status for extra SLI4 state machine reference */
+ phba->sli4_hba.link_state.speed =
+ bf_get(lpfc_acqe_link_speed, acqe_link);
+ phba->sli4_hba.link_state.duplex =
+ bf_get(lpfc_acqe_link_duplex, acqe_link);
+ phba->sli4_hba.link_state.status =
+ bf_get(lpfc_acqe_link_status, acqe_link);
+ phba->sli4_hba.link_state.type =
+ bf_get(lpfc_acqe_link_type, acqe_link);
+ phba->sli4_hba.link_state.number =
+ bf_get(lpfc_acqe_link_number, acqe_link);
+ phba->sli4_hba.link_state.fault =
+ bf_get(lpfc_acqe_link_fault, acqe_link);
+ phba->sli4_hba.link_state.logical_speed =
+ bf_get(lpfc_acqe_logical_link_speed, acqe_link);
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2900 Async FCoE Link event - Speed:%dGBit duplex:x%x "
+ "LA Type:x%x Port Type:%d Port Number:%d Logical "
+ "speed:%dMbps Fault:%d\n",
+ phba->sli4_hba.link_state.speed,
+ phba->sli4_hba.link_state.topology,
+ phba->sli4_hba.link_state.status,
+ phba->sli4_hba.link_state.type,
+ phba->sli4_hba.link_state.number,
+ phba->sli4_hba.link_state.logical_speed * 10,
+ phba->sli4_hba.link_state.fault);
+ /*
+ * For FC Mode: issue the READ_TOPOLOGY mailbox command to fetch
+ * topology info. Note: Optional for non FC-AL ports.
+ */
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED)
+ goto out_free_dmabuf;
+ return;
+ }
+ /*
+ * For FCoE Mode: fill in all the topology information we need and call
+ * the READ_TOPOLOGY completion routine to continue without actually
+ * sending the READ_TOPOLOGY mailbox command to the port.
+ */
/* Parse and translate status field */
mb = &pmb->u.mb;
mb->mbxStatus = lpfc_sli4_parse_latt_fault(phba, acqe_link);
/* Parse and translate link attention fields */
- la = (READ_LA_VAR *) &pmb->u.mb.un.varReadLA;
+ la = (struct lpfc_mbx_read_top *) &pmb->u.mb.un.varReadTop;
la->eventTag = acqe_link->event_tag;
- la->attType = att_type;
- la->UlnkSpeed = lpfc_sli4_parse_latt_link_speed(phba, acqe_link);
+ bf_set(lpfc_mbx_read_top_att_type, la, att_type);
+ bf_set(lpfc_mbx_read_top_link_spd, la,
+ lpfc_sli4_parse_latt_link_speed(phba, acqe_link));
/* Fake the the following irrelvant fields */
- la->topology = TOPOLOGY_PT_PT;
- la->granted_AL_PA = 0;
- la->il = 0;
- la->pb = 0;
- la->fa = 0;
- la->mm = 0;
+ bf_set(lpfc_mbx_read_top_topology, la, LPFC_TOPOLOGY_PT_PT);
+ bf_set(lpfc_mbx_read_top_alpa_granted, la, 0);
+ bf_set(lpfc_mbx_read_top_il, la, 0);
+ bf_set(lpfc_mbx_read_top_pb, la, 0);
+ bf_set(lpfc_mbx_read_top_fa, la, 0);
+ bf_set(lpfc_mbx_read_top_mm, la, 0);
+
+ /* Invoke the lpfc_handle_latt mailbox command callback function */
+ lpfc_mbx_cmpl_read_topology(phba, pmb);
+
+ return;
+out_free_dmabuf:
+ kfree(mp);
+out_free_pmb:
+ mempool_free(pmb, phba->mbox_mem_pool);
+}
+
+/**
+ * lpfc_sli4_async_fc_evt - Process the asynchronous FC link event
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_fc: pointer to the async fc completion queue entry.
+ *
+ * This routine is to handle the SLI4 asynchronous FC event. It will simply log
+ * that the event was received and then issue a read_topology mailbox command so
+ * that the rest of the driver will treat it the same as SLI3.
+ **/
+static void
+lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
+{
+ struct lpfc_dmabuf *mp;
+ LPFC_MBOXQ_t *pmb;
+ int rc;
+
+ if (bf_get(lpfc_trailer_type, acqe_fc) !=
+ LPFC_FC_LA_EVENT_TYPE_FC_LINK) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2895 Non FC link Event detected.(%d)\n",
+ bf_get(lpfc_trailer_type, acqe_fc));
+ return;
+ }
/* Keep the link status for extra SLI4 state machine reference */
phba->sli4_hba.link_state.speed =
- bf_get(lpfc_acqe_link_speed, acqe_link);
- phba->sli4_hba.link_state.duplex =
- bf_get(lpfc_acqe_link_duplex, acqe_link);
+ bf_get(lpfc_acqe_fc_la_speed, acqe_fc);
+ phba->sli4_hba.link_state.duplex = LPFC_ASYNC_LINK_DUPLEX_FULL;
+ phba->sli4_hba.link_state.topology =
+ bf_get(lpfc_acqe_fc_la_topology, acqe_fc);
phba->sli4_hba.link_state.status =
- bf_get(lpfc_acqe_link_status, acqe_link);
- phba->sli4_hba.link_state.physical =
- bf_get(lpfc_acqe_link_physical, acqe_link);
+ bf_get(lpfc_acqe_fc_la_att_type, acqe_fc);
+ phba->sli4_hba.link_state.type =
+ bf_get(lpfc_acqe_fc_la_port_type, acqe_fc);
+ phba->sli4_hba.link_state.number =
+ bf_get(lpfc_acqe_fc_la_port_number, acqe_fc);
phba->sli4_hba.link_state.fault =
- bf_get(lpfc_acqe_link_fault, acqe_link);
+ bf_get(lpfc_acqe_link_fault, acqe_fc);
phba->sli4_hba.link_state.logical_speed =
- bf_get(lpfc_acqe_qos_link_speed, acqe_link);
+ bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc);
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2896 Async FC event - Speed:%dGBaud Topology:x%x "
+ "LA Type:x%x Port Type:%d Port Number:%d Logical speed:"
+ "%dMbps Fault:%d\n",
+ phba->sli4_hba.link_state.speed,
+ phba->sli4_hba.link_state.topology,
+ phba->sli4_hba.link_state.status,
+ phba->sli4_hba.link_state.type,
+ phba->sli4_hba.link_state.number,
+ phba->sli4_hba.link_state.logical_speed * 10,
+ phba->sli4_hba.link_state.fault);
+ pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmb) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2897 The mboxq allocation failed\n");
+ return;
+ }
+ mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!mp) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2898 The lpfc_dmabuf allocation failed\n");
+ goto out_free_pmb;
+ }
+ mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+ if (!mp->virt) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2899 The mbuf allocation failed\n");
+ goto out_free_dmabuf;
+ }
- /* Invoke the lpfc_handle_latt mailbox command callback function */
- lpfc_mbx_cmpl_read_la(phba, pmb);
+ /* Cleanup any outstanding ELS commands */
+ lpfc_els_flush_all_cmd(phba);
+
+ /* Block ELS IOCBs until we have done process link event */
+ phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT;
+
+ /* Update link event statistics */
+ phba->sli.slistat.link_event++;
+
+ /* Create lpfc_handle_latt mailbox command from link ACQE */
+ lpfc_read_topology(phba, pmb, mp);
+ pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology;
+ pmb->vport = phba->pport;
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED)
+ goto out_free_dmabuf;
return;
out_free_dmabuf:
mempool_free(pmb, phba->mbox_mem_pool);
}
+/**
+ * lpfc_sli4_async_sli_evt - Process the asynchronous SLI link event
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_fc: pointer to the async SLI completion queue entry.
+ *
+ * This routine is to handle the SLI4 asynchronous SLI events.
+ **/
+static void
+lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
+{
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2901 Async SLI event - Event Data1:x%08x Event Data2:"
+ "x%08x SLI Event Type:%d",
+ acqe_sli->event_data1, acqe_sli->event_data2,
+ bf_get(lpfc_trailer_type, acqe_sli));
+ return;
+}
+
/**
* lpfc_sli4_perform_vport_cvl - Perform clear virtual link on a vport
* @vport: pointer to vport data structure.
if (!ndlp)
return 0;
}
- if (phba->pport->port_state < LPFC_FLOGI)
+ if ((phba->pport->port_state < LPFC_FLOGI) &&
+ (phba->pport->port_state != LPFC_VPORT_FAILED))
return NULL;
/* If virtual link is not yet instantiated ignore CVL */
- if ((vport != phba->pport) && (vport->port_state < LPFC_FDISC))
+ if ((vport != phba->pport) && (vport->port_state < LPFC_FDISC)
+ && (vport->port_state != LPFC_VPORT_FAILED))
return NULL;
shost = lpfc_shost_from_vport(vport);
if (!shost)
}
/**
- * lpfc_sli4_async_fcoe_evt - Process the asynchronous fcoe event
+ * lpfc_sli4_async_fip_evt - Process the asynchronous FCoE FIP event
* @phba: pointer to lpfc hba data structure.
* @acqe_link: pointer to the async fcoe completion queue entry.
*
* This routine is to handle the SLI4 asynchronous fcoe event.
**/
static void
-lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
- struct lpfc_acqe_fcoe *acqe_fcoe)
+lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
+ struct lpfc_acqe_fip *acqe_fip)
{
- uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe);
+ uint8_t event_type = bf_get(lpfc_trailer_type, acqe_fip);
int rc;
struct lpfc_vport *vport;
struct lpfc_nodelist *ndlp;
struct lpfc_vport **vports;
int i;
- phba->fc_eventTag = acqe_fcoe->event_tag;
- phba->fcoe_eventtag = acqe_fcoe->event_tag;
+ phba->fc_eventTag = acqe_fip->event_tag;
+ phba->fcoe_eventtag = acqe_fip->event_tag;
switch (event_type) {
- case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
- case LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD:
- if (event_type == LPFC_FCOE_EVENT_TYPE_NEW_FCF)
+ case LPFC_FIP_EVENT_TYPE_NEW_FCF:
+ case LPFC_FIP_EVENT_TYPE_FCF_PARAM_MOD:
+ if (event_type == LPFC_FIP_EVENT_TYPE_NEW_FCF)
lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
LOG_DISCOVERY,
"2546 New FCF event, evt_tag:x%x, "
"index:x%x\n",
- acqe_fcoe->event_tag,
- acqe_fcoe->index);
+ acqe_fip->event_tag,
+ acqe_fip->index);
else
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP |
LOG_DISCOVERY,
"2788 FCF param modified event, "
"evt_tag:x%x, index:x%x\n",
- acqe_fcoe->event_tag,
- acqe_fcoe->index);
+ acqe_fip->event_tag,
+ acqe_fip->index);
if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
/*
* During period of FCF discovery, read the FCF
LOG_DISCOVERY,
"2779 Read FCF (x%x) for updating "
"roundrobin FCF failover bmask\n",
- acqe_fcoe->index);
- rc = lpfc_sli4_read_fcf_rec(phba, acqe_fcoe->index);
+ acqe_fip->index);
+ rc = lpfc_sli4_read_fcf_rec(phba, acqe_fip->index);
}
/* If the FCF discovery is in progress, do nothing. */
lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
"2770 Start FCF table scan per async FCF "
"event, evt_tag:x%x, index:x%x\n",
- acqe_fcoe->event_tag, acqe_fcoe->index);
+ acqe_fip->event_tag, acqe_fip->index);
rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba,
LPFC_FCOE_FCF_GET_FIRST);
if (rc)
"command failed (x%x)\n", rc);
break;
- case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL:
+ case LPFC_FIP_EVENT_TYPE_FCF_TABLE_FULL:
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2548 FCF Table full count 0x%x tag 0x%x\n",
- bf_get(lpfc_acqe_fcoe_fcf_count, acqe_fcoe),
- acqe_fcoe->event_tag);
+ bf_get(lpfc_acqe_fip_fcf_count, acqe_fip),
+ acqe_fip->event_tag);
break;
- case LPFC_FCOE_EVENT_TYPE_FCF_DEAD:
+ case LPFC_FIP_EVENT_TYPE_FCF_DEAD:
lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
"2549 FCF (x%x) disconnected from network, "
- "tag:x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag);
+ "tag:x%x\n", acqe_fip->index, acqe_fip->event_tag);
/*
* If we are in the middle of FCF failover process, clear
* the corresponding FCF bit in the roundrobin bitmap.
if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
spin_unlock_irq(&phba->hbalock);
/* Update FLOGI FCF failover eligible FCF bmask */
- lpfc_sli4_fcf_rr_index_clear(phba, acqe_fcoe->index);
+ lpfc_sli4_fcf_rr_index_clear(phba, acqe_fip->index);
break;
}
spin_unlock_irq(&phba->hbalock);
/* If the event is not for currently used fcf do nothing */
- if (phba->fcf.current_rec.fcf_indx != acqe_fcoe->index)
+ if (phba->fcf.current_rec.fcf_indx != acqe_fip->index)
break;
/*
lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
"2771 Start FCF fast failover process due to "
"FCF DEAD event: evt_tag:x%x, fcf_index:x%x "
- "\n", acqe_fcoe->event_tag, acqe_fcoe->index);
+ "\n", acqe_fip->event_tag, acqe_fip->index);
rc = lpfc_sli4_redisc_fcf_table(phba);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
lpfc_sli4_perform_all_vport_cvl(phba);
}
break;
- case LPFC_FCOE_EVENT_TYPE_CVL:
+ case LPFC_FIP_EVENT_TYPE_CVL:
lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
"2718 Clear Virtual Link Received for VPI 0x%x"
- " tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag);
+ " tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag);
vport = lpfc_find_vport_by_vpid(phba,
- acqe_fcoe->index - phba->vpi_base);
+ acqe_fip->index - phba->vpi_base);
ndlp = lpfc_sli4_perform_vport_cvl(vport);
if (!ndlp)
break;
lpfc_printf_log(phba, KERN_INFO, LOG_FIP |
LOG_DISCOVERY,
"2773 Start FCF failover per CVL, "
- "evt_tag:x%x\n", acqe_fcoe->event_tag);
+ "evt_tag:x%x\n", acqe_fip->event_tag);
rc = lpfc_sli4_redisc_fcf_table(phba);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
default:
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0288 Unknown FCoE event type 0x%x event tag "
- "0x%x\n", event_type, acqe_fcoe->event_tag);
+ "0x%x\n", event_type, acqe_fip->event_tag);
break;
}
}
&cq_event->cqe.acqe_link);
break;
case LPFC_TRAILER_CODE_FCOE:
- lpfc_sli4_async_fcoe_evt(phba,
- &cq_event->cqe.acqe_fcoe);
+ lpfc_sli4_async_fip_evt(phba, &cq_event->cqe.acqe_fip);
break;
case LPFC_TRAILER_CODE_DCBX:
lpfc_sli4_async_dcbx_evt(phba,
lpfc_sli4_async_grp5_evt(phba,
&cq_event->cqe.acqe_grp5);
break;
+ case LPFC_TRAILER_CODE_FC:
+ lpfc_sli4_async_fc_evt(phba, &cq_event->cqe.acqe_fc);
+ break;
+ case LPFC_TRAILER_CODE_SLI:
+ lpfc_sli4_async_sli_evt(phba, &cq_event->cqe.acqe_sli);
+ break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"1804 Invalid asynchrous event code: "
int rc, i, hbq_count, buf_size, dma_buf_size, max_buf_size;
uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0};
struct lpfc_mqe *mqe;
- int longs;
+ int longs, sli_family;
/* Before proceed, wait for POST done and device ready */
rc = lpfc_sli4_post_status_check(phba);
init_timer(&phba->hb_tmofunc);
phba->hb_tmofunc.function = lpfc_hb_timeout;
phba->hb_tmofunc.data = (unsigned long)phba;
+ init_timer(&phba->rrq_tmr);
+ phba->rrq_tmr.function = lpfc_rrq_timeout;
+ phba->rrq_tmr.data = (unsigned long)phba;
psli = &phba->sli;
/* MBOX heartbeat timer */
*/
buf_size = (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) +
((phba->cfg_sg_seg_cnt + 2) * sizeof(struct sli4_sge)));
- /* Feature Level 1 hardware is limited to 2 pages */
- if ((bf_get(lpfc_sli_intf_featurelevel1, &phba->sli4_hba.sli_intf) ==
- LPFC_SLI_INTF_FEATURELEVEL1_1))
- max_buf_size = LPFC_SLI4_FL1_MAX_BUF_SIZE;
- else
- max_buf_size = LPFC_SLI4_MAX_BUF_SIZE;
+
+ sli_family = bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf);
+ max_buf_size = LPFC_SLI4_MAX_BUF_SIZE;
+ switch (sli_family) {
+ case LPFC_SLI_INTF_FAMILY_BE2:
+ case LPFC_SLI_INTF_FAMILY_BE3:
+ /* There is a single hint for BE - 2 pages per BPL. */
+ if (bf_get(lpfc_sli_intf_sli_hint1, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_SLI_HINT1_1)
+ max_buf_size = LPFC_SLI4_FL1_MAX_BUF_SIZE;
+ break;
+ case LPFC_SLI_INTF_FAMILY_LNCR_A0:
+ case LPFC_SLI_INTF_FAMILY_LNCR_B0:
+ default:
+ break;
+ }
for (dma_buf_size = LPFC_SLI4_MIN_BUF_SIZE;
dma_buf_size < max_buf_size && buf_size > dma_buf_size;
dma_buf_size = dma_buf_size << 1)
if (rc)
return -ENOMEM;
+ /* IF Type 2 ports get initialized now. */
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_2) {
+ rc = lpfc_pci_function_reset(phba);
+ if (unlikely(rc))
+ return -ENODEV;
+ }
+
/* Create the bootstrap mailbox command */
rc = lpfc_create_bootstrap_mbox(phba);
if (unlikely(rc))
if (unlikely(rc))
goto out_free_bsmbx;
- rc = lpfc_sli4_fw_cfg_check(phba);
- if (unlikely(rc))
- goto out_free_bsmbx;
-
/* Set up the hba's configuration parameters. */
rc = lpfc_sli4_read_config(phba);
if (unlikely(rc))
goto out_free_bsmbx;
- /* Perform a function reset */
- rc = lpfc_pci_function_reset(phba);
- if (unlikely(rc))
- goto out_free_bsmbx;
+ /* IF Type 0 ports get initialized now. */
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_0) {
+ rc = lpfc_pci_function_reset(phba);
+ if (unlikely(rc))
+ goto out_free_bsmbx;
+ }
mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
GFP_KERNEL);
int
lpfc_sli4_post_status_check(struct lpfc_hba *phba)
{
- struct lpfc_register sta_reg, uerrlo_reg, uerrhi_reg;
- int i, port_error = -ENODEV;
+ struct lpfc_register portsmphr_reg, uerrlo_reg, uerrhi_reg;
+ struct lpfc_register reg_data;
+ int i, port_error = 0;
+ uint32_t if_type;
- if (!phba->sli4_hba.STAregaddr)
+ if (!phba->sli4_hba.PSMPHRregaddr)
return -ENODEV;
/* Wait up to 30 seconds for the SLI Port POST done and ready */
for (i = 0; i < 3000; i++) {
- sta_reg.word0 = readl(phba->sli4_hba.STAregaddr);
- /* Encounter fatal POST error, break out */
- if (bf_get(lpfc_hst_state_perr, &sta_reg)) {
+ portsmphr_reg.word0 = readl(phba->sli4_hba.PSMPHRregaddr);
+ if (bf_get(lpfc_port_smphr_perr, &portsmphr_reg)) {
+ /* Port has a fatal POST error, break out */
port_error = -ENODEV;
break;
}
- if (LPFC_POST_STAGE_ARMFW_READY ==
- bf_get(lpfc_hst_state_port_status, &sta_reg)) {
- port_error = 0;
+ if (LPFC_POST_STAGE_PORT_READY ==
+ bf_get(lpfc_port_smphr_port_status, &portsmphr_reg))
break;
- }
msleep(10);
}
- if (port_error)
+ /*
+ * If there was a port error during POST, then don't proceed with
+ * other register reads as the data may not be valid. Just exit.
+ */
+ if (port_error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1408 Failure HBA POST Status: sta_reg=0x%x, "
- "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, xrom=x%x, "
- "dl=x%x, pstatus=x%x\n", sta_reg.word0,
- bf_get(lpfc_hst_state_perr, &sta_reg),
- bf_get(lpfc_hst_state_sfi, &sta_reg),
- bf_get(lpfc_hst_state_nip, &sta_reg),
- bf_get(lpfc_hst_state_ipc, &sta_reg),
- bf_get(lpfc_hst_state_xrom, &sta_reg),
- bf_get(lpfc_hst_state_dl, &sta_reg),
- bf_get(lpfc_hst_state_port_status, &sta_reg));
-
- /* Log device information */
- phba->sli4_hba.sli_intf.word0 = readl(phba->sli4_hba.SLIINTFregaddr);
- if (bf_get(lpfc_sli_intf_valid,
- &phba->sli4_hba.sli_intf) == LPFC_SLI_INTF_VALID) {
+ "1408 Port Failed POST - portsmphr=0x%x, "
+ "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, scr1=x%x, "
+ "scr2=x%x, hscratch=x%x, pstatus=x%x\n",
+ portsmphr_reg.word0,
+ bf_get(lpfc_port_smphr_perr, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_sfi, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_nip, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_ipc, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_scr1, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_scr2, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_host_scratch, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_port_status, &portsmphr_reg));
+ } else {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "2534 Device Info: ChipType=0x%x, SliRev=0x%x, "
- "FeatureL1=0x%x, FeatureL2=0x%x\n",
+ "2534 Device Info: SLIFamily=0x%x, "
+ "SLIRev=0x%x, IFType=0x%x, SLIHint_1=0x%x, "
+ "SLIHint_2=0x%x, FT=0x%x\n",
bf_get(lpfc_sli_intf_sli_family,
&phba->sli4_hba.sli_intf),
bf_get(lpfc_sli_intf_slirev,
&phba->sli4_hba.sli_intf),
- bf_get(lpfc_sli_intf_featurelevel1,
+ bf_get(lpfc_sli_intf_if_type,
+ &phba->sli4_hba.sli_intf),
+ bf_get(lpfc_sli_intf_sli_hint1,
&phba->sli4_hba.sli_intf),
- bf_get(lpfc_sli_intf_featurelevel2,
+ bf_get(lpfc_sli_intf_sli_hint2,
+ &phba->sli4_hba.sli_intf),
+ bf_get(lpfc_sli_intf_func_type,
&phba->sli4_hba.sli_intf));
+ /*
+ * Check for other Port errors during the initialization
+ * process. Fail the load if the port did not come up
+ * correctly.
+ */
+ if_type = bf_get(lpfc_sli_intf_if_type,
+ &phba->sli4_hba.sli_intf);
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ phba->sli4_hba.ue_mask_lo =
+ readl(phba->sli4_hba.u.if_type0.UEMASKLOregaddr);
+ phba->sli4_hba.ue_mask_hi =
+ readl(phba->sli4_hba.u.if_type0.UEMASKHIregaddr);
+ uerrlo_reg.word0 =
+ readl(phba->sli4_hba.u.if_type0.UERRLOregaddr);
+ uerrhi_reg.word0 =
+ readl(phba->sli4_hba.u.if_type0.UERRHIregaddr);
+ if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) ||
+ (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "1422 Unrecoverable Error "
+ "Detected during POST "
+ "uerr_lo_reg=0x%x, "
+ "uerr_hi_reg=0x%x, "
+ "ue_mask_lo_reg=0x%x, "
+ "ue_mask_hi_reg=0x%x\n",
+ uerrlo_reg.word0,
+ uerrhi_reg.word0,
+ phba->sli4_hba.ue_mask_lo,
+ phba->sli4_hba.ue_mask_hi);
+ port_error = -ENODEV;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ /* Final checks. The port status should be clean. */
+ reg_data.word0 =
+ readl(phba->sli4_hba.u.if_type2.STATUSregaddr);
+ if (bf_get(lpfc_sliport_status_err, ®_data)) {
+ phba->work_status[0] =
+ readl(phba->sli4_hba.u.if_type2.
+ ERR1regaddr);
+ phba->work_status[1] =
+ readl(phba->sli4_hba.u.if_type2.
+ ERR2regaddr);
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2888 Port Error Detected "
+ "during POST: "
+ "port status reg 0x%x, "
+ "port_smphr reg 0x%x, "
+ "error 1=0x%x, error 2=0x%x\n",
+ reg_data.word0,
+ portsmphr_reg.word0,
+ phba->work_status[0],
+ phba->work_status[1]);
+ port_error = -ENODEV;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ break;
+ }
}
- phba->sli4_hba.ue_mask_lo = readl(phba->sli4_hba.UEMASKLOregaddr);
- phba->sli4_hba.ue_mask_hi = readl(phba->sli4_hba.UEMASKHIregaddr);
- /* With uncoverable error, log the error message and return error */
- uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr);
- uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr);
- if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) ||
- (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1422 HBA Unrecoverable error: "
- "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
- "ue_mask_lo_reg=0x%x, ue_mask_hi_reg=0x%x\n",
- uerrlo_reg.word0, uerrhi_reg.word0,
- phba->sli4_hba.ue_mask_lo,
- phba->sli4_hba.ue_mask_hi);
- return -ENODEV;
- }
-
return port_error;
}
/**
* lpfc_sli4_bar0_register_memmap - Set up SLI4 BAR0 register memory map.
* @phba: pointer to lpfc hba data structure.
+ * @if_type: The SLI4 interface type getting configured.
*
* This routine is invoked to set up SLI4 BAR0 PCI config space register
* memory map.
**/
static void
-lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba)
-{
- phba->sli4_hba.UERRLOregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_UERR_STATUS_LO;
- phba->sli4_hba.UERRHIregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_UERR_STATUS_HI;
- phba->sli4_hba.UEMASKLOregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_UE_MASK_LO;
- phba->sli4_hba.UEMASKHIregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_UE_MASK_HI;
- phba->sli4_hba.SLIINTFregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_SLI_INTF;
+lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
+{
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ phba->sli4_hba.u.if_type0.UERRLOregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_UERR_STATUS_LO;
+ phba->sli4_hba.u.if_type0.UERRHIregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_UERR_STATUS_HI;
+ phba->sli4_hba.u.if_type0.UEMASKLOregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_UE_MASK_LO;
+ phba->sli4_hba.u.if_type0.UEMASKHIregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_UE_MASK_HI;
+ phba->sli4_hba.SLIINTFregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF;
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ phba->sli4_hba.u.if_type2.ERR1regaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_1;
+ phba->sli4_hba.u.if_type2.ERR2regaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_2;
+ phba->sli4_hba.u.if_type2.CTRLregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_CNTRL;
+ phba->sli4_hba.u.if_type2.STATUSregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_STATUS;
+ phba->sli4_hba.SLIINTFregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF;
+ phba->sli4_hba.PSMPHRregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_IF2_SMPHR;
+ phba->sli4_hba.RQDBregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_RQ_DOORBELL;
+ phba->sli4_hba.WQDBregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_WQ_DOORBELL;
+ phba->sli4_hba.EQCQDBregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_EQCQ_DOORBELL;
+ phba->sli4_hba.MQDBregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_MQ_DOORBELL;
+ phba->sli4_hba.BMBXregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX;
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ dev_printk(KERN_ERR, &phba->pcidev->dev,
+ "FATAL - unsupported SLI4 interface type - %d\n",
+ if_type);
+ break;
+ }
}
/**
static void
lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba)
{
-
- phba->sli4_hba.STAregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_STATE;
+ phba->sli4_hba.PSMPHRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+ LPFC_SLIPORT_IF0_SMPHR;
phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_ISR0;
+ LPFC_HST_ISR0;
phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_IMR0;
+ LPFC_HST_IMR0;
phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_ISCR0;
- return;
+ LPFC_HST_ISCR0;
}
/**
}
/**
- * lpfc_dev_endian_order_setup - Notify the port of the host's endian order.
+ * lpfc_setup_endian_order - Write endian order to an SLI4 if_type 0 port.
* @phba: pointer to lpfc hba data structure.
*
- * This routine is invoked to setup the host-side endian order to the
- * HBA consistent with the SLI-4 interface spec.
+ * This routine is invoked to setup the port-side endian order when
+ * the port if_type is 0. This routine has no function for other
+ * if_types.
*
* Return codes
* 0 - successful
lpfc_setup_endian_order(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *mboxq;
- uint32_t rc = 0;
+ uint32_t if_type, rc = 0;
uint32_t endian_mb_data[2] = {HOST_ENDIAN_LOW_WORD0,
HOST_ENDIAN_HIGH_WORD1};
- mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mboxq) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0492 Unable to allocate memory for issuing "
- "SLI_CONFIG_SPECIAL mailbox command\n");
- return -ENOMEM;
- }
+ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+ GFP_KERNEL);
+ if (!mboxq) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0492 Unable to allocate memory for "
+ "issuing SLI_CONFIG_SPECIAL mailbox "
+ "command\n");
+ return -ENOMEM;
+ }
- /*
- * The SLI4_CONFIG_SPECIAL mailbox command requires the first two
- * words to contain special data values and no other data.
- */
- memset(mboxq, 0, sizeof(LPFC_MBOXQ_t));
- memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data));
- rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
- if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0493 SLI_CONFIG_SPECIAL mailbox failed with "
- "status x%x\n",
- rc);
- rc = -EIO;
+ /*
+ * The SLI4_CONFIG_SPECIAL mailbox command requires the first
+ * two words to contain special data values and no other data.
+ */
+ memset(mboxq, 0, sizeof(LPFC_MBOXQ_t));
+ memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data));
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+ if (rc != MBX_SUCCESS) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0493 SLI_CONFIG_SPECIAL mailbox "
+ "failed with status x%x\n",
+ rc);
+ rc = -EIO;
+ }
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ break;
}
-
- mempool_free(mboxq, phba->mbox_mem_pool);
return rc;
}
lpfc_pci_function_reset(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *mboxq;
- uint32_t rc = 0;
+ uint32_t rc = 0, if_type;
uint32_t shdr_status, shdr_add_status;
+ uint32_t rdy_chk, num_resets = 0, reset_again = 0;
union lpfc_sli4_cfg_shdr *shdr;
+ struct lpfc_register reg_data;
- mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mboxq) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0494 Unable to allocate memory for issuing "
- "SLI_FUNCTION_RESET mailbox command\n");
- return -ENOMEM;
- }
+ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+ GFP_KERNEL);
+ if (!mboxq) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0494 Unable to allocate memory for "
+ "issuing SLI_FUNCTION_RESET mailbox "
+ "command\n");
+ return -ENOMEM;
+ }
- /* Set up PCI function reset SLI4_CONFIG mailbox-ioctl command */
- lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
- LPFC_MBOX_OPCODE_FUNCTION_RESET, 0,
- LPFC_SLI4_MBX_EMBED);
- rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
- shdr = (union lpfc_sli4_cfg_shdr *)
- &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
- shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
- shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
- if (rc != MBX_TIMEOUT)
- mempool_free(mboxq, phba->mbox_mem_pool);
- if (shdr_status || shdr_add_status || rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0495 SLI_FUNCTION_RESET mailbox failed with "
- "status x%x add_status x%x, mbx status x%x\n",
- shdr_status, shdr_add_status, rc);
- rc = -ENXIO;
+ /* Setup PCI function reset mailbox-ioctl command */
+ lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+ LPFC_MBOX_OPCODE_FUNCTION_RESET, 0,
+ LPFC_SLI4_MBX_EMBED);
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+ shdr = (union lpfc_sli4_cfg_shdr *)
+ &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
+ shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+ shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+ &shdr->response);
+ if (rc != MBX_TIMEOUT)
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ if (shdr_status || shdr_add_status || rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0495 SLI_FUNCTION_RESET mailbox "
+ "failed with status x%x add_status x%x,"
+ " mbx status x%x\n",
+ shdr_status, shdr_add_status, rc);
+ rc = -ENXIO;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ for (num_resets = 0;
+ num_resets < MAX_IF_TYPE_2_RESETS;
+ num_resets++) {
+ reg_data.word0 = 0;
+ bf_set(lpfc_sliport_ctrl_end, ®_data,
+ LPFC_SLIPORT_LITTLE_ENDIAN);
+ bf_set(lpfc_sliport_ctrl_ip, ®_data,
+ LPFC_SLIPORT_INIT_PORT);
+ writel(reg_data.word0, phba->sli4_hba.u.if_type2.
+ CTRLregaddr);
+
+ /*
+ * Poll the Port Status Register and wait for RDY for
+ * up to 10 seconds. If the port doesn't respond, treat
+ * it as an error. If the port responds with RN, start
+ * the loop again.
+ */
+ for (rdy_chk = 0; rdy_chk < 1000; rdy_chk++) {
+ reg_data.word0 =
+ readl(phba->sli4_hba.u.if_type2.
+ STATUSregaddr);
+ if (bf_get(lpfc_sliport_status_rdy, ®_data))
+ break;
+ if (bf_get(lpfc_sliport_status_rn, ®_data)) {
+ reset_again++;
+ break;
+ }
+ msleep(10);
+ }
+
+ /*
+ * If the port responds to the init request with
+ * reset needed, delay for a bit and restart the loop.
+ */
+ if (reset_again) {
+ msleep(10);
+ reset_again = 0;
+ continue;
+ }
+
+ /* Detect any port errors. */
+ reg_data.word0 = readl(phba->sli4_hba.u.if_type2.
+ STATUSregaddr);
+ if ((bf_get(lpfc_sliport_status_err, ®_data)) ||
+ (rdy_chk >= 1000)) {
+ phba->work_status[0] = readl(
+ phba->sli4_hba.u.if_type2.ERR1regaddr);
+ phba->work_status[1] = readl(
+ phba->sli4_hba.u.if_type2.ERR2regaddr);
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2890 Port Error Detected "
+ "during Port Reset: "
+ "port status reg 0x%x, "
+ "error 1=0x%x, error 2=0x%x\n",
+ reg_data.word0,
+ phba->work_status[0],
+ phba->work_status[1]);
+ rc = -ENODEV;
+ }
+
+ /*
+ * Terminate the outer loop provided the Port indicated
+ * ready within 10 seconds.
+ */
+ if (rdy_chk < 1000)
+ break;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ break;
}
+
+ /* Catch the not-ready port failure after a port reset. */
+ if (num_resets >= MAX_IF_TYPE_2_RESETS)
+ rc = -ENODEV;
+
return rc;
}
struct pci_dev *pdev;
unsigned long bar0map_len, bar1map_len, bar2map_len;
int error = -ENODEV;
+ uint32_t if_type;
/* Obtain PCI device reference */
if (!phba->pcidev)
}
}
- /* Get the bus address of SLI4 device Bar0, Bar1, and Bar2 and the
- * number of bytes required by each mapping. They are actually
- * mapping to the PCI BAR regions 0 or 1, 2, and 4 by the SLI4 device.
+ /*
+ * The BARs and register set definitions and offset locations are
+ * dependent on the if_type.
+ */
+ if (pci_read_config_dword(pdev, LPFC_SLI_INTF,
+ &phba->sli4_hba.sli_intf.word0)) {
+ return error;
+ }
+
+ /* There is no SLI3 failback for SLI4 devices. */
+ if (bf_get(lpfc_sli_intf_valid, &phba->sli4_hba.sli_intf) !=
+ LPFC_SLI_INTF_VALID) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2894 SLI_INTF reg contents invalid "
+ "sli_intf reg 0x%x\n",
+ phba->sli4_hba.sli_intf.word0);
+ return error;
+ }
+
+ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+ /*
+ * Get the bus address of SLI4 device Bar regions and the
+ * number of bytes required by each mapping. The mapping of the
+ * particular PCI BARs regions is dependent on the type of
+ * SLI4 device.
*/
if (pci_resource_start(pdev, 0)) {
phba->pci_bar0_map = pci_resource_start(pdev, 0);
bar0map_len = pci_resource_len(pdev, 0);
+
+ /*
+ * Map SLI4 PCI Config Space Register base to a kernel virtual
+ * addr
+ */
+ phba->sli4_hba.conf_regs_memmap_p =
+ ioremap(phba->pci_bar0_map, bar0map_len);
+ if (!phba->sli4_hba.conf_regs_memmap_p) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "ioremap failed for SLI4 PCI config "
+ "registers.\n");
+ goto out;
+ }
+ /* Set up BAR0 PCI config space register memory map */
+ lpfc_sli4_bar0_register_memmap(phba, if_type);
} else {
phba->pci_bar0_map = pci_resource_start(pdev, 1);
bar0map_len = pci_resource_len(pdev, 1);
- }
- phba->pci_bar1_map = pci_resource_start(pdev, 2);
- bar1map_len = pci_resource_len(pdev, 2);
-
- phba->pci_bar2_map = pci_resource_start(pdev, 4);
- bar2map_len = pci_resource_len(pdev, 4);
-
- /* Map SLI4 PCI Config Space Register base to a kernel virtual addr */
- phba->sli4_hba.conf_regs_memmap_p =
+ if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "FATAL - No BAR0 mapping for SLI4, if_type 2\n");
+ goto out;
+ }
+ phba->sli4_hba.conf_regs_memmap_p =
ioremap(phba->pci_bar0_map, bar0map_len);
- if (!phba->sli4_hba.conf_regs_memmap_p) {
- dev_printk(KERN_ERR, &pdev->dev,
- "ioremap failed for SLI4 PCI config registers.\n");
- goto out;
+ if (!phba->sli4_hba.conf_regs_memmap_p) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "ioremap failed for SLI4 PCI config "
+ "registers.\n");
+ goto out;
+ }
+ lpfc_sli4_bar0_register_memmap(phba, if_type);
}
- /* Map SLI4 HBA Control Register base to a kernel virtual address. */
- phba->sli4_hba.ctrl_regs_memmap_p =
+ if (pci_resource_start(pdev, 2)) {
+ /*
+ * Map SLI4 if type 0 HBA Control Register base to a kernel
+ * virtual address and setup the registers.
+ */
+ phba->pci_bar1_map = pci_resource_start(pdev, 2);
+ bar1map_len = pci_resource_len(pdev, 2);
+ phba->sli4_hba.ctrl_regs_memmap_p =
ioremap(phba->pci_bar1_map, bar1map_len);
- if (!phba->sli4_hba.ctrl_regs_memmap_p) {
- dev_printk(KERN_ERR, &pdev->dev,
+ if (!phba->sli4_hba.ctrl_regs_memmap_p) {
+ dev_printk(KERN_ERR, &pdev->dev,
"ioremap failed for SLI4 HBA control registers.\n");
- goto out_iounmap_conf;
+ goto out_iounmap_conf;
+ }
+ lpfc_sli4_bar1_register_memmap(phba);
}
- /* Map SLI4 HBA Doorbell Register base to a kernel virtual address. */
- phba->sli4_hba.drbl_regs_memmap_p =
+ if (pci_resource_start(pdev, 4)) {
+ /*
+ * Map SLI4 if type 0 HBA Doorbell Register base to a kernel
+ * virtual address and setup the registers.
+ */
+ phba->pci_bar2_map = pci_resource_start(pdev, 4);
+ bar2map_len = pci_resource_len(pdev, 4);
+ phba->sli4_hba.drbl_regs_memmap_p =
ioremap(phba->pci_bar2_map, bar2map_len);
- if (!phba->sli4_hba.drbl_regs_memmap_p) {
- dev_printk(KERN_ERR, &pdev->dev,
+ if (!phba->sli4_hba.drbl_regs_memmap_p) {
+ dev_printk(KERN_ERR, &pdev->dev,
"ioremap failed for SLI4 HBA doorbell registers.\n");
- goto out_iounmap_ctrl;
+ goto out_iounmap_ctrl;
+ }
+ error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0);
+ if (error)
+ goto out_iounmap_all;
}
- /* Set up BAR0 PCI config space register memory map */
- lpfc_sli4_bar0_register_memmap(phba);
-
- /* Set up BAR1 register memory map */
- lpfc_sli4_bar1_register_memmap(phba);
-
- /* Set up BAR2 register memory map */
- error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0);
- if (error)
- goto out_iounmap_all;
-
return 0;
out_iounmap_all:
goto out_unset_driver_resource_s4;
}
+ INIT_LIST_HEAD(&phba->active_rrq_list);
+
/* Set up common device driver resources */
error = lpfc_setup_driver_resource_phase2(phba);
if (error) {
"0451 Configure interrupt mode (%d) "
"failed active interrupt test.\n",
intr_mode);
- /* Unset the preivous SLI-4 HBA setup */
+ /* Unset the previous SLI-4 HBA setup. */
+ /*
+ * TODO: Is this operation compatible with IF TYPE 2
+ * devices? All port state is deleted and cleared.
+ */
lpfc_sli4_unset_hba(phba);
/* Try next level of interrupt mode */
cfg_mode = --intr_mode;
PCI_ANY_ID, PCI_ANY_ID, },
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS,
PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE,
+ PCI_ANY_ID, PCI_ANY_ID, },
{ 0 }
};
#define LOG_FCP_ERROR 0x00001000 /* log errors, not underruns */
#define LOG_LIBDFC 0x00002000 /* Libdfc events */
#define LOG_VPORT 0x00004000 /* NPIV events */
-#define LOF_SECURITY 0x00008000 /* Security events */
+#define LOG_SECURITY 0x00008000 /* Security events */
#define LOG_EVENT 0x00010000 /* CT,TEMP,DUMP, logging */
#define LOG_FIP 0x00020000 /* FIP events */
#define LOG_ALL_MSG 0xffffffff /* LOG all messages */
}
/**
- * lpfc_read_la - Prepare a mailbox command for reading HBA link attention
+ * lpfc_read_topology - Prepare a mailbox command for reading HBA topology
* @phba: pointer to lpfc hba data structure.
* @pmb: pointer to the driver internal queue element for mailbox command.
* @mp: DMA buffer memory for reading the link attention information into.
*
- * The read link attention mailbox command is issued to read the Link Event
- * Attention information indicated by the HBA port when the Link Event bit
- * of the Host Attention (HSTATT) register is set to 1. A Link Event
+ * The read topology mailbox command is issued to read the link topology
+ * information indicated by the HBA port when the Link Event bit of the Host
+ * Attention (HSTATT) register is set to 1 (For SLI-3) or when an FC Link
+ * Attention ACQE is received from the port (For SLI-4). A Link Event
* Attention occurs based on an exception detected at the Fibre Channel link
* interface.
*
- * This routine prepares the mailbox command for reading HBA link attention
+ * This routine prepares the mailbox command for reading HBA link topology
* information. A DMA memory has been set aside and address passed to the
* HBA through @mp for the HBA to DMA link attention information into the
* memory as part of the execution of the mailbox command.
* 0 - Success (currently always return 0)
**/
int
-lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp)
+lpfc_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb,
+ struct lpfc_dmabuf *mp)
{
MAILBOX_t *mb;
struct lpfc_sli *psli;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
INIT_LIST_HEAD(&mp->list);
- mb->mbxCommand = MBX_READ_LA64;
- mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize = 128;
- mb->un.varReadLA.un.lilpBde64.addrHigh = putPaddrHigh(mp->phys);
- mb->un.varReadLA.un.lilpBde64.addrLow = putPaddrLow(mp->phys);
+ mb->mbxCommand = MBX_READ_TOPOLOGY;
+ mb->un.varReadTop.lilpBde64.tus.f.bdeSize = LPFC_ALPA_MAP_SIZE;
+ mb->un.varReadTop.lilpBde64.addrHigh = putPaddrHigh(mp->phys);
+ mb->un.varReadTop.lilpBde64.addrLow = putPaddrLow(mp->phys);
/* Save address for later completion and set the owner to host so that
* the FW knows this mailbox is available for processing.
*/
- pmb->context1 = (uint8_t *) mp;
+ pmb->context1 = (uint8_t *)mp;
mb->mbxOwner = OWN_HOST;
return (0);
}
vpd = &phba->vpd;
if (vpd->rev.feaLevelHigh >= 0x02){
switch(linkspeed){
- case LINK_SPEED_1G:
- case LINK_SPEED_2G:
- case LINK_SPEED_4G:
- case LINK_SPEED_8G:
- mb->un.varInitLnk.link_flags |=
- FLAGS_LINK_SPEED;
- mb->un.varInitLnk.link_speed = linkspeed;
+ case LPFC_USER_LINK_SPEED_1G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_1G;
+ break;
+ case LPFC_USER_LINK_SPEED_2G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_2G;
+ break;
+ case LPFC_USER_LINK_SPEED_4G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_4G;
+ break;
+ case LPFC_USER_LINK_SPEED_8G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_8G;
+ break;
+ case LPFC_USER_LINK_SPEED_10G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_10G;
break;
- case LINK_SPEED_AUTO:
- default:
- mb->un.varInitLnk.link_speed =
- LINK_SPEED_AUTO;
+ case LPFC_USER_LINK_SPEED_16G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_16G;
+ break;
+ case LPFC_USER_LINK_SPEED_AUTO:
+ default:
+ mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO;
break;
}
* @did: remote port identifier.
* @param: pointer to memory holding the server parameters.
* @pmb: pointer to the driver internal queue element for mailbox command.
- * @flag: action flag to be passed back for the complete function.
+ * @rpi: the rpi to use in the registration (usually only used for SLI4.
*
* The registration login mailbox command is used to register an N_Port or
* F_Port login. This registration allows the HBA to cache the remote N_Port
**/
int
lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
- uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag)
+ uint8_t *param, LPFC_MBOXQ_t *pmb, uint16_t rpi)
{
MAILBOX_t *mb = &pmb->u.mb;
uint8_t *sparam;
mb->un.varRegLogin.rpi = 0;
if (phba->sli_rev == LPFC_SLI_REV4) {
- mb->un.varRegLogin.rpi = lpfc_sli4_alloc_rpi(phba);
+ mb->un.varRegLogin.rpi = rpi;
if (mb->un.varRegLogin.rpi == LPFC_RPI_ALLOC_ERROR)
return 1;
}
-
mb->un.varRegLogin.vpi = vpi + phba->vpi_base;
mb->un.varRegLogin.did = did;
- mb->un.varWords[30] = flag; /* Set flag to issue action on cmpl */
-
mb->mbxOwner = OWN_HOST;
-
/* Get a buffer to hold NPorts Service Parameters */
mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
if (mp)
/* REG_LOGIN: no buffers */
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
"0302 REG_LOGIN: no buffers, VPI:%d DID:x%x, "
- "flag x%x\n", vpi, did, flag);
+ "rpi x%x\n", vpi, did, rpi);
return (1);
}
INIT_LIST_HEAD(&mp->list);
struct lpfc_mbx_init_vfi *init_vfi;
memset(mbox, 0, sizeof(*mbox));
+ mbox->vport = vport;
init_vfi = &mbox->u.mqe.un.init_vfi;
bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VFI);
bf_set(lpfc_init_vfi_vr, init_vfi, 1);
bf_set(lpfc_init_vfi_vt, init_vfi, 1);
+ bf_set(lpfc_init_vfi_vp, init_vfi, 1);
bf_set(lpfc_init_vfi_vfi, init_vfi, vport->vfi + vport->phba->vfi_base);
+ bf_set(lpfc_init_vpi_vpi, init_vfi, vport->vpi + vport->phba->vpi_base);
bf_set(lpfc_init_vfi_fcfi, init_vfi, vport->phba->fcf.fcfi);
}
goto fail_free_mbox_pool;
if (phba->sli_rev == LPFC_SLI_REV4) {
+ phba->rrq_pool =
+ mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE,
+ sizeof(struct lpfc_node_rrq));
+ if (!phba->rrq_pool)
+ goto fail_free_nlp_mem_pool;
phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool",
phba->pcidev,
LPFC_HDR_BUF_SIZE, align, 0);
if (!phba->lpfc_hrb_pool)
- goto fail_free_nlp_mem_pool;
+ goto fail_free_rrq_mem_pool;
phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool",
phba->pcidev,
fail_free_hrb_pool:
pci_pool_destroy(phba->lpfc_hrb_pool);
phba->lpfc_hrb_pool = NULL;
+ fail_free_rrq_mem_pool:
+ mempool_destroy(phba->rrq_pool);
+ phba->rrq_pool = NULL;
fail_free_nlp_mem_pool:
mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL;
goto out;
rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
- (uint8_t *) sp, mbox, 0);
+ (uint8_t *) sp, mbox, ndlp->nlp_rpi);
if (rc) {
mempool_free(mbox, phba->mbox_mem_pool);
goto out;
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- if (!(ndlp->nlp_flag & NLP_RPI_VALID)) {
+ if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) {
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
return 0;
}
lpfc_unreg_rpi(vport, ndlp);
if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
- (uint8_t *) sp, mbox, 0) == 0) {
+ (uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) {
switch (ndlp->nlp_DID) {
case NameServer_DID:
mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
- if (phba->sli_rev == LPFC_SLI_REV4) {
- spin_unlock_irq(&phba->hbalock);
- lpfc_sli4_free_rpi(phba,
- mb->u.mb.un.varRegLogin.rpi);
- spin_lock_irq(&phba->hbalock);
- }
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
__lpfc_mbuf_free(phba, mp->virt, mp->phys);
}
ndlp->nlp_rpi = mb->un.varWords[0];
- ndlp->nlp_flag |= NLP_RPI_VALID;
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
/* Only if we are not a fabric nport do we issue PRLI */
if (!(ndlp->nlp_type & NLP_FABRIC)) {
if (!mb->mbxStatus) {
ndlp->nlp_rpi = mb->un.varWords[0];
- ndlp->nlp_flag |= NLP_RPI_VALID;
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
} else {
if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
lpfc_drop_node(vport, ndlp);
struct sli4_wcqe_xri_aborted *axri)
{
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
+ uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
struct lpfc_scsi_buf *psb, *next_psb;
unsigned long iflag = 0;
struct lpfc_iocbq *iocbq;
int i;
+ struct lpfc_nodelist *ndlp;
+ int rrq_empty = 0;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
psb->status = IOSTAT_SUCCESS;
spin_unlock(
&phba->sli4_hba.abts_scsi_buf_list_lock);
+ ndlp = psb->rdata->pnode;
+ rrq_empty = list_empty(&phba->active_rrq_list);
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ if (ndlp)
+ lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
lpfc_release_scsi_buf_s4(phba, psb);
+ if (rrq_empty)
+ lpfc_worker_wake_up(phba);
return;
}
}
}
/**
- * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
+ * lpfc_get_scsi_buf_s3 - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
* @phba: The HBA for which this call is being executed.
*
* This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
* Pointer to lpfc_scsi_buf - Success
**/
static struct lpfc_scsi_buf*
-lpfc_get_scsi_buf(struct lpfc_hba * phba)
+lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
struct lpfc_scsi_buf * lpfc_cmd = NULL;
struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
return lpfc_cmd;
}
+/**
+ * lpfc_get_scsi_buf_s4 - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
+ * @phba: The HBA for which this call is being executed.
+ *
+ * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
+ * and returns to caller.
+ *
+ * Return codes:
+ * NULL - Error
+ * Pointer to lpfc_scsi_buf - Success
+ **/
+static struct lpfc_scsi_buf*
+lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_scsi_buf *lpfc_cmd = NULL;
+ struct lpfc_scsi_buf *start_lpfc_cmd = NULL;
+ struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
+ unsigned long iflag = 0;
+ int found = 0;
+
+ spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
+ list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+ spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
+ while (!found && lpfc_cmd) {
+ if (lpfc_test_rrq_active(phba, ndlp,
+ lpfc_cmd->cur_iocbq.sli4_xritag)) {
+ lpfc_release_scsi_buf_s4(phba, lpfc_cmd);
+ spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
+ list_remove_head(scsi_buf_list, lpfc_cmd,
+ struct lpfc_scsi_buf, list);
+ spin_unlock_irqrestore(&phba->scsi_buf_list_lock,
+ iflag);
+ if (lpfc_cmd == start_lpfc_cmd) {
+ lpfc_cmd = NULL;
+ break;
+ } else
+ continue;
+ }
+ found = 1;
+ lpfc_cmd->seg_cnt = 0;
+ lpfc_cmd->nonsg_phys = 0;
+ lpfc_cmd->prot_seg_cnt = 0;
+ }
+ return lpfc_cmd;
+}
+/**
+ * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
+ * @phba: The HBA for which this call is being executed.
+ *
+ * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
+ * and returns to caller.
+ *
+ * Return codes:
+ * NULL - Error
+ * Pointer to lpfc_scsi_buf - Success
+ **/
+static struct lpfc_scsi_buf*
+lpfc_get_scsi_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+ return phba->lpfc_get_scsi_buf(phba, ndlp);
+}
/**
* lpfc_release_scsi_buf - Return a scsi buffer back to hba scsi buf list
phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf;
phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd;
- phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf;
switch (dev_grp) {
case LPFC_PCI_DEV_LP:
phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3;
phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3;
phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3;
+ phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s3;
break;
case LPFC_PCI_DEV_OC:
phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4;
phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4;
phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4;
+ phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s4;
break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
return -ENODEV;
break;
}
- phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf;
phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth;
phba->lpfc_scsi_cmd_iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
return 0;
* SCSI_MLQUEUE_HOST_BUSY - Block all devices served by this host temporarily.
**/
static int
-lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
+lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
{
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
goto out_host_busy;
- lpfc_cmd = lpfc_get_scsi_buf(phba);
+ lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp);
if (lpfc_cmd == NULL) {
lpfc_rampdown_queue_depth(phba);
return 0;
}
+static DEF_SCSI_QCMD(lpfc_queuecommand)
+
/**
* lpfc_abort_handler - scsi_host_template eh_abort_handler entry point
* @cmnd: Pointer to scsi_cmnd data structure.
if (!pnode || !NLP_CHK_NODE_ACT(pnode))
return FAILED;
- lpfc_cmd = lpfc_get_scsi_buf(phba);
+ lpfc_cmd = lpfc_get_scsi_buf(phba, rdata->pnode);
if (lpfc_cmd == NULL)
return FAILED;
lpfc_cmd->timeout = 60;
return sglq;
}
+/**
+ * __lpfc_set_rrq_active - set RRQ active bit in the ndlp's xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @ndlp: nodelist pointer for this target.
+ * @xritag: xri used in this exchange.
+ * @rxid: Remote Exchange ID.
+ * @send_rrq: Flag used to determine if we should send rrq els cmd.
+ *
+ * This function is called with hbalock held.
+ * The active bit is set in the ndlp's active rrq xri_bitmap. Allocates an
+ * rrq struct and adds it to the active_rrq_list.
+ *
+ * returns 0 for rrq slot for this xri
+ * < 0 Were not able to get rrq mem or invalid parameter.
+ **/
+static int
+__lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+ uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
+{
+ uint16_t adj_xri;
+ struct lpfc_node_rrq *rrq;
+ int empty;
+
+ /*
+ * set the active bit even if there is no mem available.
+ */
+ adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
+ if (!ndlp)
+ return -EINVAL;
+ if (test_and_set_bit(adj_xri, ndlp->active_rrqs.xri_bitmap))
+ return -EINVAL;
+ rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
+ if (rrq) {
+ rrq->send_rrq = send_rrq;
+ rrq->xritag = xritag;
+ rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
+ rrq->ndlp = ndlp;
+ rrq->nlp_DID = ndlp->nlp_DID;
+ rrq->vport = ndlp->vport;
+ rrq->rxid = rxid;
+ empty = list_empty(&phba->active_rrq_list);
+ if (phba->cfg_enable_rrq && send_rrq)
+ /*
+ * We need the xri before we can add this to the
+ * phba active rrq list.
+ */
+ rrq->send_rrq = send_rrq;
+ else
+ rrq->send_rrq = 0;
+ list_add_tail(&rrq->list, &phba->active_rrq_list);
+ if (!(phba->hba_flag & HBA_RRQ_ACTIVE)) {
+ phba->hba_flag |= HBA_RRQ_ACTIVE;
+ if (empty)
+ lpfc_worker_wake_up(phba);
+ }
+ return 0;
+ }
+ return -ENOMEM;
+}
+
+/**
+ * __lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @xritag: xri used in this exchange.
+ * @rrq: The RRQ to be cleared.
+ *
+ * This function is called with hbalock held. This function
+ **/
+static void
+__lpfc_clr_rrq_active(struct lpfc_hba *phba,
+ uint16_t xritag,
+ struct lpfc_node_rrq *rrq)
+{
+ uint16_t adj_xri;
+ struct lpfc_nodelist *ndlp;
+
+ ndlp = lpfc_findnode_did(rrq->vport, rrq->nlp_DID);
+
+ /* The target DID could have been swapped (cable swap)
+ * we should use the ndlp from the findnode if it is
+ * available.
+ */
+ if (!ndlp)
+ ndlp = rrq->ndlp;
+
+ adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
+ if (test_and_clear_bit(adj_xri, ndlp->active_rrqs.xri_bitmap)) {
+ rrq->send_rrq = 0;
+ rrq->xritag = 0;
+ rrq->rrq_stop_time = 0;
+ }
+ mempool_free(rrq, phba->rrq_pool);
+}
+
+/**
+ * lpfc_handle_rrq_active - Checks if RRQ has waithed RATOV.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called with hbalock held. This function
+ * Checks if stop_time (ratov from setting rrq active) has
+ * been reached, if it has and the send_rrq flag is set then
+ * it will call lpfc_send_rrq. If the send_rrq flag is not set
+ * then it will just call the routine to clear the rrq and
+ * free the rrq resource.
+ * The timer is set to the next rrq that is going to expire before
+ * leaving the routine.
+ *
+ **/
+void
+lpfc_handle_rrq_active(struct lpfc_hba *phba)
+{
+ struct lpfc_node_rrq *rrq;
+ struct lpfc_node_rrq *nextrrq;
+ unsigned long next_time;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ phba->hba_flag &= ~HBA_RRQ_ACTIVE;
+ next_time = jiffies + HZ * (phba->fc_ratov + 1);
+ list_for_each_entry_safe(rrq, nextrrq,
+ &phba->active_rrq_list, list) {
+ if (time_after(jiffies, rrq->rrq_stop_time)) {
+ list_del(&rrq->list);
+ if (!rrq->send_rrq)
+ /* this call will free the rrq */
+ __lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ else {
+ /* if we send the rrq then the completion handler
+ * will clear the bit in the xribitmap.
+ */
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (lpfc_send_rrq(phba, rrq)) {
+ lpfc_clr_rrq_active(phba, rrq->xritag,
+ rrq);
+ }
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ }
+ } else if (time_before(rrq->rrq_stop_time, next_time))
+ next_time = rrq->rrq_stop_time;
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (!list_empty(&phba->active_rrq_list))
+ mod_timer(&phba->rrq_tmr, next_time);
+}
+
+/**
+ * lpfc_get_active_rrq - Get the active RRQ for this exchange.
+ * @vport: Pointer to vport context object.
+ * @xri: The xri used in the exchange.
+ * @did: The targets DID for this exchange.
+ *
+ * returns NULL = rrq not found in the phba->active_rrq_list.
+ * rrq = rrq for this xri and target.
+ **/
+struct lpfc_node_rrq *
+lpfc_get_active_rrq(struct lpfc_vport *vport, uint16_t xri, uint32_t did)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_node_rrq *rrq;
+ struct lpfc_node_rrq *nextrrq;
+ unsigned long iflags;
+
+ if (phba->sli_rev != LPFC_SLI_REV4)
+ return NULL;
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) {
+ if (rrq->vport == vport && rrq->xritag == xri &&
+ rrq->nlp_DID == did){
+ list_del(&rrq->list);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return rrq;
+ }
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return NULL;
+}
+
+/**
+ * lpfc_cleanup_vports_rrqs - Remove and clear the active RRQ for this vport.
+ * @vport: Pointer to vport context object.
+ *
+ * Remove all active RRQs for this vport from the phba->active_rrq_list and
+ * clear the rrq.
+ **/
+void
+lpfc_cleanup_vports_rrqs(struct lpfc_vport *vport)
+
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_node_rrq *rrq;
+ struct lpfc_node_rrq *nextrrq;
+ unsigned long iflags;
+
+ if (phba->sli_rev != LPFC_SLI_REV4)
+ return;
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) {
+ if (rrq->vport == vport) {
+ list_del(&rrq->list);
+ __lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ }
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+}
+
+/**
+ * lpfc_cleanup_wt_rrqs - Remove all rrq's from the active list.
+ * @phba: Pointer to HBA context object.
+ *
+ * Remove all rrqs from the phba->active_rrq_list and free them by
+ * calling __lpfc_clr_active_rrq
+ *
+ **/
+void
+lpfc_cleanup_wt_rrqs(struct lpfc_hba *phba)
+{
+ struct lpfc_node_rrq *rrq;
+ struct lpfc_node_rrq *nextrrq;
+ unsigned long next_time;
+ unsigned long iflags;
+
+ if (phba->sli_rev != LPFC_SLI_REV4)
+ return;
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ phba->hba_flag &= ~HBA_RRQ_ACTIVE;
+ next_time = jiffies + HZ * (phba->fc_ratov * 2);
+ list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) {
+ list_del(&rrq->list);
+ __lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (!list_empty(&phba->active_rrq_list))
+ mod_timer(&phba->rrq_tmr, next_time);
+}
+
+
+/**
+ * __lpfc_test_rrq_active - Test RRQ bit in xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @ndlp: Targets nodelist pointer for this exchange.
+ * @xritag the xri in the bitmap to test.
+ *
+ * This function is called with hbalock held. This function
+ * returns 0 = rrq not active for this xri
+ * 1 = rrq is valid for this xri.
+ **/
+static int
+__lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+ uint16_t xritag)
+{
+ uint16_t adj_xri;
+
+ adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
+ if (!ndlp)
+ return 0;
+ if (test_bit(adj_xri, ndlp->active_rrqs.xri_bitmap))
+ return 1;
+ else
+ return 0;
+}
+
+/**
+ * lpfc_set_rrq_active - set RRQ active bit in xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @ndlp: nodelist pointer for this target.
+ * @xritag: xri used in this exchange.
+ * @rxid: Remote Exchange ID.
+ * @send_rrq: Flag used to determine if we should send rrq els cmd.
+ *
+ * This function takes the hbalock.
+ * The active bit is always set in the active rrq xri_bitmap even
+ * if there is no slot avaiable for the other rrq information.
+ *
+ * returns 0 rrq actived for this xri
+ * < 0 No memory or invalid ndlp.
+ **/
+int
+lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+ uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
+{
+ int ret;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ ret = __lpfc_set_rrq_active(phba, ndlp, xritag, rxid, send_rrq);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return ret;
+}
+
+/**
+ * lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @xritag: xri used in this exchange.
+ * @rrq: The RRQ to be cleared.
+ *
+ * This function is takes the hbalock.
+ **/
+void
+lpfc_clr_rrq_active(struct lpfc_hba *phba,
+ uint16_t xritag,
+ struct lpfc_node_rrq *rrq)
+{
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ __lpfc_clr_rrq_active(phba, xritag, rrq);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return;
+}
+
+
+
+/**
+ * lpfc_test_rrq_active - Test RRQ bit in xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @ndlp: Targets nodelist pointer for this exchange.
+ * @xritag the xri in the bitmap to test.
+ *
+ * This function takes the hbalock.
+ * returns 0 = rrq not active for this xri
+ * 1 = rrq is valid for this xri.
+ **/
+int
+lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+ uint16_t xritag)
+{
+ int ret;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ ret = __lpfc_test_rrq_active(phba, ndlp, xritag);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return ret;
+}
+
/**
* __lpfc_sli_get_sglq - Allocates an iocb object from sgl pool
* @phba: Pointer to HBA context object.
+ * @piocb: Pointer to the iocbq.
*
* This function is called with hbalock held. This function
* Gets a new driver sglq object from the sglq list. If the
* allocated sglq object else it returns NULL.
**/
static struct lpfc_sglq *
-__lpfc_sli_get_sglq(struct lpfc_hba *phba)
+__lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
{
struct list_head *lpfc_sgl_list = &phba->sli4_hba.lpfc_sgl_list;
struct lpfc_sglq *sglq = NULL;
+ struct lpfc_sglq *start_sglq = NULL;
uint16_t adj_xri;
+ struct lpfc_scsi_buf *lpfc_cmd;
+ struct lpfc_nodelist *ndlp;
+ int found = 0;
+
+ if (piocbq->iocb_flag & LPFC_IO_FCP) {
+ lpfc_cmd = (struct lpfc_scsi_buf *) piocbq->context1;
+ ndlp = lpfc_cmd->rdata->pnode;
+ } else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) &&
+ !(piocbq->iocb_flag & LPFC_IO_LIBDFC))
+ ndlp = piocbq->context_un.ndlp;
+ else
+ ndlp = piocbq->context1;
+
list_remove_head(lpfc_sgl_list, sglq, struct lpfc_sglq, list);
- if (!sglq)
- return NULL;
- adj_xri = sglq->sli4_xritag - phba->sli4_hba.max_cfg_param.xri_base;
- phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq;
- sglq->state = SGL_ALLOCATED;
+ start_sglq = sglq;
+ while (!found) {
+ if (!sglq)
+ return NULL;
+ adj_xri = sglq->sli4_xritag -
+ phba->sli4_hba.max_cfg_param.xri_base;
+ if (__lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) {
+ /* This xri has an rrq outstanding for this DID.
+ * put it back in the list and get another xri.
+ */
+ list_add_tail(&sglq->list, lpfc_sgl_list);
+ sglq = NULL;
+ list_remove_head(lpfc_sgl_list, sglq,
+ struct lpfc_sglq, list);
+ if (sglq == start_sglq) {
+ sglq = NULL;
+ break;
+ } else
+ continue;
+ }
+ sglq->ndlp = ndlp;
+ found = 1;
+ phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq;
+ sglq->state = SGL_ALLOCATED;
+ }
return sglq;
}
&phba->sli4_hba.abts_sgl_list_lock, iflag);
} else {
sglq->state = SGL_FREED;
+ sglq->ndlp = NULL;
list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
/* Check if TXQ queue needs to be serviced */
case MBX_READ_LNK_STAT:
case MBX_REG_LOGIN:
case MBX_UNREG_LOGIN:
- case MBX_READ_LA:
case MBX_CLEAR_LA:
case MBX_DUMP_MEMORY:
case MBX_DUMP_CONTEXT:
case MBX_READ_SPARM64:
case MBX_READ_RPI64:
case MBX_REG_LOGIN64:
- case MBX_READ_LA64:
+ case MBX_READ_TOPOLOGY:
case MBX_WRITE_WWN:
case MBX_SET_DEBUG:
case MBX_LOAD_EXP_ROM:
kfree(mp);
}
- if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
- (phba->sli_rev == LPFC_SLI_REV4) &&
- (pmb->u.mb.un.varUnregLogin.rsvd1 == 0x0))
- lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
-
/*
* If a REG_LOGIN succeeded after node is destroyed or node
* is in re-discovery driver need to cleanup the RPI.
phba->pport->fc_myDID = 0;
phba->pport->fc_prevDID = 0;
- /* Turn off parity checking and serr during the physical reset */
- pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
- pci_write_config_word(phba->pcidev, PCI_COMMAND,
- (cfg_value &
- ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
-
spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~(LPFC_PROCESS_LA);
phba->fcf.fcf_flag = 0;
/* Now physically reset the device */
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0389 Performing PCI function reset!\n");
+
+ /* Turn off parity checking and serr during the physical reset */
+ pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
+ pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value &
+ ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
+
/* Perform FCoE PCI function reset */
lpfc_pci_function_reset(phba);
+ /* Restore PCI cmd register */
+ pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value);
+
return 0;
}
struct lpfc_vport *vport = phba->pport;
struct lpfc_dmabuf *mp;
+ /*
+ * TODO: Why does this routine execute these task in a different
+ * order from probe?
+ */
/* Perform a PCI function reset to start from clean */
rc = lpfc_pci_function_reset(phba);
if (unlikely(rc))
}
rc = lpfc_sli4_read_rev(phba, mboxq, vpd, &vpd_size);
- if (unlikely(rc))
- goto out_free_vpd;
-
+ if (unlikely(rc)) {
+ kfree(vpd);
+ goto out_free_mbox;
+ }
mqe = &mboxq->u.mqe;
phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev);
if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev))
- phba->hba_flag |= HBA_FCOE_SUPPORT;
+ phba->hba_flag |= HBA_FCOE_MODE;
+ else
+ phba->hba_flag &= ~HBA_FCOE_MODE;
if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) ==
LPFC_DCBX_CEE_MODE)
phba->hba_flag &= ~HBA_FIP_SUPPORT;
if (phba->sli_rev != LPFC_SLI_REV4 ||
- !(phba->hba_flag & HBA_FCOE_SUPPORT)) {
+ !(phba->hba_flag & HBA_FCOE_MODE)) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
"0376 READ_REV Error. SLI Level %d "
"FCoE enabled %d\n",
- phba->sli_rev, phba->hba_flag & HBA_FCOE_SUPPORT);
+ phba->sli_rev, phba->hba_flag & HBA_FCOE_MODE);
rc = -EIO;
- goto out_free_vpd;
+ kfree(vpd);
+ goto out_free_mbox;
}
/*
* Evaluate the read rev and vpd data. Populate the driver
"Using defaults.\n", rc);
rc = 0;
}
+ kfree(vpd);
/* Save information as VPD data */
phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev;
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
if (unlikely(rc)) {
rc = -EIO;
- goto out_free_vpd;
+ goto out_free_mbox;
}
/*
if (rc) {
phba->link_state = LPFC_HBA_ERROR;
rc = -ENOMEM;
- goto out_free_vpd;
+ goto out_free_mbox;
}
mboxq->vport = vport;
rc, bf_get(lpfc_mqe_status, mqe));
phba->link_state = LPFC_HBA_ERROR;
rc = -EIO;
- goto out_free_vpd;
+ goto out_free_mbox;
}
if (phba->cfg_soft_wwnn)
"0582 Error %d during sgl post operation\n",
rc);
rc = -ENODEV;
- goto out_free_vpd;
+ goto out_free_mbox;
}
/* Register SCSI SGL pool to the device */
/* Some Scsi buffers were moved to the abort scsi list */
/* A pci function reset will repost them */
rc = -ENODEV;
- goto out_free_vpd;
+ goto out_free_mbox;
}
/* Post the rpi header region to the device. */
"0393 Error %d during rpi post operation\n",
rc);
rc = -ENODEV;
- goto out_free_vpd;
+ goto out_free_mbox;
}
/* Set up all the queues to the device */
}
}
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ /*
+ * The FC Port needs to register FCFI (index 0)
+ */
+ lpfc_reg_fcfi(phba, mboxq);
+ mboxq->vport = phba->pport;
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+ if (rc == MBX_SUCCESS)
+ rc = 0;
+ else
+ goto out_unset_queue;
+ }
/*
* The port is ready, set the host's link state to LINK_DOWN
* in preparation for link interrupts.
*/
- lpfc_init_link(phba, mboxq, phba->cfg_topology, phba->cfg_link_speed);
- mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- lpfc_set_loopback_flag(phba);
- /* Change driver state to LPFC_LINK_DOWN right before init link */
spin_lock_irq(&phba->hbalock);
phba->link_state = LPFC_LINK_DOWN;
spin_unlock_irq(&phba->hbalock);
- rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
- if (unlikely(rc != MBX_NOT_FINISHED)) {
- kfree(vpd);
- return 0;
- } else
- rc = -EIO;
-
+ rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
+out_unset_queue:
/* Unset all the queues set up in this routine when error out */
if (rc)
lpfc_sli4_queue_unset(phba);
-
out_stop_timers:
if (rc)
lpfc_stop_hba_timers(phba);
-out_free_vpd:
- kfree(vpd);
out_free_mbox:
mempool_free(mboxq, phba->mbox_mem_pool);
return rc;
IOCB_t *icmd;
int numBdes = 0;
int i = 0;
+ uint32_t offset = 0; /* accumulated offset in the sg request list */
+ int inbound = 0; /* number of sg reply entries inbound from firmware */
if (!piocbq || !sglq)
return xritag;
*/
bde.tus.w = le32_to_cpu(bpl->tus.w);
sgl->sge_len = cpu_to_le32(bde.tus.f.bdeSize);
+ /* The offsets in the sgl need to be accumulated
+ * separately for the request and reply lists.
+ * The request is always first, the reply follows.
+ */
+ if (piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) {
+ /* add up the reply sg entries */
+ if (bpl->tus.f.bdeFlags == BUFF_TYPE_BDE_64I)
+ inbound++;
+ /* first inbound? reset the offset */
+ if (inbound == 1)
+ offset = 0;
+ bf_set(lpfc_sli4_sge_offset, sgl, offset);
+ offset += bde.tus.f.bdeSize;
+ }
bpl++;
sgl++;
}
bf_set(els_req64_vf, &wqe->els_req, 0);
/* And a VFID for word 12 */
bf_set(els_req64_vfid, &wqe->els_req, 0);
- /*
- * Set ct field to 3, indicates that the context_tag field
- * contains the FCFI and remote N_Port_ID is
- * in word 5.
- */
ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l);
bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
iocbq->iocb.ulpContext);
bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0);
break;
case CMD_GEN_REQUEST64_CR:
+ /* For this command calculate the xmit length of the
+ * request bde.
+ */
+ xmit_len = 0;
+ numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize /
+ sizeof(struct ulp_bde64);
+ for (i = 0; i < numBdes; i++) {
+ if (bpl[i].tus.f.bdeFlags != BUFF_TYPE_BDE_64)
+ break;
+ bde.tus.w = le32_to_cpu(bpl[i].tus.w);
+ xmit_len += bde.tus.f.bdeSize;
+ }
/* word3 iocb=IO_TAG wqe=request_payload_len */
wqe->gen_req.request_payload_len = xmit_len;
/* word4 iocb=parameter wqe=relative_offset memcpy */
return IOCB_BUSY;
}
} else {
- sglq = __lpfc_sli_get_sglq(phba);
+ sglq = __lpfc_sli_get_sglq(phba, piocb);
if (!sglq) {
if (!(flag & SLI_IOCB_RET_IOCB)) {
__lpfc_sli_ringtx_put(phba,
lpfc_sli4_eratt_read(struct lpfc_hba *phba)
{
uint32_t uerr_sta_hi, uerr_sta_lo;
+ uint32_t if_type, portsmphr;
+ struct lpfc_register portstat_reg;
- /* For now, use the SLI4 device internal unrecoverable error
+ /*
+ * For now, use the SLI4 device internal unrecoverable error
* registers for error attention. This can be changed later.
*/
- uerr_sta_lo = readl(phba->sli4_hba.UERRLOregaddr);
- uerr_sta_hi = readl(phba->sli4_hba.UERRHIregaddr);
- if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) ||
- (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) {
+ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ uerr_sta_lo = readl(phba->sli4_hba.u.if_type0.UERRLOregaddr);
+ uerr_sta_hi = readl(phba->sli4_hba.u.if_type0.UERRHIregaddr);
+ if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) ||
+ (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "1423 HBA Unrecoverable error: "
+ "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
+ "ue_mask_lo_reg=0x%x, "
+ "ue_mask_hi_reg=0x%x\n",
+ uerr_sta_lo, uerr_sta_hi,
+ phba->sli4_hba.ue_mask_lo,
+ phba->sli4_hba.ue_mask_hi);
+ phba->work_status[0] = uerr_sta_lo;
+ phba->work_status[1] = uerr_sta_hi;
+ phba->work_ha |= HA_ERATT;
+ phba->hba_flag |= HBA_ERATT_HANDLED;
+ return 1;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ portstat_reg.word0 =
+ readl(phba->sli4_hba.u.if_type2.STATUSregaddr);
+ portsmphr = readl(phba->sli4_hba.PSMPHRregaddr);
+ if (bf_get(lpfc_sliport_status_err, &portstat_reg)) {
+ phba->work_status[0] =
+ readl(phba->sli4_hba.u.if_type2.ERR1regaddr);
+ phba->work_status[1] =
+ readl(phba->sli4_hba.u.if_type2.ERR2regaddr);
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2885 Port Error Detected: "
+ "port status reg 0x%x, "
+ "port smphr reg 0x%x, "
+ "error 1=0x%x, error 2=0x%x\n",
+ portstat_reg.word0,
+ portsmphr,
+ phba->work_status[0],
+ phba->work_status[1]);
+ phba->work_ha |= HA_ERATT;
+ phba->hba_flag |= HBA_ERATT_HANDLED;
+ return 1;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1423 HBA Unrecoverable error: "
- "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
- "ue_mask_lo_reg=0x%x, ue_mask_hi_reg=0x%x\n",
- uerr_sta_lo, uerr_sta_hi,
- phba->sli4_hba.ue_mask_lo,
- phba->sli4_hba.ue_mask_hi);
- phba->work_status[0] = uerr_sta_lo;
- phba->work_status[1] = uerr_sta_hi;
- /* Set the driver HA work bitmap */
- phba->work_ha |= HA_ERATT;
- /* Indicate polling handles this ERATT */
- phba->hba_flag |= HBA_ERATT_HANDLED;
+ "2886 HBA Error Attention on unsupported "
+ "if type %d.", if_type);
return 1;
}
+
return 0;
}
ha_copy = lpfc_sli_eratt_read(phba);
break;
case LPFC_SLI_REV4:
- /* Read devcie Uncoverable Error (UERR) registers */
+ /* Read device Uncoverable Error (UERR) registers */
ha_copy = lpfc_sli4_eratt_read(phba);
break;
default:
length, LPFC_SLI4_MBX_EMBED);
mq_create_ext = &mbox->u.mqe.un.mq_create_ext;
- bf_set(lpfc_mbx_mq_create_ext_num_pages, &mq_create_ext->u.request,
- mq->page_count);
- bf_set(lpfc_mbx_mq_create_ext_async_evt_link, &mq_create_ext->u.request,
- 1);
- bf_set(lpfc_mbx_mq_create_ext_async_evt_fcfste,
+ bf_set(lpfc_mbx_mq_create_ext_num_pages,
+ &mq_create_ext->u.request, mq->page_count);
+ bf_set(lpfc_mbx_mq_create_ext_async_evt_link,
+ &mq_create_ext->u.request, 1);
+ bf_set(lpfc_mbx_mq_create_ext_async_evt_fip,
&mq_create_ext->u.request, 1);
bf_set(lpfc_mbx_mq_create_ext_async_evt_group5,
&mq_create_ext->u.request, 1);
- bf_set(lpfc_mq_context_cq_id, &mq_create_ext->u.request.context,
- cq->queue_id);
+ bf_set(lpfc_mbx_mq_create_ext_async_evt_fc,
+ &mq_create_ext->u.request, 1);
+ bf_set(lpfc_mbx_mq_create_ext_async_evt_sli,
+ &mq_create_ext->u.request, 1);
+ bf_set(lpfc_mq_context_cq_id,
+ &mq_create_ext->u.request.context, cq->queue_id);
bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1);
switch (mq->entry_count) {
default:
"SID:x%x\n", oxid, sid);
return;
}
+ if (rxid >= phba->sli4_hba.max_cfg_param.xri_base
+ && rxid <= (phba->sli4_hba.max_cfg_param.max_xri
+ + phba->sli4_hba.max_cfg_param.xri_base))
+ lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0);
/* Allocate buffer for acc iocb */
ctiocb = lpfc_sli_get_iocbq(phba);
icmd->ulpLe = 1;
icmd->ulpClass = CLASS3;
icmd->ulpContext = ndlp->nlp_rpi;
+ ctiocb->context1 = ndlp;
ctiocb->iocb_cmpl = NULL;
ctiocb->vport = phba->pport;
/**
* lpfc_sli4_init_vpi - Initialize a vpi with the port
- * @phba: pointer to lpfc hba data structure.
- * @vpi: vpi value to activate with the port.
+ * @vport: Pointer to the vport for which the vpi is being initialized
*
- * This routine is invoked to activate a vpi with the
- * port when the host intends to use vports with a
- * nonzero vpi.
+ * This routine is invoked to activate a vpi with the port.
*
* Returns:
* 0 success
* -Evalue otherwise
**/
int
-lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi)
+lpfc_sli4_init_vpi(struct lpfc_vport *vport)
{
LPFC_MBOXQ_t *mboxq;
int rc = 0;
int retval = MBX_SUCCESS;
uint32_t mbox_tmo;
-
- if (vpi == 0)
- return -EINVAL;
+ struct lpfc_hba *phba = vport->phba;
mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mboxq)
return -ENOMEM;
- lpfc_init_vpi(phba, mboxq, vpi);
+ lpfc_init_vpi(phba, mboxq, vport->vpi);
mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_INIT_VPI);
rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI,
"2022 INIT VPI Mailbox failed "
"status %d, mbxStatus x%x\n", rc,
bf_get(lpfc_mqe_status, &mboxq->u.mqe));
retval = -EIO;
}
if (rc != MBX_TIMEOUT)
- mempool_free(mboxq, phba->mbox_mem_pool);
+ mempool_free(mboxq, vport->phba->mbox_mem_pool);
return retval;
}
struct lpfc_nodelist *act_mbx_ndlp = NULL;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
LIST_HEAD(mbox_cmd_list);
+ uint8_t restart_loop;
/* Clean up internally queued mailbox commands with the vport */
spin_lock_irq(&phba->hbalock);
mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
}
}
+ /* Cleanup any mailbox completions which are not yet processed */
+ do {
+ restart_loop = 0;
+ list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) {
+ /*
+ * If this mailox is already processed or it is
+ * for another vport ignore it.
+ */
+ if ((mb->vport != vport) ||
+ (mb->mbox_flag & LPFC_MBX_IMED_UNREG))
+ continue;
+
+ if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) &&
+ (mb->u.mb.mbxCommand != MBX_REG_VPI))
+ continue;
+
+ mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+ ndlp = (struct lpfc_nodelist *)mb->context2;
+ /* Unregister the RPI when mailbox complete */
+ mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
+ restart_loop = 1;
+ spin_unlock_irq(&phba->hbalock);
+ spin_lock(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+ spin_unlock(shost->host_lock);
+ spin_lock_irq(&phba->hbalock);
+ break;
+ }
+ }
+ } while (restart_loop);
+
spin_unlock_irq(&phba->hbalock);
/* Release the cleaned-up mailbox commands */
while (!list_empty(&mbox_cmd_list)) {
list_remove_head(&mbox_cmd_list, mb, LPFC_MBOXQ_t, list);
if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
- if (phba->sli_rev == LPFC_SLI_REV4)
- __lpfc_sli4_free_rpi(phba,
- mb->u.mb.un.varRegLogin.rpi);
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
__lpfc_mbuf_free(phba, mp->virt, mp->phys);
while (pring->txq_cnt) {
spin_lock_irqsave(&phba->hbalock, iflags);
- sglq = __lpfc_sli_get_sglq(phba);
+ piocbq = lpfc_sli_ringtx_get(phba, pring);
+ sglq = __lpfc_sli_get_sglq(phba, piocbq);
if (!sglq) {
+ __lpfc_sli_ringtx_put(phba, pring, piocbq);
spin_unlock_irqrestore(&phba->hbalock, iflags);
break;
} else {
- piocbq = lpfc_sli_ringtx_get(phba, pring);
if (!piocbq) {
/* The txq_cnt out of sync. This should
* never happen
union {
struct lpfc_mcqe mcqe_cmpl;
struct lpfc_acqe_link acqe_link;
- struct lpfc_acqe_fcoe acqe_fcoe;
+ struct lpfc_acqe_fip acqe_fip;
struct lpfc_acqe_dcbx acqe_dcbx;
struct lpfc_acqe_grp5 acqe_grp5;
+ struct lpfc_acqe_fc_la acqe_fc;
+ struct lpfc_acqe_sli acqe_sli;
struct lpfc_rcqe rcqe_cmpl;
struct sli4_wcqe_xri_aborted wcqe_axri;
struct lpfc_wcqe_complete wcqe_cmpl;
struct lpfc_iocbq *rsp_iocb;
struct lpfcMboxq *mbox;
struct lpfc_nodelist *ndlp;
+ struct lpfc_node_rrq *rrq;
} context_un;
void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
uint8_t speed;
uint8_t duplex;
uint8_t status;
- uint8_t physical;
+ uint8_t type;
+ uint8_t number;
uint8_t fault;
uint16_t logical_speed;
+ uint16_t topology;
};
struct lpfc_fcf_rec {
PCI BAR1, control registers */
void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for
PCI BAR2, doorbell registers */
- /* BAR0 PCI config space register memory map */
- void __iomem *UERRLOregaddr; /* Address to UERR_STATUS_LO register */
- void __iomem *UERRHIregaddr; /* Address to UERR_STATUS_HI register */
- void __iomem *UEMASKLOregaddr; /* Address to UE_MASK_LO register */
- void __iomem *UEMASKHIregaddr; /* Address to UE_MASK_HI register */
- void __iomem *SLIINTFregaddr; /* Address to SLI_INTF register */
- /* BAR1 FCoE function CSR register memory map */
- void __iomem *STAregaddr; /* Address to HST_STATE register */
- void __iomem *ISRregaddr; /* Address to HST_ISR register */
- void __iomem *IMRregaddr; /* Address to HST_IMR register */
- void __iomem *ISCRregaddr; /* Address to HST_ISCR register */
- /* BAR2 VF-0 doorbell register memory map */
- void __iomem *RQDBregaddr; /* Address to RQ_DOORBELL register */
- void __iomem *WQDBregaddr; /* Address to WQ_DOORBELL register */
- void __iomem *EQCQDBregaddr; /* Address to EQCQ_DOORBELL register */
- void __iomem *MQDBregaddr; /* Address to MQ_DOORBELL register */
- void __iomem *BMBXregaddr; /* Address to BootStrap MBX register */
+ union {
+ struct {
+ /* IF Type 0, BAR 0 PCI cfg space reg mem map */
+ void __iomem *UERRLOregaddr;
+ void __iomem *UERRHIregaddr;
+ void __iomem *UEMASKLOregaddr;
+ void __iomem *UEMASKHIregaddr;
+ } if_type0;
+ struct {
+ /* IF Type 2, BAR 0 PCI cfg space reg mem map. */
+ void __iomem *STATUSregaddr;
+ void __iomem *CTRLregaddr;
+ void __iomem *ERR1regaddr;
+ void __iomem *ERR2regaddr;
+ } if_type2;
+ } u;
+
+ /* IF type 0, BAR1 and if type 2, Bar 0 CSR register memory map */
+ void __iomem *PSMPHRregaddr;
+
+ /* Well-known SLI INTF register memory map. */
+ void __iomem *SLIINTFregaddr;
+
+ /* IF type 0, BAR 1 function CSR register memory map */
+ void __iomem *ISRregaddr; /* HST_ISR register */
+ void __iomem *IMRregaddr; /* HST_IMR register */
+ void __iomem *ISCRregaddr; /* HST_ISCR register */
+ /* IF type 0, BAR 0 and if type 2, BAR 0 doorbell register memory map */
+ void __iomem *RQDBregaddr; /* RQ_DOORBELL register */
+ void __iomem *WQDBregaddr; /* WQ_DOORBELL register */
+ void __iomem *EQCQDBregaddr; /* EQCQ_DOORBELL register */
+ void __iomem *MQDBregaddr; /* MQ_DOORBELL register */
+ void __iomem *BMBXregaddr; /* BootStrap MBX register */
uint32_t ue_mask_lo;
uint32_t ue_mask_hi;
struct list_head clist;
enum lpfc_sge_type buff_type; /* is this a scsi sgl */
enum lpfc_sgl_state state;
+ struct lpfc_nodelist *ndlp; /* ndlp associated with IO */
uint16_t iotag; /* pre-assigned IO tag */
uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */
struct sli4_sge *sgl; /* pre-assigned SGL */
struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *);
void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *);
int lpfc_sli4_alloc_rpi(struct lpfc_hba *);
-void __lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_remove_rpis(struct lpfc_hba *);
void lpfc_sli4_async_event_proc(struct lpfc_hba *);
int lpfc_sli4_add_fcf_record(struct lpfc_hba *, struct fcf_record *);
void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *);
int lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *);
-int lpfc_sli4_init_vpi(struct lpfc_hba *, uint16_t);
+int lpfc_sli4_init_vpi(struct lpfc_vport *);
uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool);
uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool);
void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t);
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.18"
+#define LPFC_DRIVER_VERSION "8.3.20"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
* by the port.
*/
if ((phba->sli_rev == LPFC_SLI_REV4) &&
- (pport->fc_flag & FC_VFI_REGISTERED)) {
- rc = lpfc_sli4_init_vpi(phba, vpi);
+ (pport->fc_flag & FC_VFI_REGISTERED)) {
+ rc = lpfc_sli4_init_vpi(vport);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"1838 Failed to INIT_VPI on vpi %d "
if ((phba->link_state < LPFC_LINK_UP) ||
(pport->port_state < LPFC_FABRIC_CFG_LINK) ||
- (phba->fc_topology == TOPOLOGY_LOOP)) {
+ (phba->fc_topology == LPFC_TOPOLOGY_LOOP)) {
lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
rc = VPORT_OK;
goto out;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
if ((phba->link_state < LPFC_LINK_UP) ||
- (phba->fc_topology == TOPOLOGY_LOOP)) {
+ (phba->fc_topology == LPFC_TOPOLOGY_LOOP)) {
lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
return VPORT_OK;
}
if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
phba->link_state >= LPFC_LINK_UP &&
- phba->fc_topology != TOPOLOGY_LOOP) {
+ phba->fc_topology != LPFC_TOPOLOGY_LOOP) {
if (vport->cfg_enable_da_id) {
timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0))
static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *);
-static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int mac53c94_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct fsc_state *state;
return 0;
}
+static DEF_SCSI_QCMD(mac53c94_queue)
+
static int mac53c94_host_reset(struct scsi_cmnd *cmd)
{
struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata;
* The command queuing entry point for the mid-layer.
*/
static int
-megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
+megaraid_queue_lck(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
{
adapter_t *adapter;
scb_t *scb;
return busy;
}
+static DEF_SCSI_QCMD(megaraid_queue)
+
/**
* mega_allocate_scb()
* @adapter - pointer to our soft state
scb->idx = CMDID_INT_CMDS;
- megaraid_queue(scmd, mega_internal_done);
+ megaraid_queue_lck(scmd, mega_internal_done);
wait_for_completion(&adapter->int_waitq);
static int issue_scb(adapter_t *, scb_t *);
static int mega_setup_mailbox(adapter_t *);
-static int megaraid_queue (Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+static int megaraid_queue (struct Scsi_Host *, struct scsi_cmnd *);
static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *);
static void __mega_runpendq(adapter_t *);
static int issue_scb_block(adapter_t *, u_char *);
obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o
obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o
obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o
+megaraid_sas-objs := megaraid_sas_base.o megaraid_sas_fusion.o \
+ megaraid_sas_fp.o
static void megaraid_mbox_display_scb(adapter_t *, scb_t *);
static void megaraid_mbox_setup_device_map(adapter_t *);
-static int megaraid_queue_command(struct scsi_cmnd *,
- void (*)(struct scsi_cmnd *));
+static int megaraid_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *);
static void megaraid_mbox_runpendq(adapter_t *, scb_t *);
static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *,
* Queue entry point for mailbox based controllers.
*/
static int
-megaraid_queue_command(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
+megaraid_queue_command_lck(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
{
adapter_t *adapter;
scb_t *scb;
return if_busy;
}
+static DEF_SCSI_QCMD(megaraid_queue_command)
+
/**
* megaraid_mbox_build_cmd - transform the mid-layer scsi commands
* @adapter : controller's soft state
/*
+ * Linux MegaRAID driver for SAS based RAID controllers
*
- * Linux MegaRAID driver for SAS based RAID controllers
+ * Copyright (c) 2009-2011 LSI Corporation.
*
- * Copyright (c) 2003-2005 LSI Corporation.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
*
- * This program is 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.
*
- * FILE : megaraid_sas.h
+ * 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
+ *
+ * FILE: megaraid_sas.h
+ *
+ * Authors: LSI Corporation
+ *
+ * Send feedback to: <megaraidlinux@lsi.com>
+ *
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: Linuxraid
*/
#ifndef LSI_MEGARAID_SAS_H
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.04.31-rc1"
-#define MEGASAS_RELDATE "May 3, 2010"
-#define MEGASAS_EXT_VERSION "Mon. May 3, 11:41:51 PST 2010"
+#define MEGASAS_VERSION "00.00.05.29-rc1"
+#define MEGASAS_RELDATE "Dec. 7, 2010"
+#define MEGASAS_EXT_VERSION "Tue. Dec. 7 17:00:00 PDT 2010"
/*
* Device IDs
#define PCI_DEVICE_ID_LSI_SAS0079GEN2 0x0079
#define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073
#define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071
+#define PCI_DEVICE_ID_LSI_FUSION 0x005b
/*
* =====================================
* Add properties that can be controlled by
* a bit in the following structure.
*/
-
struct {
u32 copyBackDisabled : 1;
u32 SMARTerEnabled : 1;
#define MEGASAS_DEFAULT_INIT_ID -1
#define MEGASAS_MAX_LUN 8
#define MEGASAS_MAX_LD 64
+#define MEGASAS_DEFAULT_CMD_PER_LUN 128
#define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \
MEGASAS_MAX_DEV_PER_CHANNEL)
#define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \
*/
struct megasas_register_set {
- u32 reserved_0[4]; /*0000h*/
+ u32 doorbell; /*0000h*/
+ u32 fusion_seq_offset; /*0004h*/
+ u32 fusion_host_diag; /*0008h*/
+ u32 reserved_01; /*000Ch*/
u32 inbound_msg_0; /*0010h*/
u32 inbound_msg_1; /*0014h*/
u32 inbound_queue_port; /*0040h*/
u32 outbound_queue_port; /*0044h*/
- u32 reserved_2[22]; /*0048h*/
+ u32 reserved_2[9]; /*0048h*/
+ u32 reply_post_host_index; /*006Ch*/
+ u32 reserved_2_2[12]; /*0070h*/
u32 outbound_doorbell_clear; /*00A0h*/
u32 reserved_3[3]; /*00A4h*/
u32 outbound_scratch_pad ; /*00B0h*/
+ u32 outbound_scratch_pad_2; /*00B4h*/
- u32 reserved_4[3]; /*00B4h*/
+ u32 reserved_4[2]; /*00B8h*/
u32 inbound_low_queue_port ; /*00C0h*/
u16 max_num_sge;
u16 max_fw_cmds;
+ /* For Fusion its num IOCTL cmds, for others MFI based its
+ max_fw_cmds */
+ u16 max_mfi_cmds;
u32 max_sectors_per_req;
struct megasas_aen_event *ev;
struct timer_list io_completion_timer;
struct list_head internal_reset_pending_q;
+
+ /* Ptr to hba specfic information */
+ void *ctrl_context;
+ u8 msi_flag;
+ struct msix_entry msixentry;
+ u64 map_id;
+ struct megasas_cmd *map_update_cmd;
+ unsigned long bar;
+ long reset_flags;
+ struct mutex reset_mutex;
};
enum {
struct megasas_register_set __iomem *);
int (*check_reset)(struct megasas_instance *, \
struct megasas_register_set __iomem *);
+ irqreturn_t (*service_isr)(int irq, void *devp);
+ void (*tasklet)(unsigned long);
+ u32 (*init_adapter)(struct megasas_instance *);
+ u32 (*build_and_issue_cmd) (struct megasas_instance *,
+ struct scsi_cmnd *);
+ void (*issue_dcmd) (struct megasas_instance *instance,
+ struct megasas_cmd *cmd);
};
#define MEGASAS_IS_LOGICAL(scp) \
struct list_head list;
struct scsi_cmnd *scmd;
struct megasas_instance *instance;
- u32 frame_count;
+ union {
+ struct {
+ u16 smid;
+ u16 resvd;
+ } context;
+ u32 frame_count;
+ };
};
#define MAX_MGMT_ADAPTERS 1024
/*
+ * Linux MegaRAID driver for SAS based RAID controllers
*
- * Linux MegaRAID driver for SAS based RAID controllers
+ * Copyright (c) 2009-2011 LSI Corporation.
*
- * Copyright (c) 2003-2005 LSI Corporation.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
*
- * This program is 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.
*
- * FILE : megaraid_sas.c
- * Version : v00.00.04.31-rc1
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * Authors:
- * (email-id : megaraidlinux@lsi.com)
- * Sreenivas Bagalkote
- * Sumant Patro
- * Bo Yang
+ * FILE: megaraid_sas_base.c
+ * Version : v00.00.05.29-rc1
*
- * List of supported controllers
+ * Authors: LSI Corporation
+ * Sreenivas Bagalkote
+ * Sumant Patro
+ * Bo Yang
*
- * OEM Product Name VID DID SSVID SSID
- * --- ------------ --- --- ---- ----
+ * Send feedback to: <megaraidlinux@lsi.com>
+ *
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: Linuxraid
*/
#include <linux/kernel.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include "megaraid_sas_fusion.h"
#include "megaraid_sas.h"
/*
MODULE_PARM_DESC(max_sectors,
"Maximum number of sectors per IO command");
+static int msix_disable;
+module_param(msix_disable, int, S_IRUGO);
+MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
+
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION);
MODULE_AUTHOR("megaraidlinux@lsi.com");
MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
-static int megasas_transition_to_ready(struct megasas_instance *instance);
+int megasas_transition_to_ready(struct megasas_instance *instance);
static int megasas_get_pd_list(struct megasas_instance *instance);
static int megasas_issue_init_mfi(struct megasas_instance *instance);
static int megasas_register_aen(struct megasas_instance *instance,
/* xscale IOP, vega */
{PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
/* xscale IOP */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)},
+ /* Fusion */
{}
};
static int megasas_poll_wait_aen;
static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
static u32 support_poll_for_event;
-static u32 megasas_dbg_lvl;
+u32 megasas_dbg_lvl;
static u32 support_device_change;
/* define lock for aen poll */
spinlock_t poll_aen_lock;
-static void
+void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status);
+static irqreturn_t megasas_isr(int irq, void *devp);
+static u32
+megasas_init_adapter_mfi(struct megasas_instance *instance);
+u32
+megasas_build_and_issue_cmd(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd);
+static void megasas_complete_cmd_dpc(unsigned long instance_addr);
+void
+megasas_release_fusion(struct megasas_instance *instance);
+int
+megasas_ioc_init_fusion(struct megasas_instance *instance);
+void
+megasas_free_cmds_fusion(struct megasas_instance *instance);
+u8
+megasas_get_map_info(struct megasas_instance *instance);
+int
+megasas_sync_map_info(struct megasas_instance *instance);
+int
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
+void megasas_reset_reply_desc(struct megasas_instance *instance);
+u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo);
+int megasas_reset_fusion(struct Scsi_Host *shost);
+void megasas_fusion_ocr_wq(struct work_struct *work);
+
+void
+megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+{
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
+}
+
/**
* megasas_get_cmd - Get a command from the free pool
* @instance: Adapter soft state
*
* Returns a free command from the pool
*/
-static struct megasas_cmd *megasas_get_cmd(struct megasas_instance
+struct megasas_cmd *megasas_get_cmd(struct megasas_instance
*instance)
{
unsigned long flags;
* @instance: Adapter soft state
* @cmd: Command packet to be returned to free command pool
*/
-static inline void
+inline void
megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
unsigned long flags;
spin_lock_irqsave(&instance->cmd_pool_lock, flags);
cmd->scmd = NULL;
+ cmd->frame_count = 0;
list_add_tail(&cmd->list, &instance->cmd_pool);
spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
/**
-* The following functions are defined for xscale
+* The following functions are defined for xscale
* (deviceid : 1064R, PERC5) controllers
*/
* megasas_clear_interrupt_xscale - Check & clear interrupt
* @regs: MFI register set
*/
-static int
+static int
megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
{
u32 status;
* @frame_count : Number of frames for the command
* @regs : MFI register set
*/
-static inline void
+static inline void
megasas_fire_cmd_xscale(struct megasas_instance *instance,
dma_addr_t frame_phys_addr,
u32 frame_count,
.read_fw_status_reg = megasas_read_fw_status_reg_xscale,
.adp_reset = megasas_adp_reset_xscale,
.check_reset = megasas_check_reset_xscale,
+ .service_isr = megasas_isr,
+ .tasklet = megasas_complete_cmd_dpc,
+ .init_adapter = megasas_init_adapter_mfi,
+ .build_and_issue_cmd = megasas_build_and_issue_cmd,
+ .issue_dcmd = megasas_issue_dcmd,
};
/**
-* This is the end of set of functions & definitions specific
+* This is the end of set of functions & definitions specific
* to xscale (deviceid : 1064R, PERC5) controllers
*/
/**
-* The following functions are defined for ppc (deviceid : 0x60)
+* The following functions are defined for ppc (deviceid : 0x60)
* controllers
*/
megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
{
writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
-
+
writel(~0x80000000, &(regs)->outbound_intr_mask);
/* Dummy readl to force pci flush */
* megasas_clear_interrupt_ppc - Check & clear interrupt
* @regs: MFI register set
*/
-static int
+static int
megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
{
u32 status;
* @frame_count : Number of frames for the command
* @regs : MFI register set
*/
-static inline void
+static inline void
megasas_fire_cmd_ppc(struct megasas_instance *instance,
dma_addr_t frame_phys_addr,
u32 frame_count,
{
unsigned long flags;
spin_lock_irqsave(&instance->hba_lock, flags);
- writel((frame_phys_addr | (frame_count<<1))|1,
+ writel((frame_phys_addr | (frame_count<<1))|1,
&(regs)->inbound_queue_port);
spin_unlock_irqrestore(&instance->hba_lock, flags);
}
return 0;
}
static struct megasas_instance_template megasas_instance_template_ppc = {
-
+
.fire_cmd = megasas_fire_cmd_ppc,
.enable_intr = megasas_enable_intr_ppc,
.disable_intr = megasas_disable_intr_ppc,
.read_fw_status_reg = megasas_read_fw_status_reg_ppc,
.adp_reset = megasas_adp_reset_ppc,
.check_reset = megasas_check_reset_ppc,
+ .service_isr = megasas_isr,
+ .tasklet = megasas_complete_cmd_dpc,
+ .init_adapter = megasas_init_adapter_mfi,
+ .build_and_issue_cmd = megasas_build_and_issue_cmd,
+ .issue_dcmd = megasas_issue_dcmd,
};
/**
.read_fw_status_reg = megasas_read_fw_status_reg_skinny,
.adp_reset = megasas_adp_reset_skinny,
.check_reset = megasas_check_reset_skinny,
+ .service_isr = megasas_isr,
+ .tasklet = megasas_complete_cmd_dpc,
+ .init_adapter = megasas_init_adapter_mfi,
+ .build_and_issue_cmd = megasas_build_and_issue_cmd,
+ .issue_dcmd = megasas_issue_dcmd,
};
.read_fw_status_reg = megasas_read_fw_status_reg_gen2,
.adp_reset = megasas_adp_reset_gen2,
.check_reset = megasas_check_reset_gen2,
+ .service_isr = megasas_isr,
+ .tasklet = megasas_complete_cmd_dpc,
+ .init_adapter = megasas_init_adapter_mfi,
+ .build_and_issue_cmd = megasas_build_and_issue_cmd,
+ .issue_dcmd = megasas_issue_dcmd,
};
/**
* specific to gen2 (deviceid : 0x78, 0x79) controllers
*/
+/*
+ * Template added for TB (Fusion)
+ */
+extern struct megasas_instance_template megasas_instance_template_fusion;
+
/**
* megasas_issue_polled - Issues a polling command
* @instance: Adapter soft state
- * @cmd: Command packet to be issued
+ * @cmd: Command packet to be issued
*
* For polling, MFI requires the cmd_status to be set to 0xFF before posting.
*/
-static int
+int
megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
- int i;
- u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
/*
* Issue the frame using inbound queue port
*/
- instance->instancet->fire_cmd(instance,
- cmd->frame_phys_addr, 0, instance->reg_set);
+ instance->instancet->issue_dcmd(instance, cmd);
/*
* Wait for cmd_status to change
*/
- for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i++) {
- rmb();
- msleep(1);
- }
-
- if (frame_hdr->cmd_status == 0xff)
- return -ETIME;
-
- return 0;
+ return wait_and_poll(instance, cmd);
}
/**
{
cmd->cmd_status = ENODATA;
- instance->instancet->fire_cmd(instance,
- cmd->frame_phys_addr, 0, instance->reg_set);
+ instance->instancet->issue_dcmd(instance, cmd);
wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA);
cmd->sync_cmd = 1;
cmd->cmd_status = 0xFF;
- instance->instancet->fire_cmd(instance,
- cmd->frame_phys_addr, 0, instance->reg_set);
+ instance->instancet->issue_dcmd(instance, cmd);
/*
* Wait for this cmd to complete
/**
* megasas_is_ldio - Checks if the cmd is for logical drive
* @scmd: SCSI command
- *
+ *
* Called by megasas_queue_command to find out if the command to be queued
- * is a logical drive command
+ * is a logical drive command
*/
-static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
+inline int megasas_is_ldio(struct scsi_cmnd *cmd)
{
if (!MEGASAS_IS_LOGICAL(cmd))
return 0;
printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
}
+u32
+megasas_build_and_issue_cmd(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ struct megasas_cmd *cmd;
+ u32 frame_count;
+
+ cmd = megasas_get_cmd(instance);
+ if (!cmd)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ /*
+ * Logical drive command
+ */
+ if (megasas_is_ldio(scmd))
+ frame_count = megasas_build_ldio(instance, scmd, cmd);
+ else
+ frame_count = megasas_build_dcdb(instance, scmd, cmd);
+
+ if (!frame_count)
+ goto out_return_cmd;
+
+ cmd->scmd = scmd;
+ scmd->SCp.ptr = (char *)cmd;
+
+ /*
+ * Issue the command to the FW
+ */
+ atomic_inc(&instance->fw_outstanding);
+
+ instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
+ cmd->frame_count-1, instance->reg_set);
+ /*
+ * Check if we have pend cmds to be completed
+ */
+ if (poll_mode_io && atomic_read(&instance->fw_outstanding))
+ tasklet_schedule(&instance->isr_tasklet);
+
+ return 0;
+out_return_cmd:
+ megasas_return_cmd(instance, cmd);
+ return 1;
+}
+
+
/**
* megasas_queue_command - Queue entry point
* @scmd: SCSI command to be queued
* @done: Callback entry point
*/
static int
-megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
{
- u32 frame_count;
- struct megasas_cmd *cmd;
struct megasas_instance *instance;
unsigned long flags;
break;
}
- cmd = megasas_get_cmd(instance);
- if (!cmd)
+ if (instance->instancet->build_and_issue_cmd(instance, scmd)) {
+ printk(KERN_ERR "megasas: Err returned from build_and_issue_cmd\n");
return SCSI_MLQUEUE_HOST_BUSY;
-
- /*
- * Logical drive command
- */
- if (megasas_is_ldio(scmd))
- frame_count = megasas_build_ldio(instance, scmd, cmd);
- else
- frame_count = megasas_build_dcdb(instance, scmd, cmd);
-
- if (!frame_count)
- goto out_return_cmd;
-
- cmd->scmd = scmd;
- scmd->SCp.ptr = (char *)cmd;
-
- /*
- * Issue the command to the FW
- */
- atomic_inc(&instance->fw_outstanding);
-
- instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
- cmd->frame_count-1, instance->reg_set);
- /*
- * Check if we have pend cmds to be completed
- */
- if (poll_mode_io && atomic_read(&instance->fw_outstanding))
- tasklet_schedule(&instance->isr_tasklet);
-
+ }
return 0;
- out_return_cmd:
- megasas_return_cmd(instance, cmd);
out_done:
done(scmd);
return 0;
}
+static DEF_SCSI_QCMD(megasas_queue_command)
+
static struct megasas_instance *megasas_lookup_instance(u16 host_no)
{
int i;
return 0;
}
-static void megaraid_sas_kill_hba(struct megasas_instance *instance)
+void megaraid_sas_kill_hba(struct megasas_instance *instance)
{
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
- writel(MFI_STOP_ADP,
- &instance->reg_set->reserved_0[0]);
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)) {
+ writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
} else {
- writel(MFI_STOP_ADP,
- &instance->reg_set->inbound_doorbell);
+ writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
+ }
+}
+
+ /**
+ * megasas_check_and_restore_queue_depth - Check if queue depth needs to be
+ * restored to max value
+ * @instance: Adapter soft state
+ *
+ */
+void
+megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
+{
+ unsigned long flags;
+ if (instance->flag & MEGASAS_FW_BUSY
+ && time_after(jiffies, instance->last_time + 5 * HZ)
+ && atomic_read(&instance->fw_outstanding) < 17) {
+
+ spin_lock_irqsave(instance->host->host_lock, flags);
+ instance->flag &= ~MEGASAS_FW_BUSY;
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ instance->host->can_queue =
+ instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+ } else
+ instance->host->can_queue =
+ instance->max_fw_cmds - MEGASAS_INT_CMDS;
+
+ spin_unlock_irqrestore(instance->host->host_lock, flags);
}
}
/*
* Check if we can restore can_queue
*/
- if (instance->flag & MEGASAS_FW_BUSY
- && time_after(jiffies, instance->last_time + 5 * HZ)
- && atomic_read(&instance->fw_outstanding) < 17) {
-
- spin_lock_irqsave(instance->host->host_lock, flags);
- instance->flag &= ~MEGASAS_FW_BUSY;
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
- instance->host->can_queue =
- instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
- } else
- instance->host->can_queue =
- instance->max_fw_cmds - MEGASAS_INT_CMDS;
-
- spin_unlock_irqrestore(instance->host->host_lock, flags);
- }
+ megasas_check_and_restore_queue_depth(instance);
}
static void
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
writel(MFI_STOP_ADP,
- &instance->reg_set->reserved_0[0]);
+ &instance->reg_set->doorbell);
} else {
writel(MFI_STOP_ADP,
&instance->reg_set->inbound_doorbell);
static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
{
int ret;
+ struct megasas_instance *instance;
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
/*
* First wait for all commands to complete
*/
- ret = megasas_generic_reset(scmd);
+ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
+ ret = megasas_reset_fusion(scmd->device->host);
+ else
+ ret = megasas_generic_reset(scmd);
return ret;
}
* @instance: Adapter soft state
* @cmd: Cmd that was issued to abort another cmd
*
- * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q
- * after it issues an abort on a previously issued command. This function
+ * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q
+ * after it issues an abort on a previously issued command. This function
* wakes up all functions waiting on the same wait queue.
*/
static void
* megasas_complete_cmd - Completes a command
* @instance: Adapter soft state
* @cmd: Command to be completed
- * @alt_status: If non-zero, use this value as status to
+ * @alt_status: If non-zero, use this value as status to
* SCSI mid-layer instead of the value returned
* by the FW. This should be used if caller wants
* an alternate status (as in the case of aborted
* commands)
*/
-static void
+void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status)
{
int exception = 0;
struct megasas_header *hdr = &cmd->frame->hdr;
unsigned long flags;
+ struct fusion_context *fusion = instance->ctrl_context;
/* flag for the retry reset */
cmd->retry_for_fw_reset = 0;
case MFI_CMD_SMP:
case MFI_CMD_STP:
case MFI_CMD_DCMD:
+ /* Check for LD map update */
+ if ((cmd->frame->dcmd.opcode == MR_DCMD_LD_MAP_GET_INFO) &&
+ (cmd->frame->dcmd.mbox.b[1] == 1)) {
+ spin_lock_irqsave(instance->host->host_lock, flags);
+ if (cmd->frame->hdr.cmd_status != 0) {
+ if (cmd->frame->hdr.cmd_status !=
+ MFI_STAT_NOT_FOUND)
+ printk(KERN_WARNING "megasas: map sync"
+ "failed, status = 0x%x.\n",
+ cmd->frame->hdr.cmd_status);
+ else {
+ megasas_return_cmd(instance, cmd);
+ spin_unlock_irqrestore(
+ instance->host->host_lock,
+ flags);
+ break;
+ }
+ } else
+ instance->map_id++;
+ megasas_return_cmd(instance, cmd);
+ if (MR_ValidateMapInfo(
+ fusion->ld_map[(instance->map_id & 1)],
+ fusion->load_balance_info))
+ fusion->fast_path_io = 1;
+ else
+ fusion->fast_path_io = 0;
+ megasas_sync_map_info(instance);
+ spin_unlock_irqrestore(instance->host->host_lock,
+ flags);
+ break;
+ }
if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
spin_lock_irqsave(&poll_aen_lock, flags);
* states, driver must take steps to bring it to ready state. Otherwise, it
* has to wait for the ready state.
*/
-static int
+int
megasas_transition_to_ready(struct megasas_instance* instance)
{
int i;
fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
if (fw_state != MFI_STATE_READY)
- printk(KERN_INFO "megasas: Waiting for FW to come to ready"
- " state\n");
+ printk(KERN_INFO "megasas: Waiting for FW to come to ready"
+ " state\n");
while (fw_state != MFI_STATE_READY) {
if ((instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
-
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_FUSION)) {
writel(
MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
- &instance->reg_set->reserved_0[0]);
+ &instance->reg_set->doorbell);
} else {
writel(
MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
case MFI_STATE_BOOT_MESSAGE_PENDING:
if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_FUSION)) {
writel(MFI_INIT_HOTPLUG,
- &instance->reg_set->reserved_0[0]);
+ &instance->reg_set->doorbell);
} else
writel(MFI_INIT_HOTPLUG,
&instance->reg_set->inbound_doorbell);
if ((instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device
+ == PCI_DEVICE_ID_LSI_FUSION)) {
writel(MFI_RESET_FLAGS,
- &instance->reg_set->reserved_0[0]);
+ &instance->reg_set->doorbell);
+ if (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_FUSION) {
+ for (i = 0; i < (10 * 1000); i += 20) {
+ if (readl(
+ &instance->
+ reg_set->
+ doorbell) & 1)
+ msleep(20);
+ else
+ break;
+ }
+ }
} else
writel(MFI_RESET_FLAGS,
&instance->reg_set->inbound_doorbell);
* The cur_state should not last for more than max_wait secs
*/
for (i = 0; i < (max_wait * 1000); i++) {
- fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
MFI_STATE_MASK ;
curr_abs_state =
instance->instancet->read_fw_status_reg(instance->reg_set);
return -ENODEV;
}
}
- printk(KERN_INFO "megasas: FW now in Ready state\n");
+ printk(KERN_INFO "megasas: FW now in Ready state\n");
return 0;
}
static void megasas_teardown_frame_pool(struct megasas_instance *instance)
{
int i;
- u32 max_cmd = instance->max_fw_cmds;
+ u32 max_cmd = instance->max_mfi_cmds;
struct megasas_cmd *cmd;
if (!instance->frame_dma_pool)
u32 frame_count;
struct megasas_cmd *cmd;
- max_cmd = instance->max_fw_cmds;
+ max_cmd = instance->max_mfi_cmds;
/*
* Size of our frame is 64 bytes for MFI frame, followed by max SG
* megasas_free_cmds - Free all the cmds in the free cmd pool
* @instance: Adapter soft state
*/
-static void megasas_free_cmds(struct megasas_instance *instance)
+void megasas_free_cmds(struct megasas_instance *instance)
{
int i;
/* First free the MFI frame pool */
megasas_teardown_frame_pool(instance);
/* Free all the commands in the cmd_list */
- for (i = 0; i < instance->max_fw_cmds; i++)
+ for (i = 0; i < instance->max_mfi_cmds; i++)
+
kfree(instance->cmd_list[i]);
/* Free the cmd_list buffer itself */
* This array is used only to look up the megasas_cmd given the context. The
* free commands themselves are maintained in a linked list called cmd_pool.
*/
-static int megasas_alloc_cmds(struct megasas_instance *instance)
+int megasas_alloc_cmds(struct megasas_instance *instance)
{
int i;
int j;
u32 max_cmd;
struct megasas_cmd *cmd;
- max_cmd = instance->max_fw_cmds;
+ max_cmd = instance->max_mfi_cmds;
/*
* instance->cmd_list is an array of struct megasas_cmd pointers.
return -ENOMEM;
}
+ memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) *max_cmd);
for (i = 0; i < max_cmd; i++) {
instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
}
-/**
- * megasas_init_mfi - Initializes the FW
- * @instance: Adapter soft state
- *
- * This is the main function for initializing MFI firmware.
- */
-static int megasas_init_mfi(struct megasas_instance *instance)
+static u32
+megasas_init_adapter_mfi(struct megasas_instance *instance)
{
+ struct megasas_register_set __iomem *reg_set;
u32 context_sz;
u32 reply_q_sz;
- u32 max_sectors_1;
- u32 max_sectors_2;
- u32 tmp_sectors;
- struct megasas_register_set __iomem *reg_set;
- struct megasas_ctrl_info *ctrl_info;
- /*
- * Map the message registers
- */
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0079GEN2)) {
- instance->base_addr = pci_resource_start(instance->pdev, 1);
- } else {
- instance->base_addr = pci_resource_start(instance->pdev, 0);
- }
-
- if (pci_request_selected_regions(instance->pdev,
- pci_select_bars(instance->pdev, IORESOURCE_MEM),
- "megasas: LSI")) {
- printk(KERN_DEBUG "megasas: IO memory region busy!\n");
- return -EBUSY;
- }
-
- instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
-
- if (!instance->reg_set) {
- printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
- goto fail_ioremap;
- }
reg_set = instance->reg_set;
- switch(instance->pdev->device)
- {
- case PCI_DEVICE_ID_LSI_SAS1078R:
- case PCI_DEVICE_ID_LSI_SAS1078DE:
- instance->instancet = &megasas_instance_template_ppc;
- break;
- case PCI_DEVICE_ID_LSI_SAS1078GEN2:
- case PCI_DEVICE_ID_LSI_SAS0079GEN2:
- instance->instancet = &megasas_instance_template_gen2;
- break;
- case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
- case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
- instance->instancet = &megasas_instance_template_skinny;
- break;
- case PCI_DEVICE_ID_LSI_SAS1064R:
- case PCI_DEVICE_ID_DELL_PERC5:
- default:
- instance->instancet = &megasas_instance_template_xscale;
- break;
- }
-
- /*
- * We expect the FW state to be READY
- */
- if (megasas_transition_to_ready(instance))
- goto fail_ready_state;
-
/*
* Get various operational parameters from status register
*/
* does not exceed max cmds that the FW can support
*/
instance->max_fw_cmds = instance->max_fw_cmds-1;
- instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
+ instance->max_mfi_cmds = instance->max_fw_cmds;
+ instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
0x10;
/*
* Create a pool of commands
if (instance->fw_support_ieee)
instance->flag_ieee = 1;
+ return 0;
+
+fail_fw_init:
+
+ pci_free_consistent(instance->pdev, reply_q_sz,
+ instance->reply_queue, instance->reply_queue_h);
+fail_reply_queue:
+ megasas_free_cmds(instance);
+
+fail_alloc_cmds:
+ iounmap(instance->reg_set);
+ return 1;
+}
+
+/**
+ * megasas_init_fw - Initializes the FW
+ * @instance: Adapter soft state
+ *
+ * This is the main function for initializing firmware
+ */
+
+static int megasas_init_fw(struct megasas_instance *instance)
+{
+ u32 max_sectors_1;
+ u32 max_sectors_2;
+ u32 tmp_sectors;
+ struct megasas_register_set __iomem *reg_set;
+ struct megasas_ctrl_info *ctrl_info;
+ unsigned long bar_list;
+
+ /* Find first memory bar */
+ bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
+ instance->bar = find_first_bit(&bar_list, sizeof(unsigned long));
+ instance->base_addr = pci_resource_start(instance->pdev, instance->bar);
+ if (pci_request_selected_regions(instance->pdev, instance->bar,
+ "megasas: LSI")) {
+ printk(KERN_DEBUG "megasas: IO memory region busy!\n");
+ return -EBUSY;
+ }
+
+ instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
+
+ if (!instance->reg_set) {
+ printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
+ goto fail_ioremap;
+ }
+
+ reg_set = instance->reg_set;
+
+ switch (instance->pdev->device) {
+ case PCI_DEVICE_ID_LSI_FUSION:
+ instance->instancet = &megasas_instance_template_fusion;
+ break;
+ case PCI_DEVICE_ID_LSI_SAS1078R:
+ case PCI_DEVICE_ID_LSI_SAS1078DE:
+ instance->instancet = &megasas_instance_template_ppc;
+ break;
+ case PCI_DEVICE_ID_LSI_SAS1078GEN2:
+ case PCI_DEVICE_ID_LSI_SAS0079GEN2:
+ instance->instancet = &megasas_instance_template_gen2;
+ break;
+ case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
+ case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
+ instance->instancet = &megasas_instance_template_skinny;
+ break;
+ case PCI_DEVICE_ID_LSI_SAS1064R:
+ case PCI_DEVICE_ID_DELL_PERC5:
+ default:
+ instance->instancet = &megasas_instance_template_xscale;
+ break;
+ }
+
+ /*
+ * We expect the FW state to be READY
+ */
+ if (megasas_transition_to_ready(instance))
+ goto fail_ready_state;
+
+ /* Get operational params, sge flags, send init cmd to controller */
+ if (instance->instancet->init_adapter(instance))
+ return -ENODEV;
+
+ printk(KERN_ERR "megasas: INIT adapter done\n");
+
/** for passthrough
* the following function will get the PD LIST.
*/
MEGASAS_COMPLETION_TIMER_INTERVAL);
return 0;
- fail_fw_init:
-
- pci_free_consistent(instance->pdev, reply_q_sz,
- instance->reply_queue, instance->reply_queue_h);
- fail_reply_queue:
- megasas_free_cmds(instance);
-
- fail_alloc_cmds:
- fail_ready_state:
+fail_ready_state:
iounmap(instance->reg_set);
fail_ioremap:
- pci_release_selected_regions(instance->pdev,
- pci_select_bars(instance->pdev, IORESOURCE_MEM));
+ pci_release_selected_regions(instance->pdev, instance->bar);
return -EINVAL;
}
*/
static void megasas_release_mfi(struct megasas_instance *instance)
{
- u32 reply_q_sz = sizeof(u32) * (instance->max_fw_cmds + 1);
+ u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1);
- pci_free_consistent(instance->pdev, reply_q_sz,
+ if (instance->reply_queue)
+ pci_free_consistent(instance->pdev, reply_q_sz,
instance->reply_queue, instance->reply_queue_h);
megasas_free_cmds(instance);
iounmap(instance->reg_set);
- pci_release_selected_regions(instance->pdev,
- pci_select_bars(instance->pdev, IORESOURCE_MEM));
+ pci_release_selected_regions(instance->pdev, instance->bar);
}
/**
/*
* Issue the aen registration frame
*/
- instance->instancet->fire_cmd(instance,
- cmd->frame_phys_addr, 0, instance->reg_set);
+ instance->instancet->issue_dcmd(instance, cmd);
return 0;
}
}
host->max_sectors = instance->max_sectors_per_req;
- host->cmd_per_lun = 128;
+ host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN;
host->max_channel = MEGASAS_MAX_CHANNELS - 1;
host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL;
host->max_lun = MEGASAS_MAX_LUN;
host->max_cmd_len = 16;
+ /* Fusion only supports host reset */
+ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) {
+ host->hostt->eh_device_reset_handler = NULL;
+ host->hostt->eh_bus_reset_handler = NULL;
+ }
+
/*
* Notify the mid-layer about the new controller
*/
/**
* megasas_probe_one - PCI hotplug entry point
* @pdev: PCI device structure
- * @id: PCI ids of supported hotplugged adapter
+ * @id: PCI ids of supported hotplugged adapter
*/
static int __devinit
megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance = (struct megasas_instance *)host->hostdata;
memset(instance, 0, sizeof(*instance));
atomic_set( &instance->fw_reset_no_pci_access, 0 );
+ instance->pdev = pdev;
- instance->producer = pci_alloc_consistent(pdev, sizeof(u32),
- &instance->producer_h);
- instance->consumer = pci_alloc_consistent(pdev, sizeof(u32),
- &instance->consumer_h);
+ switch (instance->pdev->device) {
+ case PCI_DEVICE_ID_LSI_FUSION:
+ {
+ struct fusion_context *fusion;
+
+ instance->ctrl_context =
+ kzalloc(sizeof(struct fusion_context), GFP_KERNEL);
+ if (!instance->ctrl_context) {
+ printk(KERN_DEBUG "megasas: Failed to allocate "
+ "memory for Fusion context info\n");
+ goto fail_alloc_dma_buf;
+ }
+ fusion = instance->ctrl_context;
+ INIT_LIST_HEAD(&fusion->cmd_pool);
+ spin_lock_init(&fusion->cmd_pool_lock);
+ }
+ break;
+ default: /* For all other supported controllers */
+
+ instance->producer =
+ pci_alloc_consistent(pdev, sizeof(u32),
+ &instance->producer_h);
+ instance->consumer =
+ pci_alloc_consistent(pdev, sizeof(u32),
+ &instance->consumer_h);
+
+ if (!instance->producer || !instance->consumer) {
+ printk(KERN_DEBUG "megasas: Failed to allocate"
+ "memory for producer, consumer\n");
+ goto fail_alloc_dma_buf;
+ }
- if (!instance->producer || !instance->consumer) {
- printk(KERN_DEBUG "megasas: Failed to allocate memory for "
- "producer, consumer\n");
- goto fail_alloc_dma_buf;
+ *instance->producer = 0;
+ *instance->consumer = 0;
+ break;
}
- *instance->producer = 0;
- *instance->consumer = 0;
megasas_poll_wait_aen = 0;
instance->flag_ieee = 0;
instance->ev = NULL;
spin_lock_init(&poll_aen_lock);
mutex_init(&instance->aen_mutex);
+ mutex_init(&instance->reset_mutex);
/*
* Initialize PCI related and misc parameters
*/
- instance->pdev = pdev;
instance->host = host;
instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
instance->init_id = MEGASAS_DEFAULT_INIT_ID;
instance->last_time = 0;
instance->disableOnlineCtrlReset = 1;
- INIT_WORK(&instance->work_init, process_fw_state_change_wq);
+ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
+ INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
+ else
+ INIT_WORK(&instance->work_init, process_fw_state_change_wq);
/*
* Initialize MFI Firmware
*/
- if (megasas_init_mfi(instance))
+ if (megasas_init_fw(instance))
goto fail_init_mfi;
+ /* Try to enable MSI-X */
+ if ((instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078R) &&
+ (instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078DE) &&
+ (instance->pdev->device != PCI_DEVICE_ID_LSI_VERDE_ZCR) &&
+ !msix_disable && !pci_enable_msix(instance->pdev,
+ &instance->msixentry, 1))
+ instance->msi_flag = 1;
+
/*
* Register IRQ
*/
- if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED, "megasas", instance)) {
+ if (request_irq(instance->msi_flag ? instance->msixentry.vector :
+ pdev->irq, instance->instancet->service_isr,
+ IRQF_SHARED, "megasas", instance)) {
printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
goto fail_irq;
}
pci_set_drvdata(pdev, NULL);
instance->instancet->disable_intr(instance->reg_set);
- free_irq(instance->pdev->irq, instance);
-
- megasas_release_mfi(instance);
+ free_irq(instance->msi_flag ? instance->msixentry.vector :
+ instance->pdev->irq, instance);
+ if (instance->msi_flag)
+ pci_disable_msix(instance->pdev);
fail_irq:
fail_init_mfi:
instance->evt_detail,
instance->evt_detail_h);
- if (instance->producer)
+ if (instance->producer) {
pci_free_consistent(pdev, sizeof(u32), instance->producer,
instance->producer_h);
+ megasas_release_mfi(instance);
+ } else {
+ megasas_release_fusion(instance);
+ }
if (instance->consumer)
pci_free_consistent(pdev, sizeof(u32), instance->consumer,
instance->consumer_h);
if (instance->aen_cmd)
megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd);
-
+ if (instance->map_update_cmd)
+ megasas_issue_blocked_abort_cmd(instance,
+ instance->map_update_cmd);
dcmd = &cmd->frame->dcmd;
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
pci_set_drvdata(instance->pdev, instance);
instance->instancet->disable_intr(instance->reg_set);
- free_irq(instance->pdev->irq, instance);
+ free_irq(instance->msi_flag ? instance->msixentry.vector :
+ instance->pdev->irq, instance);
+ if (instance->msi_flag)
+ pci_disable_msix(instance->pdev);
pci_save_state(pdev);
pci_disable_device(pdev);
* Initialize MFI Firmware
*/
- *instance->producer = 0;
- *instance->consumer = 0;
-
atomic_set(&instance->fw_outstanding, 0);
/*
if (megasas_transition_to_ready(instance))
goto fail_ready_state;
- if (megasas_issue_init_mfi(instance))
- goto fail_init_mfi;
+ switch (instance->pdev->device) {
+ case PCI_DEVICE_ID_LSI_FUSION:
+ {
+ megasas_reset_reply_desc(instance);
+ if (megasas_ioc_init_fusion(instance)) {
+ megasas_free_cmds(instance);
+ megasas_free_cmds_fusion(instance);
+ goto fail_init_mfi;
+ }
+ if (!megasas_get_map_info(instance))
+ megasas_sync_map_info(instance);
+ }
+ break;
+ default:
+ *instance->producer = 0;
+ *instance->consumer = 0;
+ if (megasas_issue_init_mfi(instance))
+ goto fail_init_mfi;
+ break;
+ }
- tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
- (unsigned long)instance);
+ tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
+ (unsigned long)instance);
+
+ /* Now re-enable MSI-X */
+ if (instance->msi_flag)
+ pci_enable_msix(instance->pdev, &instance->msixentry, 1);
/*
* Register IRQ
*/
- if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
- "megasas", instance)) {
+ if (request_irq(instance->msi_flag ? instance->msixentry.vector :
+ pdev->irq, instance->instancet->service_isr,
+ IRQF_SHARED, "megasas", instance)) {
printk(KERN_ERR "megasas: Failed to register IRQ\n");
goto fail_irq;
}
int i;
struct Scsi_Host *host;
struct megasas_instance *instance;
+ struct fusion_context *fusion;
instance = pci_get_drvdata(pdev);
instance->unload = 1;
host = instance->host;
+ fusion = instance->ctrl_context;
if (poll_mode_io)
del_timer_sync(&instance->io_completion_timer);
instance->instancet->disable_intr(instance->reg_set);
- free_irq(instance->pdev->irq, instance);
-
- megasas_release_mfi(instance);
-
- pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
- instance->evt_detail, instance->evt_detail_h);
-
- pci_free_consistent(pdev, sizeof(u32), instance->producer,
- instance->producer_h);
-
- pci_free_consistent(pdev, sizeof(u32), instance->consumer,
- instance->consumer_h);
+ free_irq(instance->msi_flag ? instance->msixentry.vector :
+ instance->pdev->irq, instance);
+ if (instance->msi_flag)
+ pci_disable_msix(instance->pdev);
+
+ switch (instance->pdev->device) {
+ case PCI_DEVICE_ID_LSI_FUSION:
+ megasas_release_fusion(instance);
+ for (i = 0; i < 2 ; i++)
+ if (fusion->ld_map[i])
+ dma_free_coherent(&instance->pdev->dev,
+ fusion->map_sz,
+ fusion->ld_map[i],
+ fusion->
+ ld_map_phys[i]);
+ kfree(instance->ctrl_context);
+ break;
+ default:
+ megasas_release_mfi(instance);
+ pci_free_consistent(pdev,
+ sizeof(struct megasas_evt_detail),
+ instance->evt_detail,
+ instance->evt_detail_h);
+ pci_free_consistent(pdev, sizeof(u32),
+ instance->producer,
+ instance->producer_h);
+ pci_free_consistent(pdev, sizeof(u32),
+ instance->consumer,
+ instance->consumer_h);
+ break;
+ }
scsi_host_put(host);
break;
case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
case MR_EVT_FOREIGN_CFG_IMPORTED:
+ case MR_EVT_LD_STATE_CHANGE:
doscan = 1;
break;
default:
pci_unregister_driver(&megasas_pci_driver);
err_pcidrv:
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
- return rval;
+ return rval;
}
/**
--- /dev/null
+/*
+ * Linux MegaRAID driver for SAS based RAID controllers
+ *
+ * Copyright (c) 2009-2011 LSI Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * FILE: megaraid_sas_fp.c
+ *
+ * Authors: LSI Corporation
+ * Sumant Patro
+ * Varad Talamacki
+ * Manoj Jose
+ *
+ * Send feedback to: <megaraidlinux@lsi.com>
+ *
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: Linuxraid
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <linux/uio.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/compat.h>
+#include <linux/blkdev.h>
+#include <linux/poll.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "megaraid_sas_fusion.h"
+#include <asm/div64.h>
+
+#define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
+#define MR_LD_STATE_OPTIMAL 3
+#define FALSE 0
+#define TRUE 1
+
+/* Prototypes */
+void
+mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo);
+
+u32 mega_mod64(u64 dividend, u32 divisor)
+{
+ u64 d;
+ u32 remainder;
+
+ if (!divisor)
+ printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n");
+ d = dividend;
+ remainder = do_div(d, divisor);
+ return remainder;
+}
+
+/**
+ * @param dividend : Dividend
+ * @param divisor : Divisor
+ *
+ * @return quotient
+ **/
+u64 mega_div64_32(uint64_t dividend, uint32_t divisor)
+{
+ u32 remainder;
+ u64 d;
+
+ if (!divisor)
+ printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n");
+
+ d = dividend;
+ remainder = do_div(d, divisor);
+
+ return d;
+}
+
+struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return &map->raidMap.ldSpanMap[ld].ldRaid;
+}
+
+static struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld,
+ struct MR_FW_RAID_MAP_ALL
+ *map)
+{
+ return &map->raidMap.ldSpanMap[ld].spanBlock[0];
+}
+
+static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
+}
+
+static u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.arMapInfo[ar].pd[arm];
+}
+
+static u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
+}
+
+static u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.devHndlInfo[pd].curDevHdl;
+}
+
+u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.ldSpanMap[ld].ldRaid.targetId;
+}
+
+u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.ldTgtIdToLd[ldTgtId];
+}
+
+static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span,
+ struct MR_FW_RAID_MAP_ALL *map)
+{
+ return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;
+}
+
+/*
+ * This function will validate Map info data provided by FW
+ */
+u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo)
+{
+ struct MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap;
+
+ if (pFwRaidMap->totalSize !=
+ (sizeof(struct MR_FW_RAID_MAP) -sizeof(struct MR_LD_SPAN_MAP) +
+ (sizeof(struct MR_LD_SPAN_MAP) *pFwRaidMap->ldCount))) {
+ printk(KERN_ERR "megasas: map info structure size 0x%x is not matching with ld count\n",
+ (unsigned int)((sizeof(struct MR_FW_RAID_MAP) -
+ sizeof(struct MR_LD_SPAN_MAP)) +
+ (sizeof(struct MR_LD_SPAN_MAP) *
+ pFwRaidMap->ldCount)));
+ printk(KERN_ERR "megasas: span map %x, pFwRaidMap->totalSize "
+ ": %x\n", (unsigned int)sizeof(struct MR_LD_SPAN_MAP),
+ pFwRaidMap->totalSize);
+ return 0;
+ }
+
+ mr_update_load_balance_params(map, lbInfo);
+
+ return 1;
+}
+
+u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk,
+ struct MR_FW_RAID_MAP_ALL *map, int *div_error)
+{
+ struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);
+ struct MR_QUAD_ELEMENT *quad;
+ struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
+ u32 span, j;
+
+ for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) {
+
+ for (j = 0; j < pSpanBlock->block_span_info.noElements; j++) {
+ quad = &pSpanBlock->block_span_info.quad[j];
+
+ if (quad->diff == 0) {
+ *div_error = 1;
+ return span;
+ }
+ if (quad->logStart <= row && row <= quad->logEnd &&
+ (mega_mod64(row-quad->logStart, quad->diff)) == 0) {
+ if (span_blk != NULL) {
+ u64 blk, debugBlk;
+ blk =
+ mega_div64_32(
+ (row-quad->logStart),
+ quad->diff);
+ debugBlk = blk;
+
+ blk = (blk + quad->offsetInSpan) <<
+ raid->stripeShift;
+ *span_blk = blk;
+ }
+ return span;
+ }
+ }
+ }
+ return span;
+}
+
+/*
+******************************************************************************
+*
+* This routine calculates the arm, span and block for the specified stripe and
+* reference in stripe.
+*
+* Inputs :
+*
+* ld - Logical drive number
+* stripRow - Stripe number
+* stripRef - Reference in stripe
+*
+* Outputs :
+*
+* span - Span number
+* block - Absolute Block number in the physical disk
+*/
+u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock,
+ u16 *pDevHandle, struct RAID_CONTEXT *pRAID_Context,
+ struct MR_FW_RAID_MAP_ALL *map)
+{
+ struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
+ u32 pd, arRef;
+ u8 physArm, span;
+ u64 row;
+ u8 retval = TRUE;
+ int error_code = 0;
+
+ row = mega_div64_32(stripRow, raid->rowDataSize);
+
+ if (raid->level == 6) {
+ /* logical arm within row */
+ u32 logArm = mega_mod64(stripRow, raid->rowDataSize);
+ u32 rowMod, armQ, arm;
+
+ if (raid->rowSize == 0)
+ return FALSE;
+ /* get logical row mod */
+ rowMod = mega_mod64(row, raid->rowSize);
+ armQ = raid->rowSize-1-rowMod; /* index of Q drive */
+ arm = armQ+1+logArm; /* data always logically follows Q */
+ if (arm >= raid->rowSize) /* handle wrap condition */
+ arm -= raid->rowSize;
+ physArm = (u8)arm;
+ } else {
+ if (raid->modFactor == 0)
+ return FALSE;
+ physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow,
+ raid->modFactor),
+ map);
+ }
+
+ if (raid->spanDepth == 1) {
+ span = 0;
+ *pdBlock = row << raid->stripeShift;
+ } else {
+ span = (u8)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code);
+ if (error_code == 1)
+ return FALSE;
+ }
+
+ /* Get the array on which this span is present */
+ arRef = MR_LdSpanArrayGet(ld, span, map);
+ pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */
+
+ if (pd != MR_PD_INVALID)
+ /* Get dev handle from Pd. */
+ *pDevHandle = MR_PdDevHandleGet(pd, map);
+ else {
+ *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */
+ if (raid->level >= 5)
+ pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
+ else if (raid->level == 1) {
+ /* Get alternate Pd. */
+ pd = MR_ArPdGet(arRef, physArm + 1, map);
+ if (pd != MR_PD_INVALID)
+ /* Get dev handle from Pd */
+ *pDevHandle = MR_PdDevHandleGet(pd, map);
+ }
+ retval = FALSE;
+ }
+
+ *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
+ pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
+ physArm;
+ return retval;
+}
+
+/*
+******************************************************************************
+*
+* MR_BuildRaidContext function
+*
+* This function will initiate command processing. The start/end row and strip
+* information is calculated then the lock is acquired.
+* This function will return 0 if region lock was acquired OR return num strips
+*/
+u8
+MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
+ struct RAID_CONTEXT *pRAID_Context,
+ struct MR_FW_RAID_MAP_ALL *map)
+{
+ struct MR_LD_RAID *raid;
+ u32 ld, stripSize, stripe_mask;
+ u64 endLba, endStrip, endRow, start_row, start_strip;
+ u64 regStart;
+ u32 regSize;
+ u8 num_strips, numRows;
+ u16 ref_in_start_stripe, ref_in_end_stripe;
+ u64 ldStartBlock;
+ u32 numBlocks, ldTgtId;
+ u8 isRead;
+ u8 retval = 0;
+
+ ldStartBlock = io_info->ldStartBlock;
+ numBlocks = io_info->numBlocks;
+ ldTgtId = io_info->ldTgtId;
+ isRead = io_info->isRead;
+
+ ld = MR_TargetIdToLdGet(ldTgtId, map);
+ raid = MR_LdRaidGet(ld, map);
+
+ stripSize = 1 << raid->stripeShift;
+ stripe_mask = stripSize-1;
+ /*
+ * calculate starting row and stripe, and number of strips and rows
+ */
+ start_strip = ldStartBlock >> raid->stripeShift;
+ ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask);
+ endLba = ldStartBlock + numBlocks - 1;
+ ref_in_end_stripe = (u16)(endLba & stripe_mask);
+ endStrip = endLba >> raid->stripeShift;
+ num_strips = (u8)(endStrip - start_strip + 1); /* End strip */
+ if (raid->rowDataSize == 0)
+ return FALSE;
+ start_row = mega_div64_32(start_strip, raid->rowDataSize);
+ endRow = mega_div64_32(endStrip, raid->rowDataSize);
+ numRows = (u8)(endRow - start_row + 1);
+
+ /*
+ * calculate region info.
+ */
+
+ /* assume region is at the start of the first row */
+ regStart = start_row << raid->stripeShift;
+ /* assume this IO needs the full row - we'll adjust if not true */
+ regSize = stripSize;
+
+ /* If IO spans more than 1 strip, fp is not possible
+ FP is not possible for writes on non-0 raid levels
+ FP is not possible if LD is not capable */
+ if (num_strips > 1 || (!isRead && raid->level != 0) ||
+ !raid->capability.fpCapable) {
+ io_info->fpOkForIo = FALSE;
+ } else {
+ io_info->fpOkForIo = TRUE;
+ }
+
+ if (numRows == 1) {
+ /* single-strip IOs can always lock only the data needed */
+ if (num_strips == 1) {
+ regStart += ref_in_start_stripe;
+ regSize = numBlocks;
+ }
+ /* multi-strip IOs always need to full stripe locked */
+ } else {
+ if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {
+ /* If the start strip is the last in the start row */
+ regStart += ref_in_start_stripe;
+ regSize = stripSize - ref_in_start_stripe;
+ /* initialize count to sectors from startref to end
+ of strip */
+ }
+
+ if (numRows > 2)
+ /* Add complete rows in the middle of the transfer */
+ regSize += (numRows-2) << raid->stripeShift;
+
+ /* if IO ends within first strip of last row */
+ if (endStrip == endRow*raid->rowDataSize)
+ regSize += ref_in_end_stripe+1;
+ else
+ regSize += stripSize;
+ }
+
+ pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec;
+ pRAID_Context->regLockFlags = (isRead) ? REGION_TYPE_SHARED_READ :
+ raid->regTypeReqOnWrite;
+ pRAID_Context->VirtualDiskTgtId = raid->targetId;
+ pRAID_Context->regLockRowLBA = regStart;
+ pRAID_Context->regLockLength = regSize;
+ pRAID_Context->configSeqNum = raid->seqNum;
+
+ /*Get Phy Params only if FP capable, or else leave it to MR firmware
+ to do the calculation.*/
+ if (io_info->fpOkForIo) {
+ retval = MR_GetPhyParams(ld, start_strip, ref_in_start_stripe,
+ &io_info->pdBlock,
+ &io_info->devHandle, pRAID_Context,
+ map);
+ /* If IO on an invalid Pd, then FP i snot possible */
+ if (io_info->devHandle == MR_PD_INVALID)
+ io_info->fpOkForIo = FALSE;
+ return retval;
+ } else if (isRead) {
+ uint stripIdx;
+ for (stripIdx = 0; stripIdx < num_strips; stripIdx++) {
+ if (!MR_GetPhyParams(ld, start_strip + stripIdx,
+ ref_in_start_stripe,
+ &io_info->pdBlock,
+ &io_info->devHandle,
+ pRAID_Context, map))
+ return TRUE;
+ }
+ }
+ return TRUE;
+}
+
+void
+mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo)
+{
+ int ldCount;
+ u16 ld;
+ struct MR_LD_RAID *raid;
+
+ for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
+ ld = MR_TargetIdToLdGet(ldCount, map);
+ if (ld >= MAX_LOGICAL_DRIVES) {
+ lbInfo[ldCount].loadBalanceFlag = 0;
+ continue;
+ }
+
+ raid = MR_LdRaidGet(ld, map);
+
+ /* Two drive Optimal RAID 1 */
+ if ((raid->level == 1) && (raid->rowSize == 2) &&
+ (raid->spanDepth == 1) && raid->ldState ==
+ MR_LD_STATE_OPTIMAL) {
+ u32 pd, arRef;
+
+ lbInfo[ldCount].loadBalanceFlag = 1;
+
+ /* Get the array on which this span is present */
+ arRef = MR_LdSpanArrayGet(ld, 0, map);
+
+ /* Get the Pd */
+ pd = MR_ArPdGet(arRef, 0, map);
+ /* Get dev handle from Pd */
+ lbInfo[ldCount].raid1DevHandle[0] =
+ MR_PdDevHandleGet(pd, map);
+ /* Get the Pd */
+ pd = MR_ArPdGet(arRef, 1, map);
+
+ /* Get the dev handle from Pd */
+ lbInfo[ldCount].raid1DevHandle[1] =
+ MR_PdDevHandleGet(pd, map);
+ } else
+ lbInfo[ldCount].loadBalanceFlag = 0;
+ }
+}
+
+u8 megasas_get_best_arm(struct LD_LOAD_BALANCE_INFO *lbInfo, u8 arm, u64 block,
+ u32 count)
+{
+ u16 pend0, pend1;
+ u64 diff0, diff1;
+ u8 bestArm;
+
+ /* get the pending cmds for the data and mirror arms */
+ pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]);
+ pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]);
+
+ /* Determine the disk whose head is nearer to the req. block */
+ diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]);
+ diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]);
+ bestArm = (diff0 <= diff1 ? 0 : 1);
+
+ if ((bestArm == arm && pend0 > pend1 + 16) ||
+ (bestArm != arm && pend1 > pend0 + 16))
+ bestArm ^= 1;
+
+ /* Update the last accessed block on the correct pd */
+ lbInfo->last_accessed_block[bestArm] = block + count - 1;
+
+ return bestArm;
+}
+
+u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
+ struct IO_REQUEST_INFO *io_info)
+{
+ u8 arm, old_arm;
+ u16 devHandle;
+
+ old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1;
+
+ /* get best new arm */
+ arm = megasas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock,
+ io_info->numBlocks);
+ devHandle = lbInfo->raid1DevHandle[arm];
+ atomic_inc(&lbInfo->scsi_pending_cmds[arm]);
+
+ return devHandle;
+}
--- /dev/null
+/*
+ * Linux MegaRAID driver for SAS based RAID controllers
+ *
+ * Copyright (c) 2009-2011 LSI Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * FILE: megaraid_sas_fusion.c
+ *
+ * Authors: LSI Corporation
+ * Sumant Patro
+ * Adam Radford <linuxraid@lsi.com>
+ *
+ * Send feedback to: <megaraidlinux@lsi.com>
+ *
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: Linuxraid
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <linux/uio.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/compat.h>
+#include <linux/blkdev.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "megaraid_sas_fusion.h"
+#include "megaraid_sas.h"
+
+extern void megasas_free_cmds(struct megasas_instance *instance);
+extern struct megasas_cmd *megasas_get_cmd(struct megasas_instance
+ *instance);
+extern void
+megasas_complete_cmd(struct megasas_instance *instance,
+ struct megasas_cmd *cmd, u8 alt_status);
+int megasas_is_ldio(struct scsi_cmnd *cmd);
+int
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
+
+void
+megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd);
+int megasas_alloc_cmds(struct megasas_instance *instance);
+int
+megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs);
+int
+megasas_issue_polled(struct megasas_instance *instance,
+ struct megasas_cmd *cmd);
+
+u8
+MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
+ struct RAID_CONTEXT *pRAID_Context,
+ struct MR_FW_RAID_MAP_ALL *map);
+u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
+struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
+
+u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
+u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo);
+u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
+ struct IO_REQUEST_INFO *in_info);
+int megasas_transition_to_ready(struct megasas_instance *instance);
+void megaraid_sas_kill_hba(struct megasas_instance *instance);
+
+extern u32 megasas_dbg_lvl;
+
+/**
+ * megasas_enable_intr_fusion - Enables interrupts
+ * @regs: MFI register set
+ */
+void
+megasas_enable_intr_fusion(struct megasas_register_set __iomem *regs)
+{
+ writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
+
+ /* Dummy readl to force pci flush */
+ readl(®s->outbound_intr_mask);
+}
+
+/**
+ * megasas_disable_intr_fusion - Disables interrupt
+ * @regs: MFI register set
+ */
+void
+megasas_disable_intr_fusion(struct megasas_register_set __iomem *regs)
+{
+ u32 mask = 0xFFFFFFFF;
+ u32 status;
+
+ writel(mask, ®s->outbound_intr_mask);
+ /* Dummy readl to force pci flush */
+ status = readl(®s->outbound_intr_mask);
+}
+
+int
+megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs)
+{
+ u32 status;
+ /*
+ * Check if it is our interrupt
+ */
+ status = readl(®s->outbound_intr_status);
+
+ if (status & 1) {
+ writel(status, ®s->outbound_intr_status);
+ readl(®s->outbound_intr_status);
+ return 1;
+ }
+ if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
+ return 0;
+
+ /*
+ * dummy read to flush PCI
+ */
+ readl(®s->outbound_intr_status);
+
+ return 1;
+}
+
+/**
+ * megasas_get_cmd_fusion - Get a command from the free pool
+ * @instance: Adapter soft state
+ *
+ * Returns a free command from the pool
+ */
+struct megasas_cmd_fusion *megasas_get_cmd_fusion(struct megasas_instance
+ *instance)
+{
+ unsigned long flags;
+ struct fusion_context *fusion =
+ (struct fusion_context *)instance->ctrl_context;
+ struct megasas_cmd_fusion *cmd = NULL;
+
+ spin_lock_irqsave(&fusion->cmd_pool_lock, flags);
+
+ if (!list_empty(&fusion->cmd_pool)) {
+ cmd = list_entry((&fusion->cmd_pool)->next,
+ struct megasas_cmd_fusion, list);
+ list_del_init(&cmd->list);
+ } else {
+ printk(KERN_ERR "megasas: Command pool (fusion) empty!\n");
+ }
+
+ spin_unlock_irqrestore(&fusion->cmd_pool_lock, flags);
+ return cmd;
+}
+
+/**
+ * megasas_return_cmd_fusion - Return a cmd to free command pool
+ * @instance: Adapter soft state
+ * @cmd: Command packet to be returned to free command pool
+ */
+static inline void
+megasas_return_cmd_fusion(struct megasas_instance *instance,
+ struct megasas_cmd_fusion *cmd)
+{
+ unsigned long flags;
+ struct fusion_context *fusion =
+ (struct fusion_context *)instance->ctrl_context;
+
+ spin_lock_irqsave(&fusion->cmd_pool_lock, flags);
+
+ cmd->scmd = NULL;
+ cmd->sync_cmd_idx = (u32)ULONG_MAX;
+ list_add_tail(&cmd->list, &fusion->cmd_pool);
+
+ spin_unlock_irqrestore(&fusion->cmd_pool_lock, flags);
+}
+
+/**
+ * megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA pool
+ * @instance: Adapter soft state
+ */
+static void megasas_teardown_frame_pool_fusion(
+ struct megasas_instance *instance)
+{
+ int i;
+ struct fusion_context *fusion = instance->ctrl_context;
+
+ u16 max_cmd = instance->max_fw_cmds;
+
+ struct megasas_cmd_fusion *cmd;
+
+ if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
+ printk(KERN_ERR "megasas: dma pool is null. SG Pool %p, "
+ "sense pool : %p\n", fusion->sg_dma_pool,
+ fusion->sense_dma_pool);
+ return;
+ }
+
+ /*
+ * Return all frames to pool
+ */
+ for (i = 0; i < max_cmd; i++) {
+
+ cmd = fusion->cmd_list[i];
+
+ if (cmd->sg_frame)
+ pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
+ cmd->sg_frame_phys_addr);
+
+ if (cmd->sense)
+ pci_pool_free(fusion->sense_dma_pool, cmd->sense,
+ cmd->sense_phys_addr);
+ }
+
+ /*
+ * Now destroy the pool itself
+ */
+ pci_pool_destroy(fusion->sg_dma_pool);
+ pci_pool_destroy(fusion->sense_dma_pool);
+
+ fusion->sg_dma_pool = NULL;
+ fusion->sense_dma_pool = NULL;
+}
+
+/**
+ * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool
+ * @instance: Adapter soft state
+ */
+void
+megasas_free_cmds_fusion(struct megasas_instance *instance)
+{
+ int i;
+ struct fusion_context *fusion = instance->ctrl_context;
+
+ u32 max_cmds, req_sz, reply_sz, io_frames_sz;
+
+
+ req_sz = fusion->request_alloc_sz;
+ reply_sz = fusion->reply_alloc_sz;
+ io_frames_sz = fusion->io_frames_alloc_sz;
+
+ max_cmds = instance->max_fw_cmds;
+
+ /* Free descriptors and request Frames memory */
+ if (fusion->req_frames_desc)
+ dma_free_coherent(&instance->pdev->dev, req_sz,
+ fusion->req_frames_desc,
+ fusion->req_frames_desc_phys);
+
+ if (fusion->reply_frames_desc) {
+ pci_pool_free(fusion->reply_frames_desc_pool,
+ fusion->reply_frames_desc,
+ fusion->reply_frames_desc_phys);
+ pci_pool_destroy(fusion->reply_frames_desc_pool);
+ }
+
+ if (fusion->io_request_frames) {
+ pci_pool_free(fusion->io_request_frames_pool,
+ fusion->io_request_frames,
+ fusion->io_request_frames_phys);
+ pci_pool_destroy(fusion->io_request_frames_pool);
+ }
+
+ /* Free the Fusion frame pool */
+ megasas_teardown_frame_pool_fusion(instance);
+
+ /* Free all the commands in the cmd_list */
+ for (i = 0; i < max_cmds; i++)
+ kfree(fusion->cmd_list[i]);
+
+ /* Free the cmd_list buffer itself */
+ kfree(fusion->cmd_list);
+ fusion->cmd_list = NULL;
+
+ INIT_LIST_HEAD(&fusion->cmd_pool);
+}
+
+/**
+ * megasas_create_frame_pool_fusion - Creates DMA pool for cmd frames
+ * @instance: Adapter soft state
+ *
+ */
+static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
+{
+ int i;
+ u32 max_cmd;
+ struct fusion_context *fusion;
+ struct megasas_cmd_fusion *cmd;
+ u32 total_sz_chain_frame;
+
+ fusion = instance->ctrl_context;
+ max_cmd = instance->max_fw_cmds;
+
+ total_sz_chain_frame = MEGASAS_MAX_SZ_CHAIN_FRAME;
+
+ /*
+ * Use DMA pool facility provided by PCI layer
+ */
+
+ fusion->sg_dma_pool = pci_pool_create("megasas sg pool fusion",
+ instance->pdev,
+ total_sz_chain_frame, 4,
+ 0);
+ if (!fusion->sg_dma_pool) {
+ printk(KERN_DEBUG "megasas: failed to setup request pool "
+ "fusion\n");
+ return -ENOMEM;
+ }
+ fusion->sense_dma_pool = pci_pool_create("megasas sense pool fusion",
+ instance->pdev,
+ SCSI_SENSE_BUFFERSIZE, 64, 0);
+
+ if (!fusion->sense_dma_pool) {
+ printk(KERN_DEBUG "megasas: failed to setup sense pool "
+ "fusion\n");
+ pci_pool_destroy(fusion->sg_dma_pool);
+ fusion->sg_dma_pool = NULL;
+ return -ENOMEM;
+ }
+
+ /*
+ * Allocate and attach a frame to each of the commands in cmd_list
+ */
+ for (i = 0; i < max_cmd; i++) {
+
+ cmd = fusion->cmd_list[i];
+
+ cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
+ GFP_KERNEL,
+ &cmd->sg_frame_phys_addr);
+
+ cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
+ GFP_KERNEL, &cmd->sense_phys_addr);
+ /*
+ * megasas_teardown_frame_pool_fusion() takes care of freeing
+ * whatever has been allocated
+ */
+ if (!cmd->sg_frame || !cmd->sense) {
+ printk(KERN_DEBUG "megasas: pci_pool_alloc failed\n");
+ megasas_teardown_frame_pool_fusion(instance);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+/**
+ * megasas_alloc_cmds_fusion - Allocates the command packets
+ * @instance: Adapter soft state
+ *
+ *
+ * Each frame has a 32-bit field called context. This context is used to get
+ * back the megasas_cmd_fusion from the frame when a frame gets completed
+ * In this driver, the 32 bit values are the indices into an array cmd_list.
+ * This array is used only to look up the megasas_cmd_fusion given the context.
+ * The free commands themselves are maintained in a linked list called cmd_pool.
+ *
+ * cmds are formed in the io_request and sg_frame members of the
+ * megasas_cmd_fusion. The context field is used to get a request descriptor
+ * and is used as SMID of the cmd.
+ * SMID value range is from 1 to max_fw_cmds.
+ */
+int
+megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+{
+ int i, j;
+ u32 max_cmd, io_frames_sz;
+ struct fusion_context *fusion;
+ struct megasas_cmd_fusion *cmd;
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+ u32 offset;
+ dma_addr_t io_req_base_phys;
+ u8 *io_req_base;
+
+ fusion = instance->ctrl_context;
+
+ max_cmd = instance->max_fw_cmds;
+
+ fusion->req_frames_desc =
+ dma_alloc_coherent(&instance->pdev->dev,
+ fusion->request_alloc_sz,
+ &fusion->req_frames_desc_phys, GFP_KERNEL);
+
+ if (!fusion->req_frames_desc) {
+ printk(KERN_ERR "megasas; Could not allocate memory for "
+ "request_frames\n");
+ goto fail_req_desc;
+ }
+
+ fusion->reply_frames_desc_pool =
+ pci_pool_create("reply_frames pool", instance->pdev,
+ fusion->reply_alloc_sz, 16, 0);
+
+ if (!fusion->reply_frames_desc_pool) {
+ printk(KERN_ERR "megasas; Could not allocate memory for "
+ "reply_frame pool\n");
+ goto fail_reply_desc;
+ }
+
+ fusion->reply_frames_desc =
+ pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
+ &fusion->reply_frames_desc_phys);
+ if (!fusion->reply_frames_desc) {
+ printk(KERN_ERR "megasas; Could not allocate memory for "
+ "reply_frame pool\n");
+ pci_pool_destroy(fusion->reply_frames_desc_pool);
+ goto fail_reply_desc;
+ }
+
+ reply_desc = fusion->reply_frames_desc;
+ for (i = 0; i < fusion->reply_q_depth; i++, reply_desc++)
+ reply_desc->Words = ULLONG_MAX;
+
+ io_frames_sz = fusion->io_frames_alloc_sz;
+
+ fusion->io_request_frames_pool =
+ pci_pool_create("io_request_frames pool", instance->pdev,
+ fusion->io_frames_alloc_sz, 16, 0);
+
+ if (!fusion->io_request_frames_pool) {
+ printk(KERN_ERR "megasas: Could not allocate memory for "
+ "io_request_frame pool\n");
+ goto fail_io_frames;
+ }
+
+ fusion->io_request_frames =
+ pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
+ &fusion->io_request_frames_phys);
+ if (!fusion->io_request_frames) {
+ printk(KERN_ERR "megasas: Could not allocate memory for "
+ "io_request_frames frames\n");
+ pci_pool_destroy(fusion->io_request_frames_pool);
+ goto fail_io_frames;
+ }
+
+ /*
+ * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
+ * Allocate the dynamic array first and then allocate individual
+ * commands.
+ */
+ fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *)
+ *max_cmd, GFP_KERNEL);
+
+ if (!fusion->cmd_list) {
+ printk(KERN_DEBUG "megasas: out of memory. Could not alloc "
+ "memory for cmd_list_fusion\n");
+ goto fail_cmd_list;
+ }
+
+ memset(fusion->cmd_list, 0, sizeof(struct megasas_cmd_fusion *)
+ *max_cmd);
+
+ max_cmd = instance->max_fw_cmds;
+ for (i = 0; i < max_cmd; i++) {
+ fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
+ GFP_KERNEL);
+ if (!fusion->cmd_list[i]) {
+ printk(KERN_ERR "Could not alloc cmd list fusion\n");
+
+ for (j = 0; j < i; j++)
+ kfree(fusion->cmd_list[j]);
+
+ kfree(fusion->cmd_list);
+ fusion->cmd_list = NULL;
+ goto fail_cmd_list;
+ }
+ }
+
+ /* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */
+ io_req_base = fusion->io_request_frames +
+ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+ io_req_base_phys = fusion->io_request_frames_phys +
+ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+
+ /*
+ * Add all the commands to command pool (fusion->cmd_pool)
+ */
+
+ /* SMID 0 is reserved. Set SMID/index from 1 */
+ for (i = 0; i < max_cmd; i++) {
+ cmd = fusion->cmd_list[i];
+ offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
+ memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
+ cmd->index = i + 1;
+ cmd->scmd = NULL;
+ cmd->sync_cmd_idx = (u32)ULONG_MAX; /* Set to Invalid */
+ cmd->instance = instance;
+ cmd->io_request =
+ (struct MPI2_RAID_SCSI_IO_REQUEST *)
+ (io_req_base + offset);
+ memset(cmd->io_request, 0,
+ sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
+ cmd->io_request_phys_addr = io_req_base_phys + offset;
+
+ list_add_tail(&cmd->list, &fusion->cmd_pool);
+ }
+
+ /*
+ * Create a frame pool and assign one frame to each cmd
+ */
+ if (megasas_create_frame_pool_fusion(instance)) {
+ printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n");
+ megasas_free_cmds_fusion(instance);
+ goto fail_req_desc;
+ }
+
+ return 0;
+
+fail_cmd_list:
+ pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames,
+ fusion->io_request_frames_phys);
+ pci_pool_destroy(fusion->io_request_frames_pool);
+fail_io_frames:
+ dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
+ fusion->reply_frames_desc,
+ fusion->reply_frames_desc_phys);
+ pci_pool_free(fusion->reply_frames_desc_pool,
+ fusion->reply_frames_desc,
+ fusion->reply_frames_desc_phys);
+ pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+fail_reply_desc:
+ dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
+ fusion->req_frames_desc,
+ fusion->req_frames_desc_phys);
+fail_req_desc:
+ return -ENOMEM;
+}
+
+/**
+ * wait_and_poll - Issues a polling command
+ * @instance: Adapter soft state
+ * @cmd: Command packet to be issued
+ *
+ * For polling, MFI requires the cmd_status to be set to 0xFF before posting.
+ */
+int
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd)
+{
+ int i;
+ struct megasas_header *frame_hdr = &cmd->frame->hdr;
+
+ u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
+
+ /*
+ * Wait for cmd_status to change
+ */
+ for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) {
+ rmb();
+ msleep(20);
+ }
+
+ if (frame_hdr->cmd_status == 0xff)
+ return -ETIME;
+
+ return 0;
+}
+
+/**
+ * megasas_ioc_init_fusion - Initializes the FW
+ * @instance: Adapter soft state
+ *
+ * Issues the IOC Init cmd
+ */
+int
+megasas_ioc_init_fusion(struct megasas_instance *instance)
+{
+ struct megasas_init_frame *init_frame;
+ struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
+ dma_addr_t ioc_init_handle;
+ u32 context;
+ struct megasas_cmd *cmd;
+ u8 ret;
+ struct fusion_context *fusion;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ int i;
+ struct megasas_header *frame_hdr;
+
+ fusion = instance->ctrl_context;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_ERR "Could not allocate cmd for INIT Frame\n");
+ ret = 1;
+ goto fail_get_cmd;
+ }
+
+ IOCInitMessage =
+ dma_alloc_coherent(&instance->pdev->dev,
+ sizeof(struct MPI2_IOC_INIT_REQUEST),
+ &ioc_init_handle, GFP_KERNEL);
+
+ if (!IOCInitMessage) {
+ printk(KERN_ERR "Could not allocate memory for "
+ "IOCInitMessage\n");
+ ret = 1;
+ goto fail_fw_init;
+ }
+
+ memset(IOCInitMessage, 0, sizeof(struct MPI2_IOC_INIT_REQUEST));
+
+ IOCInitMessage->Function = MPI2_FUNCTION_IOC_INIT;
+ IOCInitMessage->WhoInit = MPI2_WHOINIT_HOST_DRIVER;
+ IOCInitMessage->MsgVersion = MPI2_VERSION;
+ IOCInitMessage->HeaderVersion = MPI2_HEADER_VERSION;
+ IOCInitMessage->SystemRequestFrameSize =
+ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4;
+
+ IOCInitMessage->ReplyDescriptorPostQueueDepth = fusion->reply_q_depth;
+ IOCInitMessage->ReplyDescriptorPostQueueAddress =
+ fusion->reply_frames_desc_phys;
+ IOCInitMessage->SystemRequestFrameBaseAddress =
+ fusion->io_request_frames_phys;
+
+ init_frame = (struct megasas_init_frame *)cmd->frame;
+ memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
+
+ frame_hdr = &cmd->frame->hdr;
+ context = init_frame->context;
+ init_frame->context = context;
+
+ frame_hdr->cmd_status = 0xFF;
+ frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+
+ init_frame->cmd = MFI_CMD_INIT;
+ init_frame->cmd_status = 0xFF;
+
+ init_frame->queue_info_new_phys_addr_lo = ioc_init_handle;
+ init_frame->data_xfer_len = sizeof(struct MPI2_IOC_INIT_REQUEST);
+
+ req_desc =
+ (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)fusion->req_frames_desc;
+
+ req_desc->Words = cmd->frame_phys_addr;
+ req_desc->MFAIo.RequestFlags =
+ (MEGASAS_REQ_DESCRIPT_FLAGS_MFA <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+
+ /*
+ * disable the intr before firing the init frame
+ */
+ instance->instancet->disable_intr(instance->reg_set);
+
+ for (i = 0; i < (10 * 1000); i += 20) {
+ if (readl(&instance->reg_set->doorbell) & 1)
+ msleep(20);
+ else
+ break;
+ }
+
+ instance->instancet->fire_cmd(instance, req_desc->u.low,
+ req_desc->u.high, instance->reg_set);
+
+ wait_and_poll(instance, cmd);
+
+ frame_hdr = &cmd->frame->hdr;
+ if (frame_hdr->cmd_status != 0) {
+ ret = 1;
+ goto fail_fw_init;
+ }
+ printk(KERN_ERR "megasas:IOC Init cmd success\n");
+
+ ret = 0;
+
+fail_fw_init:
+ megasas_return_cmd(instance, cmd);
+ if (IOCInitMessage)
+ dma_free_coherent(&instance->pdev->dev,
+ sizeof(struct MPI2_IOC_INIT_REQUEST),
+ IOCInitMessage, ioc_init_handle);
+fail_get_cmd:
+ return ret;
+}
+
+/*
+ * megasas_return_cmd_for_smid - Returns a cmd_fusion for a SMID
+ * @instance: Adapter soft state
+ *
+ */
+void
+megasas_return_cmd_for_smid(struct megasas_instance *instance, u16 smid)
+{
+ struct fusion_context *fusion;
+ struct megasas_cmd_fusion *cmd;
+
+ fusion = instance->ctrl_context;
+ cmd = fusion->cmd_list[smid - 1];
+ megasas_return_cmd_fusion(instance, cmd);
+}
+
+/*
+ * megasas_get_ld_map_info - Returns FW's ld_map structure
+ * @instance: Adapter soft state
+ * @pend: Pend the command or not
+ * Issues an internal command (DCMD) to get the FW's controller PD
+ * list structure. This information is mainly used to find out SYSTEM
+ * supported by the FW.
+ */
+static int
+megasas_get_ld_map_info(struct megasas_instance *instance)
+{
+ int ret = 0;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ struct MR_FW_RAID_MAP_ALL *ci;
+ dma_addr_t ci_h = 0;
+ u32 size_map_info;
+ struct fusion_context *fusion;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas: Failed to get cmd for map info.\n");
+ return -ENOMEM;
+ }
+
+ fusion = instance->ctrl_context;
+
+ if (!fusion) {
+ megasas_return_cmd(instance, cmd);
+ return 1;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ size_map_info = sizeof(struct MR_FW_RAID_MAP) +
+ (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1));
+
+ ci = fusion->ld_map[(instance->map_id & 1)];
+ ci_h = fusion->ld_map_phys[(instance->map_id & 1)];
+
+ if (!ci) {
+ printk(KERN_DEBUG "Failed to alloc mem for ld_map_info\n");
+ megasas_return_cmd(instance, cmd);
+ return -ENOMEM;
+ }
+
+ memset(ci, 0, sizeof(*ci));
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_READ;
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = size_map_info;
+ dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
+ dcmd->sgl.sge32[0].phys_addr = ci_h;
+ dcmd->sgl.sge32[0].length = size_map_info;
+
+ if (!megasas_issue_polled(instance, cmd))
+ ret = 0;
+ else {
+ printk(KERN_ERR "megasas: Get LD Map Info Failed\n");
+ ret = -1;
+ }
+
+ megasas_return_cmd(instance, cmd);
+
+ return ret;
+}
+
+u8
+megasas_get_map_info(struct megasas_instance *instance)
+{
+ struct fusion_context *fusion = instance->ctrl_context;
+
+ fusion->fast_path_io = 0;
+ if (!megasas_get_ld_map_info(instance)) {
+ if (MR_ValidateMapInfo(fusion->ld_map[(instance->map_id & 1)],
+ fusion->load_balance_info)) {
+ fusion->fast_path_io = 1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * megasas_sync_map_info - Returns FW's ld_map structure
+ * @instance: Adapter soft state
+ *
+ * Issues an internal command (DCMD) to get the FW's controller PD
+ * list structure. This information is mainly used to find out SYSTEM
+ * supported by the FW.
+ */
+int
+megasas_sync_map_info(struct megasas_instance *instance)
+{
+ int ret = 0, i;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ u32 size_sync_info, num_lds;
+ struct fusion_context *fusion;
+ struct MR_LD_TARGET_SYNC *ci = NULL;
+ struct MR_FW_RAID_MAP_ALL *map;
+ struct MR_LD_RAID *raid;
+ struct MR_LD_TARGET_SYNC *ld_sync;
+ dma_addr_t ci_h = 0;
+ u32 size_map_info;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas: Failed to get cmd for sync"
+ "info.\n");
+ return -ENOMEM;
+ }
+
+ fusion = instance->ctrl_context;
+
+ if (!fusion) {
+ megasas_return_cmd(instance, cmd);
+ return 1;
+ }
+
+ map = fusion->ld_map[instance->map_id & 1];
+
+ num_lds = map->raidMap.ldCount;
+
+ dcmd = &cmd->frame->dcmd;
+
+ size_sync_info = sizeof(struct MR_LD_TARGET_SYNC) *num_lds;
+
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ ci = (struct MR_LD_TARGET_SYNC *)
+ fusion->ld_map[(instance->map_id - 1) & 1];
+ memset(ci, 0, sizeof(struct MR_FW_RAID_MAP_ALL));
+
+ ci_h = fusion->ld_map_phys[(instance->map_id - 1) & 1];
+
+ ld_sync = (struct MR_LD_TARGET_SYNC *)ci;
+
+ for (i = 0; i < num_lds; i++, ld_sync++) {
+ raid = MR_LdRaidGet(i, map);
+ ld_sync->targetId = MR_GetLDTgtId(i, map);
+ ld_sync->seqNum = raid->seqNum;
+ }
+
+ size_map_info = sizeof(struct MR_FW_RAID_MAP) +
+ (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1));
+
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_WRITE;
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = size_map_info;
+ dcmd->mbox.b[0] = num_lds;
+ dcmd->mbox.b[1] = MEGASAS_DCMD_MBOX_PEND_FLAG;
+ dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
+ dcmd->sgl.sge32[0].phys_addr = ci_h;
+ dcmd->sgl.sge32[0].length = size_map_info;
+
+ instance->map_update_cmd = cmd;
+
+ instance->instancet->issue_dcmd(instance, cmd);
+
+ return ret;
+}
+
+/**
+ * megasas_init_adapter_fusion - Initializes the FW
+ * @instance: Adapter soft state
+ *
+ * This is the main function for initializing firmware.
+ */
+u32
+megasas_init_adapter_fusion(struct megasas_instance *instance)
+{
+ struct megasas_register_set __iomem *reg_set;
+ struct fusion_context *fusion;
+ u32 max_cmd;
+ int i = 0;
+
+ fusion = instance->ctrl_context;
+
+ reg_set = instance->reg_set;
+
+ /*
+ * Get various operational parameters from status register
+ */
+ instance->max_fw_cmds =
+ instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+ instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
+
+ /*
+ * Reduce the max supported cmds by 1. This is to ensure that the
+ * reply_q_sz (1 more than the max cmd that driver may send)
+ * does not exceed max cmds that the FW can support
+ */
+ instance->max_fw_cmds = instance->max_fw_cmds-1;
+ /* Only internal cmds (DCMD) need to have MFI frames */
+ instance->max_mfi_cmds = MEGASAS_INT_CMDS;
+
+ max_cmd = instance->max_fw_cmds;
+
+ fusion->reply_q_depth = ((max_cmd + 1 + 15)/16)*16;
+
+ fusion->request_alloc_sz =
+ sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *max_cmd;
+ fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)
+ *(fusion->reply_q_depth);
+ fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE +
+ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE *
+ (max_cmd + 1)); /* Extra 1 for SMID 0 */
+
+ fusion->max_sge_in_main_msg =
+ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
+ offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16;
+
+ fusion->max_sge_in_chain =
+ MEGASAS_MAX_SZ_CHAIN_FRAME / sizeof(union MPI2_SGE_IO_UNION);
+
+ instance->max_num_sge = fusion->max_sge_in_main_msg +
+ fusion->max_sge_in_chain - 2;
+
+ /* Used for pass thru MFI frame (DCMD) */
+ fusion->chain_offset_mfi_pthru =
+ offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL)/16;
+
+ fusion->chain_offset_io_request =
+ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
+ sizeof(union MPI2_SGE_IO_UNION))/16;
+
+ fusion->last_reply_idx = 0;
+
+ /*
+ * Allocate memory for descriptors
+ * Create a pool of commands
+ */
+ if (megasas_alloc_cmds(instance))
+ goto fail_alloc_mfi_cmds;
+ if (megasas_alloc_cmds_fusion(instance))
+ goto fail_alloc_cmds;
+
+ if (megasas_ioc_init_fusion(instance))
+ goto fail_ioc_init;
+
+ instance->flag_ieee = 1;
+
+ fusion->map_sz = sizeof(struct MR_FW_RAID_MAP) +
+ (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1));
+
+ fusion->fast_path_io = 0;
+
+ for (i = 0; i < 2; i++) {
+ fusion->ld_map[i] = dma_alloc_coherent(&instance->pdev->dev,
+ fusion->map_sz,
+ &fusion->ld_map_phys[i],
+ GFP_KERNEL);
+ if (!fusion->ld_map[i]) {
+ printk(KERN_ERR "megasas: Could not allocate memory "
+ "for map info\n");
+ goto fail_map_info;
+ }
+ }
+
+ if (!megasas_get_map_info(instance))
+ megasas_sync_map_info(instance);
+
+ return 0;
+
+fail_alloc_cmds:
+fail_alloc_mfi_cmds:
+fail_map_info:
+ if (i == 1)
+ dma_free_coherent(&instance->pdev->dev, fusion->map_sz,
+ fusion->ld_map[0], fusion->ld_map_phys[0]);
+fail_ioc_init:
+ return 1;
+}
+
+/**
+ * megasas_fire_cmd_fusion - Sends command to the FW
+ * @frame_phys_addr : Physical address of cmd
+ * @frame_count : Number of frames for the command
+ * @regs : MFI register set
+ */
+void
+megasas_fire_cmd_fusion(struct megasas_instance *instance,
+ dma_addr_t req_desc_lo,
+ u32 req_desc_hi,
+ struct megasas_register_set __iomem *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&instance->hba_lock, flags);
+
+ writel(req_desc_lo,
+ &(regs)->inbound_low_queue_port);
+ writel(req_desc_hi, &(regs)->inbound_high_queue_port);
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
+}
+
+/**
+ * map_cmd_status - Maps FW cmd status to OS cmd status
+ * @cmd : Pointer to cmd
+ * @status : status of cmd returned by FW
+ * @ext_status : ext status of cmd returned by FW
+ */
+
+void
+map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status)
+{
+
+ switch (status) {
+
+ case MFI_STAT_OK:
+ cmd->scmd->result = DID_OK << 16;
+ break;
+
+ case MFI_STAT_SCSI_IO_FAILED:
+ case MFI_STAT_LD_INIT_IN_PROGRESS:
+ cmd->scmd->result = (DID_ERROR << 16) | ext_status;
+ break;
+
+ case MFI_STAT_SCSI_DONE_WITH_ERROR:
+
+ cmd->scmd->result = (DID_OK << 16) | ext_status;
+ if (ext_status == SAM_STAT_CHECK_CONDITION) {
+ memset(cmd->scmd->sense_buffer, 0,
+ SCSI_SENSE_BUFFERSIZE);
+ memcpy(cmd->scmd->sense_buffer, cmd->sense,
+ SCSI_SENSE_BUFFERSIZE);
+ cmd->scmd->result |= DRIVER_SENSE << 24;
+ }
+ break;
+
+ case MFI_STAT_LD_OFFLINE:
+ case MFI_STAT_DEVICE_NOT_FOUND:
+ cmd->scmd->result = DID_BAD_TARGET << 16;
+ break;
+
+ default:
+ printk(KERN_DEBUG "megasas: FW status %#x\n", status);
+ cmd->scmd->result = DID_ERROR << 16;
+ break;
+ }
+}
+
+/**
+ * megasas_make_sgl_fusion - Prepares 32-bit SGL
+ * @instance: Adapter soft state
+ * @scp: SCSI command from the mid-layer
+ * @sgl_ptr: SGL to be filled in
+ * @cmd: cmd we are working on
+ *
+ * If successful, this function returns the number of SG elements.
+ */
+static int
+megasas_make_sgl_fusion(struct megasas_instance *instance,
+ struct scsi_cmnd *scp,
+ struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr,
+ struct megasas_cmd_fusion *cmd)
+{
+ int i, sg_processed;
+ int sge_count, sge_idx;
+ struct scatterlist *os_sgl;
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
+ cmd->io_request->ChainOffset = 0;
+
+ sge_count = scsi_dma_map(scp);
+
+ BUG_ON(sge_count < 0);
+
+ if (sge_count > instance->max_num_sge || !sge_count)
+ return sge_count;
+
+ if (sge_count > fusion->max_sge_in_main_msg) {
+ /* One element to store the chain info */
+ sge_idx = fusion->max_sge_in_main_msg - 1;
+ } else
+ sge_idx = sge_count;
+
+ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+ sgl_ptr->Length = sg_dma_len(os_sgl);
+ sgl_ptr->Address = sg_dma_address(os_sgl);
+ sgl_ptr->Flags = 0;
+ sgl_ptr++;
+
+ sg_processed = i + 1;
+
+ if ((sg_processed == (fusion->max_sge_in_main_msg - 1)) &&
+ (sge_count > fusion->max_sge_in_main_msg)) {
+
+ struct MPI25_IEEE_SGE_CHAIN64 *sg_chain;
+ cmd->io_request->ChainOffset =
+ fusion->chain_offset_io_request;
+ sg_chain = sgl_ptr;
+ /* Prepare chain element */
+ sg_chain->NextChainOffset = 0;
+ sg_chain->Flags = (IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+ MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
+ sg_chain->Length = (sizeof(union MPI2_SGE_IO_UNION)
+ *(sge_count - sg_processed));
+ sg_chain->Address = cmd->sg_frame_phys_addr;
+
+ sgl_ptr =
+ (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame;
+ }
+ }
+
+ return sge_count;
+}
+
+/**
+ * megasas_set_pd_lba - Sets PD LBA
+ * @cdb: CDB
+ * @cdb_len: cdb length
+ * @start_blk: Start block of IO
+ *
+ * Used to set the PD LBA in CDB for FP IOs
+ */
+void
+megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
+ struct IO_REQUEST_INFO *io_info, struct scsi_cmnd *scp,
+ struct MR_FW_RAID_MAP_ALL *local_map_ptr, u32 ref_tag)
+{
+ struct MR_LD_RAID *raid;
+ u32 ld;
+ u64 start_blk = io_info->pdBlock;
+ u8 *cdb = io_request->CDB.CDB32;
+ u32 num_blocks = io_info->numBlocks;
+ u8 opcode, flagvals, groupnum, control;
+
+ /* Check if T10 PI (DIF) is enabled for this LD */
+ ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
+ raid = MR_LdRaidGet(ld, local_map_ptr);
+ if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) {
+ memset(cdb, 0, sizeof(io_request->CDB.CDB32));
+ cdb[0] = MEGASAS_SCSI_VARIABLE_LENGTH_CMD;
+ cdb[7] = MEGASAS_SCSI_ADDL_CDB_LEN;
+
+ if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_READ32;
+ else
+ cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_WRITE32;
+ cdb[10] = MEGASAS_RD_WR_PROTECT_CHECK_ALL;
+
+ /* LBA */
+ cdb[12] = (u8)((start_blk >> 56) & 0xff);
+ cdb[13] = (u8)((start_blk >> 48) & 0xff);
+ cdb[14] = (u8)((start_blk >> 40) & 0xff);
+ cdb[15] = (u8)((start_blk >> 32) & 0xff);
+ cdb[16] = (u8)((start_blk >> 24) & 0xff);
+ cdb[17] = (u8)((start_blk >> 16) & 0xff);
+ cdb[18] = (u8)((start_blk >> 8) & 0xff);
+ cdb[19] = (u8)(start_blk & 0xff);
+
+ /* Logical block reference tag */
+ io_request->CDB.EEDP32.PrimaryReferenceTag =
+ cpu_to_be32(ref_tag);
+ io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff;
+
+ io_request->DataLength = num_blocks * 512;
+ io_request->IoFlags = 32; /* Specify 32-byte cdb */
+
+ /* Transfer length */
+ cdb[28] = (u8)((num_blocks >> 24) & 0xff);
+ cdb[29] = (u8)((num_blocks >> 16) & 0xff);
+ cdb[30] = (u8)((num_blocks >> 8) & 0xff);
+ cdb[31] = (u8)(num_blocks & 0xff);
+
+ /* set SCSI IO EEDPFlags */
+ if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) {
+ io_request->EEDPFlags =
+ MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
+ } else {
+ io_request->EEDPFlags =
+ MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
+ }
+ io_request->Control |= (0x4 << 26);
+ io_request->EEDPBlockSize = MEGASAS_EEDPBLOCKSIZE;
+ } else {
+ /* Some drives don't support 16/12 byte CDB's, convert to 10 */
+ if (((cdb_len == 12) || (cdb_len == 16)) &&
+ (start_blk <= 0xffffffff)) {
+ if (cdb_len == 16) {
+ opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10;
+ flagvals = cdb[1];
+ groupnum = cdb[14];
+ control = cdb[15];
+ } else {
+ opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10;
+ flagvals = cdb[1];
+ groupnum = cdb[10];
+ control = cdb[11];
+ }
+
+ memset(cdb, 0, sizeof(io_request->CDB.CDB32));
+
+ cdb[0] = opcode;
+ cdb[1] = flagvals;
+ cdb[6] = groupnum;
+ cdb[9] = control;
+
+ /* Transfer length */
+ cdb[8] = (u8)(num_blocks & 0xff);
+ cdb[7] = (u8)((num_blocks >> 8) & 0xff);
+
+ cdb_len = 10;
+ }
+
+ /* Normal case, just load LBA here */
+ switch (cdb_len) {
+ case 6:
+ {
+ u8 val = cdb[1] & 0xE0;
+ cdb[3] = (u8)(start_blk & 0xff);
+ cdb[2] = (u8)((start_blk >> 8) & 0xff);
+ cdb[1] = val | ((u8)(start_blk >> 16) & 0x1f);
+ break;
+ }
+ case 10:
+ cdb[5] = (u8)(start_blk & 0xff);
+ cdb[4] = (u8)((start_blk >> 8) & 0xff);
+ cdb[3] = (u8)((start_blk >> 16) & 0xff);
+ cdb[2] = (u8)((start_blk >> 24) & 0xff);
+ break;
+ case 12:
+ cdb[5] = (u8)(start_blk & 0xff);
+ cdb[4] = (u8)((start_blk >> 8) & 0xff);
+ cdb[3] = (u8)((start_blk >> 16) & 0xff);
+ cdb[2] = (u8)((start_blk >> 24) & 0xff);
+ break;
+ case 16:
+ cdb[9] = (u8)(start_blk & 0xff);
+ cdb[8] = (u8)((start_blk >> 8) & 0xff);
+ cdb[7] = (u8)((start_blk >> 16) & 0xff);
+ cdb[6] = (u8)((start_blk >> 24) & 0xff);
+ cdb[5] = (u8)((start_blk >> 32) & 0xff);
+ cdb[4] = (u8)((start_blk >> 40) & 0xff);
+ cdb[3] = (u8)((start_blk >> 48) & 0xff);
+ cdb[2] = (u8)((start_blk >> 56) & 0xff);
+ break;
+ }
+ }
+}
+
+/**
+ * megasas_build_ldio_fusion - Prepares IOs to devices
+ * @instance: Adapter soft state
+ * @scp: SCSI command
+ * @cmd: Command to be prepared
+ *
+ * Prepares the io_request and chain elements (sg_frame) for IO
+ * The IO can be for PD (Fast Path) or LD
+ */
+void
+megasas_build_ldio_fusion(struct megasas_instance *instance,
+ struct scsi_cmnd *scp,
+ struct megasas_cmd_fusion *cmd)
+{
+ u8 fp_possible;
+ u32 start_lba_lo, start_lba_hi, device_id;
+ struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ struct IO_REQUEST_INFO io_info;
+ struct fusion_context *fusion;
+ struct MR_FW_RAID_MAP_ALL *local_map_ptr;
+
+ device_id = MEGASAS_DEV_INDEX(instance, scp);
+
+ fusion = instance->ctrl_context;
+
+ io_request = cmd->io_request;
+ io_request->RaidContext.VirtualDiskTgtId = device_id;
+ io_request->RaidContext.status = 0;
+ io_request->RaidContext.exStatus = 0;
+
+ req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
+
+ start_lba_lo = 0;
+ start_lba_hi = 0;
+ fp_possible = 0;
+
+ /*
+ * 6-byte READ(0x08) or WRITE(0x0A) cdb
+ */
+ if (scp->cmd_len == 6) {
+ io_request->DataLength = (u32) scp->cmnd[4];
+ start_lba_lo = ((u32) scp->cmnd[1] << 16) |
+ ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3];
+
+ start_lba_lo &= 0x1FFFFF;
+ }
+
+ /*
+ * 10-byte READ(0x28) or WRITE(0x2A) cdb
+ */
+ else if (scp->cmd_len == 10) {
+ io_request->DataLength = (u32) scp->cmnd[8] |
+ ((u32) scp->cmnd[7] << 8);
+ start_lba_lo = ((u32) scp->cmnd[2] << 24) |
+ ((u32) scp->cmnd[3] << 16) |
+ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+ }
+
+ /*
+ * 12-byte READ(0xA8) or WRITE(0xAA) cdb
+ */
+ else if (scp->cmd_len == 12) {
+ io_request->DataLength = ((u32) scp->cmnd[6] << 24) |
+ ((u32) scp->cmnd[7] << 16) |
+ ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
+ start_lba_lo = ((u32) scp->cmnd[2] << 24) |
+ ((u32) scp->cmnd[3] << 16) |
+ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+ }
+
+ /*
+ * 16-byte READ(0x88) or WRITE(0x8A) cdb
+ */
+ else if (scp->cmd_len == 16) {
+ io_request->DataLength = ((u32) scp->cmnd[10] << 24) |
+ ((u32) scp->cmnd[11] << 16) |
+ ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13];
+ start_lba_lo = ((u32) scp->cmnd[6] << 24) |
+ ((u32) scp->cmnd[7] << 16) |
+ ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
+
+ start_lba_hi = ((u32) scp->cmnd[2] << 24) |
+ ((u32) scp->cmnd[3] << 16) |
+ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+ }
+
+ memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO));
+ io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo;
+ io_info.numBlocks = io_request->DataLength;
+ io_info.ldTgtId = device_id;
+
+ if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ io_info.isRead = 1;
+
+ local_map_ptr = fusion->ld_map[(instance->map_id & 1)];
+
+ if ((MR_TargetIdToLdGet(device_id, local_map_ptr) >=
+ MAX_LOGICAL_DRIVES) || (!fusion->fast_path_io)) {
+ io_request->RaidContext.regLockFlags = 0;
+ fp_possible = 0;
+ } else {
+ if (MR_BuildRaidContext(&io_info, &io_request->RaidContext,
+ local_map_ptr))
+ fp_possible = io_info.fpOkForIo;
+ }
+
+ if (fp_possible) {
+ megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp,
+ local_map_ptr, start_lba_lo);
+ io_request->DataLength = scsi_bufflen(scp);
+ io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
+ << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ if ((fusion->load_balance_info[device_id].loadBalanceFlag) &&
+ (io_info.isRead)) {
+ io_info.devHandle =
+ get_updated_dev_handle(
+ &fusion->load_balance_info[device_id],
+ &io_info);
+ scp->SCp.Status |= MEGASAS_LOAD_BALANCE_FLAG;
+ } else
+ scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
+ cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle;
+ io_request->DevHandle = io_info.devHandle;
+ } else {
+ io_request->RaidContext.timeoutValue =
+ local_map_ptr->raidMap.fpPdIoTimeoutSec;
+ io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
+ io_request->DevHandle = device_id;
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
+ << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ } /* Not FP */
+}
+
+/**
+ * megasas_build_dcdb_fusion - Prepares IOs to devices
+ * @instance: Adapter soft state
+ * @scp: SCSI command
+ * @cmd: Command to be prepared
+ *
+ * Prepares the io_request frame for non-io cmds
+ */
+static void
+megasas_build_dcdb_fusion(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd,
+ struct megasas_cmd_fusion *cmd)
+{
+ u32 device_id;
+ struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
+ u16 pd_index = 0;
+ struct MR_FW_RAID_MAP_ALL *local_map_ptr;
+ struct fusion_context *fusion = instance->ctrl_context;
+
+ io_request = cmd->io_request;
+ device_id = MEGASAS_DEV_INDEX(instance, scmd);
+ pd_index = (scmd->device->channel * MEGASAS_MAX_DEV_PER_CHANNEL)
+ +scmd->device->id;
+ local_map_ptr = fusion->ld_map[(instance->map_id & 1)];
+
+ /* Check if this is a system PD I/O */
+ if ((instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) &&
+ (instance->pd_list[pd_index].driveType == TYPE_DISK)) {
+ io_request->Function = 0;
+ io_request->DevHandle =
+ local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ io_request->RaidContext.timeoutValue =
+ local_map_ptr->raidMap.fpPdIoTimeoutSec;
+ io_request->RaidContext.regLockFlags = 0;
+ io_request->RaidContext.regLockRowLBA = 0;
+ io_request->RaidContext.regLockLength = 0;
+ io_request->RaidContext.RAIDFlags =
+ MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD <<
+ MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ } else {
+ io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
+ io_request->DevHandle = device_id;
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ }
+ io_request->RaidContext.VirtualDiskTgtId = device_id;
+ io_request->LUN[0] = scmd->device->lun;
+ io_request->DataLength = scsi_bufflen(scmd);
+}
+
+/**
+ * megasas_build_io_fusion - Prepares IOs to devices
+ * @instance: Adapter soft state
+ * @scp: SCSI command
+ * @cmd: Command to be prepared
+ *
+ * Invokes helper functions to prepare request frames
+ * and sets flags appropriate for IO/Non-IO cmd
+ */
+int
+megasas_build_io_fusion(struct megasas_instance *instance,
+ struct scsi_cmnd *scp,
+ struct megasas_cmd_fusion *cmd)
+{
+ u32 device_id, sge_count;
+ struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request;
+
+ device_id = MEGASAS_DEV_INDEX(instance, scp);
+
+ /* Zero out some fields so they don't get reused */
+ io_request->LUN[0] = 0;
+ io_request->CDB.EEDP32.PrimaryReferenceTag = 0;
+ io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0;
+ io_request->EEDPFlags = 0;
+ io_request->Control = 0;
+ io_request->EEDPBlockSize = 0;
+ io_request->IoFlags = 0;
+ io_request->RaidContext.RAIDFlags = 0;
+
+ memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len);
+ /*
+ * Just the CDB length,rest of the Flags are zero
+ * This will be modified for FP in build_ldio_fusion
+ */
+ io_request->IoFlags = scp->cmd_len;
+
+ if (megasas_is_ldio(scp))
+ megasas_build_ldio_fusion(instance, scp, cmd);
+ else
+ megasas_build_dcdb_fusion(instance, scp, cmd);
+
+ /*
+ * Construct SGL
+ */
+
+ sge_count =
+ megasas_make_sgl_fusion(instance, scp,
+ (struct MPI25_IEEE_SGE_CHAIN64 *)
+ &io_request->SGL, cmd);
+
+ if (sge_count > instance->max_num_sge) {
+ printk(KERN_ERR "megasas: Error. sge_count (0x%x) exceeds "
+ "max (0x%x) allowed\n", sge_count,
+ instance->max_num_sge);
+ return 1;
+ }
+
+ io_request->RaidContext.numSGE = sge_count;
+
+ io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
+
+ if (scp->sc_data_direction == PCI_DMA_TODEVICE)
+ io_request->Control |= MPI2_SCSIIO_CONTROL_WRITE;
+ else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ io_request->Control |= MPI2_SCSIIO_CONTROL_READ;
+
+ io_request->SGLOffset0 =
+ offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL) / 4;
+
+ io_request->SenseBufferLowAddress = cmd->sense_phys_addr;
+ io_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
+
+ cmd->scmd = scp;
+ scp->SCp.ptr = (char *)cmd;
+
+ return 0;
+}
+
+union MEGASAS_REQUEST_DESCRIPTOR_UNION *
+megasas_get_request_descriptor(struct megasas_instance *instance, u16 index)
+{
+ u8 *p;
+ struct fusion_context *fusion;
+
+ if (index >= instance->max_fw_cmds) {
+ printk(KERN_ERR "megasas: Invalid SMID (0x%x)request for "
+ "descriptor\n", index);
+ return NULL;
+ }
+ fusion = instance->ctrl_context;
+ p = fusion->req_frames_desc
+ +sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *index;
+
+ return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p;
+}
+
+/**
+ * megasas_build_and_issue_cmd_fusion -Main routine for building and
+ * issuing non IOCTL cmd
+ * @instance: Adapter soft state
+ * @scmd: pointer to scsi cmd from OS
+ */
+static u32
+megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ struct megasas_cmd_fusion *cmd;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ u32 index;
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
+ cmd = megasas_get_cmd_fusion(instance);
+ if (!cmd)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ index = cmd->index;
+
+ req_desc = megasas_get_request_descriptor(instance, index-1);
+ if (!req_desc)
+ return 1;
+
+ req_desc->Words = 0;
+ cmd->request_desc = req_desc;
+ cmd->request_desc->Words = 0;
+
+ if (megasas_build_io_fusion(instance, scmd, cmd)) {
+ megasas_return_cmd_fusion(instance, cmd);
+ printk(KERN_ERR "megasas: Error building command.\n");
+ cmd->request_desc = NULL;
+ return 1;
+ }
+
+ req_desc = cmd->request_desc;
+ req_desc->SCSIIO.SMID = index;
+
+ if (cmd->io_request->ChainOffset != 0 &&
+ cmd->io_request->ChainOffset != 0xF)
+ printk(KERN_ERR "megasas: The chain offset value is not "
+ "correct : %x\n", cmd->io_request->ChainOffset);
+
+ /*
+ * Issue the command to the FW
+ */
+ atomic_inc(&instance->fw_outstanding);
+
+ instance->instancet->fire_cmd(instance,
+ req_desc->u.low, req_desc->u.high,
+ instance->reg_set);
+
+ return 0;
+}
+
+/**
+ * complete_cmd_fusion - Completes command
+ * @instance: Adapter soft state
+ * Completes all commands that is in reply descriptor queue
+ */
+int
+complete_cmd_fusion(struct megasas_instance *instance)
+{
+ union MPI2_REPLY_DESCRIPTORS_UNION *desc;
+ struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
+ struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req;
+ struct fusion_context *fusion;
+ struct megasas_cmd *cmd_mfi;
+ struct megasas_cmd_fusion *cmd_fusion;
+ u16 smid, num_completed;
+ u8 reply_descript_type, arm;
+ u32 status, extStatus, device_id;
+ union desc_value d_val;
+ struct LD_LOAD_BALANCE_INFO *lbinfo;
+
+ fusion = instance->ctrl_context;
+
+ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+ return IRQ_HANDLED;
+
+ desc = fusion->reply_frames_desc;
+ desc += fusion->last_reply_idx;
+
+ reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
+
+ d_val.word = desc->Words;
+
+ reply_descript_type = reply_desc->ReplyFlags &
+ MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+
+ if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+ return IRQ_NONE;
+
+ d_val.word = desc->Words;
+
+ num_completed = 0;
+
+ while ((d_val.u.low != UINT_MAX) && (d_val.u.high != UINT_MAX)) {
+ smid = reply_desc->SMID;
+
+ cmd_fusion = fusion->cmd_list[smid - 1];
+
+ scsi_io_req =
+ (struct MPI2_RAID_SCSI_IO_REQUEST *)
+ cmd_fusion->io_request;
+
+ if (cmd_fusion->scmd)
+ cmd_fusion->scmd->SCp.ptr = NULL;
+
+ status = scsi_io_req->RaidContext.status;
+ extStatus = scsi_io_req->RaidContext.exStatus;
+
+ switch (scsi_io_req->Function) {
+ case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/
+ /* Update load balancing info */
+ device_id = MEGASAS_DEV_INDEX(instance,
+ cmd_fusion->scmd);
+ lbinfo = &fusion->load_balance_info[device_id];
+ if (cmd_fusion->scmd->SCp.Status &
+ MEGASAS_LOAD_BALANCE_FLAG) {
+ arm = lbinfo->raid1DevHandle[0] ==
+ cmd_fusion->io_request->DevHandle ? 0 :
+ 1;
+ atomic_dec(&lbinfo->scsi_pending_cmds[arm]);
+ cmd_fusion->scmd->SCp.Status &=
+ ~MEGASAS_LOAD_BALANCE_FLAG;
+ }
+ if (reply_descript_type ==
+ MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) {
+ if (megasas_dbg_lvl == 5)
+ printk(KERN_ERR "\nmegasas: FAST Path "
+ "IO Success\n");
+ }
+ /* Fall thru and complete IO */
+ case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */
+ /* Map the FW Cmd Status */
+ map_cmd_status(cmd_fusion, status, extStatus);
+ scsi_dma_unmap(cmd_fusion->scmd);
+ cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
+ scsi_io_req->RaidContext.status = 0;
+ scsi_io_req->RaidContext.exStatus = 0;
+ megasas_return_cmd_fusion(instance, cmd_fusion);
+ atomic_dec(&instance->fw_outstanding);
+
+ break;
+ case MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */
+ cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
+ megasas_complete_cmd(instance, cmd_mfi, DID_OK);
+ cmd_fusion->flags = 0;
+ megasas_return_cmd_fusion(instance, cmd_fusion);
+
+ break;
+ }
+
+ fusion->last_reply_idx++;
+ if (fusion->last_reply_idx >= fusion->reply_q_depth)
+ fusion->last_reply_idx = 0;
+
+ desc->Words = ULLONG_MAX;
+ num_completed++;
+
+ /* Get the next reply descriptor */
+ if (!fusion->last_reply_idx)
+ desc = fusion->reply_frames_desc;
+ else
+ desc++;
+
+ reply_desc =
+ (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
+
+ d_val.word = desc->Words;
+
+ reply_descript_type = reply_desc->ReplyFlags &
+ MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+
+ if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+ break;
+ }
+
+ if (!num_completed)
+ return IRQ_NONE;
+
+ wmb();
+ writel(fusion->last_reply_idx,
+ &instance->reg_set->reply_post_host_index);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * megasas_complete_cmd_dpc_fusion - Completes command
+ * @instance: Adapter soft state
+ *
+ * Tasklet to complete cmds
+ */
+void
+megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
+{
+ struct megasas_instance *instance =
+ (struct megasas_instance *)instance_addr;
+ unsigned long flags;
+
+ /* If we have already declared adapter dead, donot complete cmds */
+ spin_lock_irqsave(&instance->hba_lock, flags);
+ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
+
+ spin_lock_irqsave(&instance->completion_lock, flags);
+ complete_cmd_fusion(instance);
+ spin_unlock_irqrestore(&instance->completion_lock, flags);
+}
+
+/**
+ * megasas_isr_fusion - isr entry point
+ */
+irqreturn_t megasas_isr_fusion(int irq, void *devp)
+{
+ struct megasas_instance *instance = (struct megasas_instance *)devp;
+ u32 mfiStatus, fw_state;
+
+ if (!instance->msi_flag) {
+ mfiStatus = instance->instancet->clear_intr(instance->reg_set);
+ if (!mfiStatus)
+ return IRQ_NONE;
+ }
+
+ /* If we are resetting, bail */
+ if (test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags))
+ return IRQ_HANDLED;
+
+ if (!complete_cmd_fusion(instance)) {
+ /* If we didn't complete any commands, check for FW fault */
+ fw_state = instance->instancet->read_fw_status_reg(
+ instance->reg_set) & MFI_STATE_MASK;
+ if (fw_state == MFI_STATE_FAULT)
+ schedule_work(&instance->work_init);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * build_mpt_mfi_pass_thru - builds a cmd fo MFI Pass thru
+ * @instance: Adapter soft state
+ * mfi_cmd: megasas_cmd pointer
+ *
+ */
+u8
+build_mpt_mfi_pass_thru(struct megasas_instance *instance,
+ struct megasas_cmd *mfi_cmd)
+{
+ struct MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
+ struct MPI2_RAID_SCSI_IO_REQUEST *io_req;
+ struct megasas_cmd_fusion *cmd;
+ struct fusion_context *fusion;
+ struct megasas_header *frame_hdr = &mfi_cmd->frame->hdr;
+
+ cmd = megasas_get_cmd_fusion(instance);
+ if (!cmd)
+ return 1;
+
+ /* Save the smid. To be used for returning the cmd */
+ mfi_cmd->context.smid = cmd->index;
+
+ cmd->sync_cmd_idx = mfi_cmd->index;
+
+ /*
+ * For cmds where the flag is set, store the flag and check
+ * on completion. For cmds with this flag, don't call
+ * megasas_complete_cmd
+ */
+
+ if (frame_hdr->flags & MFI_FRAME_DONT_POST_IN_REPLY_QUEUE)
+ cmd->flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+
+ fusion = instance->ctrl_context;
+ io_req = cmd->io_request;
+ mpi25_ieee_chain =
+ (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
+
+ io_req->Function = MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
+ io_req->SGLOffset0 = offsetof(struct MPI2_RAID_SCSI_IO_REQUEST,
+ SGL) / 4;
+ io_req->ChainOffset = fusion->chain_offset_mfi_pthru;
+
+ mpi25_ieee_chain->Address = mfi_cmd->frame_phys_addr;
+
+ mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+ MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
+
+ mpi25_ieee_chain->Length = MEGASAS_MAX_SZ_CHAIN_FRAME;
+
+ return 0;
+}
+
+/**
+ * build_mpt_cmd - Calls helper function to build a cmd MFI Pass thru cmd
+ * @instance: Adapter soft state
+ * @cmd: mfi cmd to build
+ *
+ */
+union MEGASAS_REQUEST_DESCRIPTOR_UNION *
+build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+{
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ u16 index;
+
+ if (build_mpt_mfi_pass_thru(instance, cmd)) {
+ printk(KERN_ERR "Couldn't build MFI pass thru cmd\n");
+ return NULL;
+ }
+
+ index = cmd->context.smid;
+
+ req_desc = megasas_get_request_descriptor(instance, index - 1);
+
+ if (!req_desc)
+ return NULL;
+
+ req_desc->Words = 0;
+ req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+
+ req_desc->SCSIIO.SMID = index;
+
+ return req_desc;
+}
+
+/**
+ * megasas_issue_dcmd_fusion - Issues a MFI Pass thru cmd
+ * @instance: Adapter soft state
+ * @cmd: mfi cmd pointer
+ *
+ */
+void
+megasas_issue_dcmd_fusion(struct megasas_instance *instance,
+ struct megasas_cmd *cmd)
+{
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ union desc_value d_val;
+
+ req_desc = build_mpt_cmd(instance, cmd);
+ if (!req_desc) {
+ printk(KERN_ERR "Couldn't issue MFI pass thru cmd\n");
+ return;
+ }
+ d_val.word = req_desc->Words;
+
+ instance->instancet->fire_cmd(instance, req_desc->u.low,
+ req_desc->u.high, instance->reg_set);
+}
+
+/**
+ * megasas_release_fusion - Reverses the FW initialization
+ * @intance: Adapter soft state
+ */
+void
+megasas_release_fusion(struct megasas_instance *instance)
+{
+ megasas_free_cmds(instance);
+ megasas_free_cmds_fusion(instance);
+
+ iounmap(instance->reg_set);
+
+ pci_release_selected_regions(instance->pdev, instance->bar);
+}
+
+/**
+ * megasas_read_fw_status_reg_fusion - returns the current FW status value
+ * @regs: MFI register set
+ */
+static u32
+megasas_read_fw_status_reg_fusion(struct megasas_register_set __iomem *regs)
+{
+ return readl(&(regs)->outbound_scratch_pad);
+}
+
+/**
+ * megasas_adp_reset_fusion - For controller reset
+ * @regs: MFI register set
+ */
+static int
+megasas_adp_reset_fusion(struct megasas_instance *instance,
+ struct megasas_register_set __iomem *regs)
+{
+ return 0;
+}
+
+/**
+ * megasas_check_reset_fusion - For controller reset check
+ * @regs: MFI register set
+ */
+static int
+megasas_check_reset_fusion(struct megasas_instance *instance,
+ struct megasas_register_set __iomem *regs)
+{
+ return 0;
+}
+
+/* This function waits for outstanding commands on fusion to complete */
+int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
+{
+ int i, outstanding, retval = 0;
+ u32 fw_state, wait_time = MEGASAS_RESET_WAIT_TIME;
+
+ for (i = 0; i < wait_time; i++) {
+ /* Check if firmware is in fault state */
+ fw_state = instance->instancet->read_fw_status_reg(
+ instance->reg_set) & MFI_STATE_MASK;
+ if (fw_state == MFI_STATE_FAULT) {
+ printk(KERN_WARNING "megasas: Found FW in FAULT state,"
+ " will reset adapter.\n");
+ retval = 1;
+ goto out;
+ }
+
+ outstanding = atomic_read(&instance->fw_outstanding);
+ if (!outstanding)
+ goto out;
+
+ if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+ printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
+ "commands to complete\n", i, outstanding);
+ megasas_complete_cmd_dpc_fusion(
+ (unsigned long)instance);
+ }
+ msleep(1000);
+ }
+
+ if (atomic_read(&instance->fw_outstanding)) {
+ printk("megaraid_sas: pending commands remain after waiting, "
+ "will reset adapter.\n");
+ retval = 1;
+ }
+out:
+ return retval;
+}
+
+void megasas_reset_reply_desc(struct megasas_instance *instance)
+{
+ int i;
+ struct fusion_context *fusion;
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+
+ fusion = instance->ctrl_context;
+ fusion->last_reply_idx = 0;
+ reply_desc = fusion->reply_frames_desc;
+ for (i = 0 ; i < fusion->reply_q_depth; i++, reply_desc++)
+ reply_desc->Words = ULLONG_MAX;
+}
+
+/* Core fusion reset function */
+int megasas_reset_fusion(struct Scsi_Host *shost)
+{
+ int retval = SUCCESS, i, j, retry = 0;
+ struct megasas_instance *instance;
+ struct megasas_cmd_fusion *cmd_fusion;
+ struct fusion_context *fusion;
+ struct megasas_cmd *cmd_mfi;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ u32 host_diag, abs_state;
+
+ instance = (struct megasas_instance *)shost->hostdata;
+ fusion = instance->ctrl_context;
+
+ mutex_lock(&instance->reset_mutex);
+ set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
+ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ instance->instancet->disable_intr(instance->reg_set);
+ msleep(1000);
+
+ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
+ "returning FAILED.\n");
+ retval = FAILED;
+ goto out;
+ }
+
+ /* First try waiting for commands to complete */
+ if (megasas_wait_for_outstanding_fusion(instance)) {
+ printk(KERN_WARNING "megaraid_sas: resetting fusion "
+ "adapter.\n");
+ /* Now return commands back to the OS */
+ for (i = 0 ; i < instance->max_fw_cmds; i++) {
+ cmd_fusion = fusion->cmd_list[i];
+ if (cmd_fusion->scmd) {
+ scsi_dma_unmap(cmd_fusion->scmd);
+ cmd_fusion->scmd->result = (DID_RESET << 16);
+ cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
+ megasas_return_cmd_fusion(instance, cmd_fusion);
+ atomic_dec(&instance->fw_outstanding);
+ }
+ }
+
+ if (instance->disableOnlineCtrlReset == 1) {
+ /* Reset not supported, kill adapter */
+ printk(KERN_WARNING "megaraid_sas: Reset not supported"
+ ", killing adapter.\n");
+ megaraid_sas_kill_hba(instance);
+ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+ retval = FAILED;
+ goto out;
+ }
+
+ /* Now try to reset the chip */
+ for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
+ writel(MPI2_WRSEQ_FLUSH_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_1ST_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_2ND_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_3RD_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_4TH_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_5TH_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_6TH_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+
+ /* Check that the diag write enable (DRWE) bit is on */
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
+ msleep(100);
+ host_diag =
+ readl(&instance->reg_set->fusion_host_diag);
+ if (retry++ == 100) {
+ printk(KERN_WARNING "megaraid_sas: "
+ "Host diag unlock failed!\n");
+ break;
+ }
+ }
+ if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
+ continue;
+
+ /* Send chip reset command */
+ writel(host_diag | HOST_DIAG_RESET_ADAPTER,
+ &instance->reg_set->fusion_host_diag);
+ msleep(3000);
+
+ /* Make sure reset adapter bit is cleared */
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ retry = 0;
+ while (host_diag & HOST_DIAG_RESET_ADAPTER) {
+ msleep(100);
+ host_diag =
+ readl(&instance->reg_set->fusion_host_diag);
+ if (retry++ == 1000) {
+ printk(KERN_WARNING "megaraid_sas: "
+ "Diag reset adapter never "
+ "cleared!\n");
+ break;
+ }
+ }
+ if (host_diag & HOST_DIAG_RESET_ADAPTER)
+ continue;
+
+ abs_state =
+ instance->instancet->read_fw_status_reg(
+ instance->reg_set);
+ retry = 0;
+
+ while ((abs_state <= MFI_STATE_FW_INIT) &&
+ (retry++ < 1000)) {
+ msleep(100);
+ abs_state =
+ instance->instancet->read_fw_status_reg(
+ instance->reg_set);
+ }
+ if (abs_state <= MFI_STATE_FW_INIT) {
+ printk(KERN_WARNING "megaraid_sas: firmware "
+ "state < MFI_STATE_FW_INIT, state = "
+ "0x%x\n", abs_state);
+ continue;
+ }
+
+ /* Wait for FW to become ready */
+ if (megasas_transition_to_ready(instance)) {
+ printk(KERN_WARNING "megaraid_sas: Failed to "
+ "transition controller to ready.\n");
+ continue;
+ }
+
+ megasas_reset_reply_desc(instance);
+ if (megasas_ioc_init_fusion(instance)) {
+ printk(KERN_WARNING "megaraid_sas: "
+ "megasas_ioc_init_fusion() failed!\n");
+ continue;
+ }
+
+ instance->instancet->enable_intr(instance->reg_set);
+ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+
+ /* Re-fire management commands */
+ for (j = 0 ; j < instance->max_fw_cmds; j++) {
+ cmd_fusion = fusion->cmd_list[j];
+ if (cmd_fusion->sync_cmd_idx !=
+ (u32)ULONG_MAX) {
+ cmd_mfi =
+ instance->
+ cmd_list[cmd_fusion->sync_cmd_idx];
+ if (cmd_mfi->frame->dcmd.opcode ==
+ MR_DCMD_LD_MAP_GET_INFO) {
+ megasas_return_cmd(instance,
+ cmd_mfi);
+ megasas_return_cmd_fusion(
+ instance, cmd_fusion);
+ } else {
+ req_desc =
+ megasas_get_request_descriptor(
+ instance,
+ cmd_mfi->context.smid
+ -1);
+ if (!req_desc)
+ printk(KERN_WARNING
+ "req_desc NULL"
+ "\n");
+ else {
+ instance->instancet->
+ fire_cmd(instance,
+ req_desc->
+ u.low,
+ req_desc->
+ u.high,
+ instance->
+ reg_set);
+ }
+ }
+ }
+ }
+
+ /* Reset load balance info */
+ memset(fusion->load_balance_info, 0,
+ sizeof(struct LD_LOAD_BALANCE_INFO)
+ *MAX_LOGICAL_DRIVES);
+
+ if (!megasas_get_map_info(instance))
+ megasas_sync_map_info(instance);
+
+ /* Adapter reset completed successfully */
+ printk(KERN_WARNING "megaraid_sas: Reset "
+ "successful.\n");
+ retval = SUCCESS;
+ goto out;
+ }
+ /* Reset failed, kill the adapter */
+ printk(KERN_WARNING "megaraid_sas: Reset failed, killing "
+ "adapter.\n");
+ megaraid_sas_kill_hba(instance);
+ retval = FAILED;
+ } else {
+ instance->instancet->enable_intr(instance->reg_set);
+ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+ }
+out:
+ clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
+ mutex_unlock(&instance->reset_mutex);
+ return retval;
+}
+
+/* Fusion OCR work queue */
+void megasas_fusion_ocr_wq(struct work_struct *work)
+{
+ struct megasas_instance *instance =
+ container_of(work, struct megasas_instance, work_init);
+
+ megasas_reset_fusion(instance->host);
+}
+
+struct megasas_instance_template megasas_instance_template_fusion = {
+ .fire_cmd = megasas_fire_cmd_fusion,
+ .enable_intr = megasas_enable_intr_fusion,
+ .disable_intr = megasas_disable_intr_fusion,
+ .clear_intr = megasas_clear_intr_fusion,
+ .read_fw_status_reg = megasas_read_fw_status_reg_fusion,
+ .adp_reset = megasas_adp_reset_fusion,
+ .check_reset = megasas_check_reset_fusion,
+ .service_isr = megasas_isr_fusion,
+ .tasklet = megasas_complete_cmd_dpc_fusion,
+ .init_adapter = megasas_init_adapter_fusion,
+ .build_and_issue_cmd = megasas_build_and_issue_cmd_fusion,
+ .issue_dcmd = megasas_issue_dcmd_fusion,
+};
--- /dev/null
+/*
+ * Linux MegaRAID driver for SAS based RAID controllers
+ *
+ * Copyright (c) 2009-2011 LSI Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * FILE: megaraid_sas_fusion.h
+ *
+ * Authors: LSI Corporation
+ * Manoj Jose
+ * Sumant Patro
+ *
+ * Send feedback to: <megaraidlinux@lsi.com>
+ *
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: Linuxraid
+ */
+
+#ifndef _MEGARAID_SAS_FUSION_H_
+#define _MEGARAID_SAS_FUSION_H_
+
+/* Fusion defines */
+#define MEGASAS_MAX_SZ_CHAIN_FRAME 1024
+#define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000009)
+#define MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 256
+#define MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0
+#define MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST 0xF1
+#define MEGASAS_LOAD_BALANCE_FLAG 0x1
+#define MEGASAS_DCMD_MBOX_PEND_FLAG 0x1
+#define HOST_DIAG_WRITE_ENABLE 0x80
+#define HOST_DIAG_RESET_ADAPTER 0x4
+#define MEGASAS_FUSION_MAX_RESET_TRIES 3
+
+/* T10 PI defines */
+#define MR_PROT_INFO_TYPE_CONTROLLER 0x8
+#define MEGASAS_SCSI_VARIABLE_LENGTH_CMD 0x7f
+#define MEGASAS_SCSI_SERVICE_ACTION_READ32 0x9
+#define MEGASAS_SCSI_SERVICE_ACTION_WRITE32 0xB
+#define MEGASAS_SCSI_ADDL_CDB_LEN 0x18
+#define MEGASAS_RD_WR_PROTECT_CHECK_ALL 0x20
+#define MEGASAS_RD_WR_PROTECT_CHECK_NONE 0x60
+#define MEGASAS_EEDPBLOCKSIZE 512
+
+/*
+ * Raid context flags
+ */
+
+#define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT 0x4
+#define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_MASK 0x30
+enum MR_RAID_FLAGS_IO_SUB_TYPE {
+ MR_RAID_FLAGS_IO_SUB_TYPE_NONE = 0,
+ MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD = 1,
+};
+
+/*
+ * Request descriptor types
+ */
+#define MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO 0x7
+#define MEGASAS_REQ_DESCRIPT_FLAGS_MFA 0x1
+
+#define MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT 1
+
+#define MEGASAS_FP_CMD_LEN 16
+#define MEGASAS_FUSION_IN_RESET 0
+
+/*
+ * Raid Context structure which describes MegaRAID specific IO Paramenters
+ * This resides at offset 0x60 where the SGL normally starts in MPT IO Frames
+ */
+
+struct RAID_CONTEXT {
+ u16 resvd0;
+ u16 timeoutValue;
+ u8 regLockFlags;
+ u8 resvd1;
+ u16 VirtualDiskTgtId;
+ u64 regLockRowLBA;
+ u32 regLockLength;
+ u16 nextLMId;
+ u8 exStatus;
+ u8 status;
+ u8 RAIDFlags;
+ u8 numSGE;
+ u16 configSeqNum;
+ u8 spanArm;
+ u8 resvd2[3];
+};
+
+#define RAID_CTX_SPANARM_ARM_SHIFT (0)
+#define RAID_CTX_SPANARM_ARM_MASK (0x1f)
+
+#define RAID_CTX_SPANARM_SPAN_SHIFT (5)
+#define RAID_CTX_SPANARM_SPAN_MASK (0xE0)
+
+/*
+ * define region lock types
+ */
+enum REGION_TYPE {
+ REGION_TYPE_UNUSED = 0,
+ REGION_TYPE_SHARED_READ = 1,
+ REGION_TYPE_SHARED_WRITE = 2,
+ REGION_TYPE_EXCLUSIVE = 3,
+};
+
+/* MPI2 defines */
+#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */
+#define MPI2_WHOINIT_HOST_DRIVER (0x04)
+#define MPI2_VERSION_MAJOR (0x02)
+#define MPI2_VERSION_MINOR (0x00)
+#define MPI2_VERSION_MAJOR_MASK (0xFF00)
+#define MPI2_VERSION_MAJOR_SHIFT (8)
+#define MPI2_VERSION_MINOR_MASK (0x00FF)
+#define MPI2_VERSION_MINOR_SHIFT (0)
+#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
+ MPI2_VERSION_MINOR)
+#define MPI2_HEADER_VERSION_UNIT (0x10)
+#define MPI2_HEADER_VERSION_DEV (0x00)
+#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
+#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
+#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF)
+#define MPI2_HEADER_VERSION_DEV_SHIFT (0)
+#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | \
+ MPI2_HEADER_VERSION_DEV)
+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03)
+#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100)
+#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004)
+#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */
+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
+#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02)
+#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000)
+#define MPI2_SCSIIO_CONTROL_READ (0x02000000)
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E)
+#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
+#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00)
+#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F)
+#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0)
+#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004)
+#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF)
+#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4)
+#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB)
+#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2)
+#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7)
+#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD)
+
+struct MPI25_IEEE_SGE_CHAIN64 {
+ u64 Address;
+ u32 Length;
+ u16 Reserved1;
+ u8 NextChainOffset;
+ u8 Flags;
+};
+
+struct MPI2_SGE_SIMPLE_UNION {
+ u32 FlagsLength;
+ union {
+ u32 Address32;
+ u64 Address64;
+ } u;
+};
+
+struct MPI2_SCSI_IO_CDB_EEDP32 {
+ u8 CDB[20]; /* 0x00 */
+ u32 PrimaryReferenceTag; /* 0x14 */
+ u16 PrimaryApplicationTag; /* 0x18 */
+ u16 PrimaryApplicationTagMask; /* 0x1A */
+ u32 TransferLength; /* 0x1C */
+};
+
+struct MPI2_SGE_CHAIN_UNION {
+ u16 Length;
+ u8 NextChainOffset;
+ u8 Flags;
+ union {
+ u32 Address32;
+ u64 Address64;
+ } u;
+};
+
+struct MPI2_IEEE_SGE_SIMPLE32 {
+ u32 Address;
+ u32 FlagsLength;
+};
+
+struct MPI2_IEEE_SGE_CHAIN32 {
+ u32 Address;
+ u32 FlagsLength;
+};
+
+struct MPI2_IEEE_SGE_SIMPLE64 {
+ u64 Address;
+ u32 Length;
+ u16 Reserved1;
+ u8 Reserved2;
+ u8 Flags;
+};
+
+struct MPI2_IEEE_SGE_CHAIN64 {
+ u64 Address;
+ u32 Length;
+ u16 Reserved1;
+ u8 Reserved2;
+ u8 Flags;
+};
+
+union MPI2_IEEE_SGE_SIMPLE_UNION {
+ struct MPI2_IEEE_SGE_SIMPLE32 Simple32;
+ struct MPI2_IEEE_SGE_SIMPLE64 Simple64;
+};
+
+union MPI2_IEEE_SGE_CHAIN_UNION {
+ struct MPI2_IEEE_SGE_CHAIN32 Chain32;
+ struct MPI2_IEEE_SGE_CHAIN64 Chain64;
+};
+
+union MPI2_SGE_IO_UNION {
+ struct MPI2_SGE_SIMPLE_UNION MpiSimple;
+ struct MPI2_SGE_CHAIN_UNION MpiChain;
+ union MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple;
+ union MPI2_IEEE_SGE_CHAIN_UNION IeeeChain;
+};
+
+union MPI2_SCSI_IO_CDB_UNION {
+ u8 CDB32[32];
+ struct MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
+ struct MPI2_SGE_SIMPLE_UNION SGE;
+};
+
+/*
+ * RAID SCSI IO Request Message
+ * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST
+ */
+struct MPI2_RAID_SCSI_IO_REQUEST {
+ u16 DevHandle; /* 0x00 */
+ u8 ChainOffset; /* 0x02 */
+ u8 Function; /* 0x03 */
+ u16 Reserved1; /* 0x04 */
+ u8 Reserved2; /* 0x06 */
+ u8 MsgFlags; /* 0x07 */
+ u8 VP_ID; /* 0x08 */
+ u8 VF_ID; /* 0x09 */
+ u16 Reserved3; /* 0x0A */
+ u32 SenseBufferLowAddress; /* 0x0C */
+ u16 SGLFlags; /* 0x10 */
+ u8 SenseBufferLength; /* 0x12 */
+ u8 Reserved4; /* 0x13 */
+ u8 SGLOffset0; /* 0x14 */
+ u8 SGLOffset1; /* 0x15 */
+ u8 SGLOffset2; /* 0x16 */
+ u8 SGLOffset3; /* 0x17 */
+ u32 SkipCount; /* 0x18 */
+ u32 DataLength; /* 0x1C */
+ u32 BidirectionalDataLength; /* 0x20 */
+ u16 IoFlags; /* 0x24 */
+ u16 EEDPFlags; /* 0x26 */
+ u32 EEDPBlockSize; /* 0x28 */
+ u32 SecondaryReferenceTag; /* 0x2C */
+ u16 SecondaryApplicationTag; /* 0x30 */
+ u16 ApplicationTagTranslationMask; /* 0x32 */
+ u8 LUN[8]; /* 0x34 */
+ u32 Control; /* 0x3C */
+ union MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
+ struct RAID_CONTEXT RaidContext; /* 0x60 */
+ union MPI2_SGE_IO_UNION SGL; /* 0x80 */
+};
+
+/*
+ * MPT RAID MFA IO Descriptor.
+ */
+struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR {
+ u32 RequestFlags:8;
+ u32 MessageAddress1:24; /* bits 31:8*/
+ u32 MessageAddress2; /* bits 61:32 */
+};
+
+/* Default Request Descriptor */
+struct MPI2_DEFAULT_REQUEST_DESCRIPTOR {
+ u8 RequestFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 LMID; /* 0x04 */
+ u16 DescriptorTypeDependent; /* 0x06 */
+};
+
+/* High Priority Request Descriptor */
+struct MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR {
+ u8 RequestFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 LMID; /* 0x04 */
+ u16 Reserved1; /* 0x06 */
+};
+
+/* SCSI IO Request Descriptor */
+struct MPI2_SCSI_IO_REQUEST_DESCRIPTOR {
+ u8 RequestFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 LMID; /* 0x04 */
+ u16 DevHandle; /* 0x06 */
+};
+
+/* SCSI Target Request Descriptor */
+struct MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR {
+ u8 RequestFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 LMID; /* 0x04 */
+ u16 IoIndex; /* 0x06 */
+};
+
+/* RAID Accelerator Request Descriptor */
+struct MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR {
+ u8 RequestFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 LMID; /* 0x04 */
+ u16 Reserved; /* 0x06 */
+};
+
+/* union of Request Descriptors */
+union MEGASAS_REQUEST_DESCRIPTOR_UNION {
+ struct MPI2_DEFAULT_REQUEST_DESCRIPTOR Default;
+ struct MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority;
+ struct MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO;
+ struct MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget;
+ struct MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator;
+ struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR MFAIo;
+ union {
+ struct {
+ u32 low;
+ u32 high;
+ } u;
+ u64 Words;
+ };
+};
+
+/* Default Reply Descriptor */
+struct MPI2_DEFAULT_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 DescriptorTypeDependent1; /* 0x02 */
+ u32 DescriptorTypeDependent2; /* 0x04 */
+};
+
+/* Address Reply Descriptor */
+struct MPI2_ADDRESS_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u32 ReplyFrameAddress; /* 0x04 */
+};
+
+/* SCSI IO Success Reply Descriptor */
+struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 TaskTag; /* 0x04 */
+ u16 Reserved1; /* 0x06 */
+};
+
+/* TargetAssist Success Reply Descriptor */
+struct MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u8 SequenceNumber; /* 0x04 */
+ u8 Reserved1; /* 0x05 */
+ u16 IoIndex; /* 0x06 */
+};
+
+/* Target Command Buffer Reply Descriptor */
+struct MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u8 VP_ID; /* 0x02 */
+ u8 Flags; /* 0x03 */
+ u16 InitiatorDevHandle; /* 0x04 */
+ u16 IoIndex; /* 0x06 */
+};
+
+/* RAID Accelerator Success Reply Descriptor */
+struct MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u32 Reserved; /* 0x04 */
+};
+
+/* union of Reply Descriptors */
+union MPI2_REPLY_DESCRIPTORS_UNION {
+ struct MPI2_DEFAULT_REPLY_DESCRIPTOR Default;
+ struct MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply;
+ struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess;
+ struct MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess;
+ struct MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
+ struct MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR
+ RAIDAcceleratorSuccess;
+ u64 Words;
+};
+
+/* IOCInit Request message */
+struct MPI2_IOC_INIT_REQUEST {
+ u8 WhoInit; /* 0x00 */
+ u8 Reserved1; /* 0x01 */
+ u8 ChainOffset; /* 0x02 */
+ u8 Function; /* 0x03 */
+ u16 Reserved2; /* 0x04 */
+ u8 Reserved3; /* 0x06 */
+ u8 MsgFlags; /* 0x07 */
+ u8 VP_ID; /* 0x08 */
+ u8 VF_ID; /* 0x09 */
+ u16 Reserved4; /* 0x0A */
+ u16 MsgVersion; /* 0x0C */
+ u16 HeaderVersion; /* 0x0E */
+ u32 Reserved5; /* 0x10 */
+ u16 Reserved6; /* 0x14 */
+ u8 Reserved7; /* 0x16 */
+ u8 HostMSIxVectors; /* 0x17 */
+ u16 Reserved8; /* 0x18 */
+ u16 SystemRequestFrameSize; /* 0x1A */
+ u16 ReplyDescriptorPostQueueDepth; /* 0x1C */
+ u16 ReplyFreeQueueDepth; /* 0x1E */
+ u32 SenseBufferAddressHigh; /* 0x20 */
+ u32 SystemReplyAddressHigh; /* 0x24 */
+ u64 SystemRequestFrameBaseAddress; /* 0x28 */
+ u64 ReplyDescriptorPostQueueAddress;/* 0x30 */
+ u64 ReplyFreeQueueAddress; /* 0x38 */
+ u64 TimeStamp; /* 0x40 */
+};
+
+/* mrpriv defines */
+#define MR_PD_INVALID 0xFFFF
+#define MAX_SPAN_DEPTH 8
+#define MAX_RAIDMAP_SPAN_DEPTH (MAX_SPAN_DEPTH)
+#define MAX_ROW_SIZE 32
+#define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE)
+#define MAX_LOGICAL_DRIVES 64
+#define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES)
+#define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES)
+#define MAX_ARRAYS 128
+#define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS)
+#define MAX_PHYSICAL_DEVICES 256
+#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES)
+#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101
+
+struct MR_DEV_HANDLE_INFO {
+ u16 curDevHdl;
+ u8 validHandles;
+ u8 reserved;
+ u16 devHandle[2];
+};
+
+struct MR_ARRAY_INFO {
+ u16 pd[MAX_RAIDMAP_ROW_SIZE];
+};
+
+struct MR_QUAD_ELEMENT {
+ u64 logStart;
+ u64 logEnd;
+ u64 offsetInSpan;
+ u32 diff;
+ u32 reserved1;
+};
+
+struct MR_SPAN_INFO {
+ u32 noElements;
+ u32 reserved1;
+ struct MR_QUAD_ELEMENT quad[MAX_RAIDMAP_SPAN_DEPTH];
+};
+
+struct MR_LD_SPAN {
+ u64 startBlk;
+ u64 numBlks;
+ u16 arrayRef;
+ u8 reserved[6];
+};
+
+struct MR_SPAN_BLOCK_INFO {
+ u64 num_rows;
+ struct MR_LD_SPAN span;
+ struct MR_SPAN_INFO block_span_info;
+};
+
+struct MR_LD_RAID {
+ struct {
+ u32 fpCapable:1;
+ u32 reserved5:3;
+ u32 ldPiMode:4;
+ u32 pdPiMode:4;
+ u32 encryptionType:8;
+ u32 fpWriteCapable:1;
+ u32 fpReadCapable:1;
+ u32 fpWriteAcrossStripe:1;
+ u32 fpReadAcrossStripe:1;
+ u32 reserved4:8;
+ } capability;
+ u32 reserved6;
+ u64 size;
+ u8 spanDepth;
+ u8 level;
+ u8 stripeShift;
+ u8 rowSize;
+ u8 rowDataSize;
+ u8 writeMode;
+ u8 PRL;
+ u8 SRL;
+ u16 targetId;
+ u8 ldState;
+ u8 regTypeReqOnWrite;
+ u8 modFactor;
+ u8 reserved2[1];
+ u16 seqNum;
+
+ struct {
+ u32 ldSyncRequired:1;
+ u32 reserved:31;
+ } flags;
+
+ u8 reserved3[0x5C];
+};
+
+struct MR_LD_SPAN_MAP {
+ struct MR_LD_RAID ldRaid;
+ u8 dataArmMap[MAX_RAIDMAP_ROW_SIZE];
+ struct MR_SPAN_BLOCK_INFO spanBlock[MAX_RAIDMAP_SPAN_DEPTH];
+};
+
+struct MR_FW_RAID_MAP {
+ u32 totalSize;
+ union {
+ struct {
+ u32 maxLd;
+ u32 maxSpanDepth;
+ u32 maxRowSize;
+ u32 maxPdCount;
+ u32 maxArrays;
+ } validationInfo;
+ u32 version[5];
+ u32 reserved1[5];
+ };
+
+ u32 ldCount;
+ u32 Reserved1;
+ u8 ldTgtIdToLd[MAX_RAIDMAP_LOGICAL_DRIVES+
+ MAX_RAIDMAP_VIEWS];
+ u8 fpPdIoTimeoutSec;
+ u8 reserved2[7];
+ struct MR_ARRAY_INFO arMapInfo[MAX_RAIDMAP_ARRAYS];
+ struct MR_DEV_HANDLE_INFO devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES];
+ struct MR_LD_SPAN_MAP ldSpanMap[1];
+};
+
+struct IO_REQUEST_INFO {
+ u64 ldStartBlock;
+ u32 numBlocks;
+ u16 ldTgtId;
+ u8 isRead;
+ u16 devHandle;
+ u64 pdBlock;
+ u8 fpOkForIo;
+};
+
+struct MR_LD_TARGET_SYNC {
+ u8 targetId;
+ u8 reserved;
+ u16 seqNum;
+};
+
+#define IEEE_SGE_FLAGS_ADDR_MASK (0x03)
+#define IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00)
+#define IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01)
+#define IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02)
+#define IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03)
+#define IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80)
+#define IEEE_SGE_FLAGS_END_OF_LIST (0x40)
+
+struct megasas_register_set;
+struct megasas_instance;
+
+union desc_word {
+ u64 word;
+ struct {
+ u32 low;
+ u32 high;
+ } u;
+};
+
+struct megasas_cmd_fusion {
+ struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
+ dma_addr_t io_request_phys_addr;
+
+ union MPI2_SGE_IO_UNION *sg_frame;
+ dma_addr_t sg_frame_phys_addr;
+
+ u8 *sense;
+ dma_addr_t sense_phys_addr;
+
+ struct list_head list;
+ struct scsi_cmnd *scmd;
+ struct megasas_instance *instance;
+
+ u8 retry_for_fw_reset;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *request_desc;
+
+ /*
+ * Context for a MFI frame.
+ * Used to get the mfi cmd from list when a MFI cmd is completed
+ */
+ u32 sync_cmd_idx;
+ u32 index;
+ u8 flags;
+};
+
+struct LD_LOAD_BALANCE_INFO {
+ u8 loadBalanceFlag;
+ u8 reserved1;
+ u16 raid1DevHandle[2];
+ atomic_t scsi_pending_cmds[2];
+ u64 last_accessed_block[2];
+};
+
+struct MR_FW_RAID_MAP_ALL {
+ struct MR_FW_RAID_MAP raidMap;
+ struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES - 1];
+} __attribute__ ((packed));
+
+struct fusion_context {
+ struct megasas_cmd_fusion **cmd_list;
+ struct list_head cmd_pool;
+
+ spinlock_t cmd_pool_lock;
+
+ dma_addr_t req_frames_desc_phys;
+ u8 *req_frames_desc;
+
+ struct dma_pool *io_request_frames_pool;
+ dma_addr_t io_request_frames_phys;
+ u8 *io_request_frames;
+
+ struct dma_pool *sg_dma_pool;
+ struct dma_pool *sense_dma_pool;
+
+ dma_addr_t reply_frames_desc_phys;
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
+ struct dma_pool *reply_frames_desc_pool;
+
+ u16 last_reply_idx;
+
+ u32 reply_q_depth;
+ u32 request_alloc_sz;
+ u32 reply_alloc_sz;
+ u32 io_frames_alloc_sz;
+
+ u16 max_sge_in_main_msg;
+ u16 max_sge_in_chain;
+
+ u8 chain_offset_io_request;
+ u8 chain_offset_mfi_pthru;
+
+ struct MR_FW_RAID_MAP_ALL *ld_map[2];
+ dma_addr_t ld_map_phys[2];
+
+ u32 map_sz;
+ u8 fast_path_io;
+ struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES];
+};
+
+union desc_value {
+ u64 word;
+ struct {
+ u32 low;
+ u32 high;
+ } u;
+};
+
+#endif /* _MEGARAID_SAS_FUSION_H_ */
* Called by midlayer with host locked to queue a new
* request
*/
-static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int mesh_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct mesh_state *ms;
return 0;
}
+static DEF_SCSI_QCMD(mesh_queue)
+
/*
* Called to handle interrupts, either call by the interrupt
* handler (do_mesh_interrupt) or by other functions in
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.15
+ * mpi2.h Version: 02.00.16
*
* Version History
* ---------------
* Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
* Added defines for product-specific range of message
* function codes, 0xF0 to 0xFF.
+ * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added alternative defines for the SGE Direction bit.
* --------------------------------------------------------------------------
*/
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x0F)
+#define MPI2_HEADER_VERSION_UNIT (0x10)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00)
#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04)
+#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST)
+#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC)
+
/* Address Size */
#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00)
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.14
+ * mpi2_cnfg.h Version: 02.00.15
*
* Version History
* ---------------
* Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
* Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
* Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
+ * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
+ * define.
+ * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
+ * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
* --------------------------------------------------------------------------
*/
#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06)
#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* Config Reply Message */
#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064)
#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065)
+#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E)
+
#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080)
#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081)
#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082)
#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E)
+
+
/* Manufacturing Page 0 */
typedef struct _MPI2_CONFIG_PAGE_MAN_0
/* IO Unit Page 1 Flags defines */
#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800)
#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600)
+#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9)
#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000)
#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200)
#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400)
#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000)
#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000)
#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080)
#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040)
#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020)
#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000)
#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03)
#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04)
#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06)
#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF)
/* PhysDiskAttributes defines */
+#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C)
#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08)
#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04)
+
+#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03)
#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02)
#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01)
#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03)
#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04)
#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05)
+#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06)
#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08)
#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09)
#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A)
#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000)
#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000)
+#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27)
#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000)
#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000)
#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000)
* can be sized by the build environment.
* 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
* VolumeCreationFlags and marked the old one as obsolete.
+ * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
* --------------------------------------------------------------------------
mpi2_sas.h
* Request.
* 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
* to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ * 05-12-10 02.00.04 Modified some comments.
* --------------------------------------------------------------------------
mpi2_targ.h
* and reply messages.
* Added MPI2_DIAG_BUF_TYPE_EXTENDED.
* Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
* --------------------------------------------------------------------------
mpi2_type.h
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.09
+ * mpi2_init.h Version: 02.00.10
*
* Version History
* ---------------
* Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
* Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
* 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it.
+ * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request.
* --------------------------------------------------------------------------
*/
U8 LUN[8]; /* 0x34 */
U32 Control; /* 0x3C */
MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
+
+#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */
+ MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion;
+#endif
+
MPI2_SGE_IO_UNION SGL; /* 0x60 */
+
} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t;
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.14
+ * mpi2_ioc.h Version: 02.00.15
*
* Version History
* ---------------
* 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines.
* Added PowerManagementControl Request structures and
* defines.
+ * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete.
+ * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
* --------------------------------------------------------------------------
*/
#define MPI2_EVENT_STATE_CHANGE (0x0002)
#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005)
#define MPI2_EVENT_EVENT_CHANGE (0x000A)
-#define MPI2_EVENT_TASK_SET_FULL (0x000E)
+#define MPI2_EVENT_TASK_SET_FULL (0x000E) /* obsolete */
#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F)
#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014)
#define MPI2_EVENT_SAS_DISCOVERY (0x0016)
MPI2_POINTER pMpi2EventDataHardResetReceived_t;
/* Task Set Full Event data */
+/* this event is obsolete */
typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL
{
#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03)
#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04)
#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05)
+#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A)
/*
- * Copyright (c) 2000-2008 LSI Corporation.
+ * Copyright (c) 2000-2010 LSI Corporation.
*
*
* Name: mpi2_raid.h
* Title: MPI Integrated RAID messages and structures
* Creation Date: April 26, 2007
*
- * mpi2_raid.h Version: 02.00.04
+ * mpi2_raid.h Version: 02.00.05
*
* Version History
* ---------------
* can be sized by the build environment.
* 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
* VolumeCreationFlags and marked the old one as obsolete.
+ * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
* --------------------------------------------------------------------------
*/
#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)
#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002)
#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003)
+#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004)
/* RAID Action Reply ActionData union */
/*
- * Copyright (c) 2000-2007 LSI Corporation.
+ * Copyright (c) 2000-2010 LSI Corporation.
*
*
* Name: mpi2_sas.h
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: February 9, 2007
*
- * mpi2.h Version: 02.00.03
+ * mpi2_sas.h Version: 02.00.04
*
* Version History
* ---------------
* Request.
* 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
* to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ * 05-12-10 02.00.04 Modified some comments.
* --------------------------------------------------------------------------
*/
/* values for PassthroughFlags field */
#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* SMP Passthrough Reply Message */
#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002)
#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* SATA Passthrough Reply Message */
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.04
+ * mpi2_tool.h Version: 02.00.05
*
* Version History
* ---------------
* and reply messages.
* Added MPI2_DIAG_BUF_TYPE_EXTENDED.
* Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
* --------------------------------------------------------------------------
*/
/* defines for the Tools */
#define MPI2_TOOLBOX_CLEAN_TOOL (0x00)
#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01)
+#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02)
#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03)
#define MPI2_TOOLBOX_BEACON_TOOL (0x05)
#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06)
* Toolbox Memory Move request
****************************************************************************/
-typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST
-{
+typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST {
U8 Tool; /* 0x00 */
U8 Reserved1; /* 0x01 */
U8 ChainOffset; /* 0x02 */
Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_t;
+/****************************************************************************
+* Toolbox Diagnostic Data Upload request
+****************************************************************************/
+
+typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST {
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U8 SGLFlags; /* 0x0C */
+ U8 Reserved5; /* 0x0D */
+ U16 Reserved6; /* 0x0E */
+ U32 Flags; /* 0x10 */
+ U32 DataLength; /* 0x14 */
+ MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */
+} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+Mpi2ToolboxDiagDataUploadRequest_t,
+MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t;
+
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+
+typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER {
+ U32 DiagDataLength; /* 00h */
+ U8 FormatCode; /* 04h */
+ U8 Reserved1; /* 05h */
+ U16 Reserved2; /* 06h */
+} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER,
+Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t;
+
+
/****************************************************************************
* Toolbox ISTWI Read Write Tool
****************************************************************************/
#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11)
#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* Toolbox ISTWI Read Write Tool reply message */
Mpi2ToolboxDiagnosticCliRequest_t,
MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t;
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* Toolbox Diagnostic CLI Tool reply message */
static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
-#define MPT2SAS_MAX_REQUEST_QUEUE 600 /* maximum controller queue depth */
static int max_queue_depth = -1;
module_param(max_queue_depth, int, 0);
module_param(msix_disable, int, 0);
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
+static int missing_delay[2] = {-1, -1};
+module_param_array(missing_delay, int, NULL, 0);
+MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay");
+
/* diag_buffer_enable is bitwise
* bit 0 set = TRACE
* bit 1 set = SNAPSHOT
case MPI2_EVENT_EVENT_CHANGE:
desc = "Event Change";
break;
- case MPI2_EVENT_TASK_SET_FULL:
- desc = "Task Set Full";
- break;
case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
desc = "Device Status Change";
break;
if (smid < ioc->internal_smid) {
i = smid - ioc->hi_priority_smid;
cb_idx = ioc->hpr_lookup[i].cb_idx;
- } else {
+ } else if (smid <= ioc->hba_queue_depth) {
i = smid - ioc->internal_smid;
cb_idx = ioc->internal_lookup[i].cb_idx;
}
return IRQ_NONE;
completed_cmds = 0;
+ cb_idx = 0xFF;
do {
rd.word = rpf->Words;
if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)
MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
reply = le32_to_cpu
(rpf->AddressReply.ReplyFrameAddress);
+ if (reply > ioc->reply_dma_max_address ||
+ reply < ioc->reply_dma_min_address)
+ reply = 0;
} else if (request_desript_type ==
MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER)
goto next;
{
unsigned long flags;
int i;
+ struct chain_tracker *chain_req, *next;
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
if (smid >= ioc->hi_priority_smid) {
/* scsiio queue */
i = smid - 1;
+ if (!list_empty(&ioc->scsi_lookup[i].chain_list)) {
+ list_for_each_entry_safe(chain_req, next,
+ &ioc->scsi_lookup[i].chain_list, tracker_list) {
+ list_del_init(&chain_req->tracker_list);
+ list_add_tail(&chain_req->tracker_list,
+ &ioc->free_chain_list);
+ }
+ }
ioc->scsi_lookup[i].cb_idx = 0xFF;
ioc->scsi_lookup[i].scmd = NULL;
list_add_tail(&ioc->scsi_lookup[i].tracker_list,
printk(")\n");
}
+/**
+ * _base_update_missing_delay - change the missing delay timers
+ * @ioc: per adapter object
+ * @device_missing_delay: amount of time till device is reported missing
+ * @io_missing_delay: interval IO is returned when there is a missing device
+ *
+ * Return nothing.
+ *
+ * Passed on the command line, this function will modify the device missing
+ * delay, as well as the io missing delay. This should be called at driver
+ * load time.
+ */
+static void
+_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
+ u16 device_missing_delay, u8 io_missing_delay)
+{
+ u16 dmd, dmd_new, dmd_orignal;
+ u8 io_missing_delay_original;
+ u16 sz;
+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
+ Mpi2ConfigReply_t mpi_reply;
+ u8 num_phys = 0;
+ u16 ioc_status;
+
+ mpt2sas_config_get_number_hba_phys(ioc, &num_phys);
+ if (!num_phys)
+ return;
+
+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys *
+ sizeof(Mpi2SasIOUnit1PhyData_t));
+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
+ if (!sas_iounit_pg1) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ goto out;
+ }
+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
+ sas_iounit_pg1, sz))) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ goto out;
+ }
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ goto out;
+ }
+
+ /* device missing delay */
+ dmd = sas_iounit_pg1->ReportDeviceMissingDelay;
+ if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
+ dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
+ else
+ dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
+ dmd_orignal = dmd;
+ if (device_missing_delay > 0x7F) {
+ dmd = (device_missing_delay > 0x7F0) ? 0x7F0 :
+ device_missing_delay;
+ dmd = dmd / 16;
+ dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16;
+ } else
+ dmd = device_missing_delay;
+ sas_iounit_pg1->ReportDeviceMissingDelay = dmd;
+
+ /* io missing delay */
+ io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay;
+ sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay;
+
+ if (!mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
+ sz)) {
+ if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
+ dmd_new = (dmd &
+ MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
+ else
+ dmd_new =
+ dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
+ printk(MPT2SAS_INFO_FMT "device_missing_delay: old(%d), "
+ "new(%d)\n", ioc->name, dmd_orignal, dmd_new);
+ printk(MPT2SAS_INFO_FMT "ioc_missing_delay: old(%d), "
+ "new(%d)\n", ioc->name, io_missing_delay_original,
+ io_missing_delay);
+ ioc->device_missing_delay = dmd_new;
+ ioc->io_missing_delay = io_missing_delay;
+ }
+
+out:
+ kfree(sas_iounit_pg1);
+}
+
/**
* _base_static_config_pages - static start of day config pages
* @ioc: per adapter object
MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+
}
/**
static void
_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
{
+ int i;
+
dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
}
kfree(ioc->hpr_lookup);
kfree(ioc->internal_lookup);
+ if (ioc->chain_lookup) {
+ for (i = 0; i < ioc->chain_depth; i++) {
+ if (ioc->chain_lookup[i].chain_buffer)
+ pci_pool_free(ioc->chain_dma_pool,
+ ioc->chain_lookup[i].chain_buffer,
+ ioc->chain_lookup[i].chain_buffer_dma);
+ }
+ if (ioc->chain_dma_pool)
+ pci_pool_destroy(ioc->chain_dma_pool);
+ }
+ if (ioc->chain_lookup) {
+ free_pages((ulong)ioc->chain_lookup, ioc->chain_pages);
+ ioc->chain_lookup = NULL;
+ }
}
u32 sz, total_sz;
u32 retry_sz;
u16 max_request_credit;
+ int i;
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
}
/* command line tunables for max controller queue depth */
- if (max_queue_depth != -1) {
+ if (max_queue_depth != -1)
max_request_credit = (max_queue_depth < facts->RequestCredit)
? max_queue_depth : facts->RequestCredit;
- } else {
- max_request_credit = (facts->RequestCredit >
- MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE :
- facts->RequestCredit;
- }
+ else
+ max_request_credit = facts->RequestCredit;
ioc->hba_queue_depth = max_request_credit;
ioc->hi_priority_depth = facts->HighPriorityCredit;
* "frame for smid=0
*/
ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth;
- sz = ((ioc->scsiio_depth + 1 + ioc->chain_depth) * ioc->request_sz);
+ sz = ((ioc->scsiio_depth + 1) * ioc->request_sz);
/* hi-priority queue */
sz += (ioc->hi_priority_depth * ioc->request_sz);
ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
ioc->request_sz);
- ioc->chain = ioc->internal + (ioc->internal_depth *
- ioc->request_sz);
- ioc->chain_dma = ioc->internal_dma + (ioc->internal_depth *
- ioc->request_sz);
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "
"depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
ioc->request, ioc->hba_queue_depth, ioc->request_sz,
(ioc->hba_queue_depth * ioc->request_sz)/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth"
- "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain,
- ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
- ioc->request_sz))/1024));
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n",
ioc->name, (unsigned long long) ioc->request_dma));
total_sz += sz;
"depth(%d)\n", ioc->name, ioc->request,
ioc->scsiio_depth));
+ /* loop till the allocation succeeds */
+ do {
+ sz = ioc->chain_depth * sizeof(struct chain_tracker);
+ ioc->chain_pages = get_order(sz);
+ ioc->chain_lookup = (struct chain_tracker *)__get_free_pages(
+ GFP_KERNEL, ioc->chain_pages);
+ if (ioc->chain_lookup == NULL)
+ ioc->chain_depth -= 100;
+ } while (ioc->chain_lookup == NULL);
+ ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
+ ioc->request_sz, 16, 0);
+ if (!ioc->chain_dma_pool) {
+ printk(MPT2SAS_ERR_FMT "chain_dma_pool: pci_pool_create "
+ "failed\n", ioc->name);
+ goto out;
+ }
+ for (i = 0; i < ioc->chain_depth; i++) {
+ ioc->chain_lookup[i].chain_buffer = pci_pool_alloc(
+ ioc->chain_dma_pool , GFP_KERNEL,
+ &ioc->chain_lookup[i].chain_buffer_dma);
+ if (!ioc->chain_lookup[i].chain_buffer) {
+ ioc->chain_depth = i;
+ goto chain_done;
+ }
+ total_sz += ioc->request_sz;
+ }
+chain_done:
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool depth"
+ "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
+ ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
+ ioc->request_sz))/1024));
+
/* initialize hi-priority queue smid's */
ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
sizeof(struct request_tracker), GFP_KERNEL);
ioc->name);
goto out;
}
+ ioc->reply_dma_min_address = (u32)(ioc->reply_dma);
+ ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz;
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth"
"(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply,
ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024));
return 0;
out:
- _base_release_memory_pools(ioc);
return -ENOMEM;
}
INIT_LIST_HEAD(&ioc->free_list);
smid = 1;
for (i = 0; i < ioc->scsiio_depth; i++, smid++) {
+ INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list);
ioc->scsi_lookup[i].cb_idx = 0xFF;
ioc->scsi_lookup[i].smid = smid;
ioc->scsi_lookup[i].scmd = NULL;
list_add_tail(&ioc->internal_lookup[i].tracker_list,
&ioc->internal_free_list);
}
+
+ /* chain pool */
+ INIT_LIST_HEAD(&ioc->free_chain_list);
+ for (i = 0; i < ioc->chain_depth; i++)
+ list_add_tail(&ioc->chain_lookup[i].tracker_list,
+ &ioc->free_chain_list);
+
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
/* initialize Reply Free Queue */
_base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME);
_base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK);
_base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);
- _base_unmask_events(ioc, MPI2_EVENT_TASK_SET_FULL);
_base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED);
r = _base_make_ioc_operational(ioc, CAN_SLEEP);
if (r)
goto out_free_resources;
+ if (missing_delay[0] != -1 && missing_delay[1] != -1)
+ _base_update_missing_delay(ioc, missing_delay[0],
+ missing_delay[1]);
+
mpt2sas_base_start_watchdog(ioc);
return 0;
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "06.100.00.00"
-#define MPT2SAS_MAJOR_VERSION 06
+#define MPT2SAS_DRIVER_VERSION "07.100.00.00"
+#define MPT2SAS_MAJOR_VERSION 07
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 00
#define MPT2SAS_RELEASE_VERSION 00
SOFT_RESET,
};
+/**
+ * struct chain_tracker - firmware chain tracker
+ * @chain_buffer: chain buffer
+ * @chain_buffer_dma: physical address
+ * @tracker_list: list of free request (ioc->free_chain_list)
+ */
+struct chain_tracker {
+ void *chain_buffer;
+ dma_addr_t chain_buffer_dma;
+ struct list_head tracker_list;
+};
+
/**
* struct request_tracker - firmware request tracker
* @smid: system message id
u16 smid;
struct scsi_cmnd *scmd;
u8 cb_idx;
+ struct list_head chain_list;
struct list_head tracker_list;
};
wait_queue_head_t reset_wq;
/* chain */
- u8 *chain;
- dma_addr_t chain_dma;
+ struct chain_tracker *chain_lookup;
+ struct list_head free_chain_list;
+ struct dma_pool *chain_dma_pool;
+ ulong chain_pages;
u16 max_sges_in_main_message;
u16 max_sges_in_chain_message;
u16 chains_needed_per_io;
u16 reply_sz;
u8 *reply;
dma_addr_t reply_dma;
+ u32 reply_dma_max_address;
+ u32 reply_dma_min_address;
struct dma_pool *reply_dma_pool;
/* reply free queue */
ulong timeout, struct scsi_cmnd *scmd);
void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
+void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
+void mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
u16 handle);
struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
BLOCKING,
};
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _ctl_sas_device_find_by_handle - sas device search
* @ioc: per adapter object
return r;
}
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _ctl_display_some_debug - debug routine
* @ioc: per adapter object
}
/**
- * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
+ * _scsih_get_chain_buffer_tracker - obtain chain tracker
* @ioc: per adapter object
- * @smid: system request message index
+ * @smid: smid associated to an IO request
*
- * Returns phys pointer to chain buffer.
+ * Returns chain tracker(from ioc->free_chain_list)
*/
-static dma_addr_t
-_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+static struct chain_tracker *
+_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
- return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
- ioc->chains_needed_per_io));
-}
+ struct chain_tracker *chain_req;
+ unsigned long flags;
-/**
- * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns virt pointer to chain buffer.
- */
-static void *
-_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
- ioc->chains_needed_per_io)));
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ if (list_empty(&ioc->free_chain_list)) {
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ printk(MPT2SAS_WARN_FMT "chain buffers not available\n",
+ ioc->name);
+ return NULL;
+ }
+ chain_req = list_entry(ioc->free_chain_list.next,
+ struct chain_tracker, tracker_list);
+ list_del_init(&chain_req->tracker_list);
+ list_add_tail(&chain_req->tracker_list,
+ &ioc->scsi_lookup[smid - 1].chain_list);
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return chain_req;
}
/**
u32 sgl_flags;
u32 sgl_flags_last_element;
u32 sgl_flags_end_buffer;
+ struct chain_tracker *chain_req;
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
/* initializing the chain flags and pointers */
chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
- chain = _scsih_get_chain_buffer(ioc, smid);
- chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
+ chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
+ if (!chain_req)
+ return -1;
+ chain = chain_req->chain_buffer;
+ chain_dma = chain_req->chain_buffer_dma;
do {
sges_in_segment = (sges_left <=
ioc->max_sges_in_chain_message) ? sges_left :
sges_in_segment--;
}
- chain_dma += ioc->request_sz;
- chain += ioc->request_sz;
+ chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
+ if (!chain_req)
+ return -1;
+ chain = chain_req->chain_buffer;
+ chain_dma = chain_req->chain_buffer_dma;
} while (1);
}
/**
- * _scsih_change_queue_depth - setting device queue depth
+ * _scsih_adjust_queue_depth - setting device queue depth
* @sdev: scsi device struct
* @qdepth: requested queue depth
- * @reason: calling context
*
- * Returns queue depth.
+ *
+ * Returns nothing
*/
-static int
-_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
+static void
+_scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
{
struct Scsi_Host *shost = sdev->host;
int max_depth;
- int tag_type;
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
struct MPT2SAS_DEVICE *sas_device_priv_data;
struct MPT2SAS_TARGET *sas_target_priv_data;
struct _sas_device *sas_device;
unsigned long flags;
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
max_depth = shost->can_queue;
/* limit max device queue for SATA to 32 */
max_depth = 1;
if (qdepth > max_depth)
qdepth = max_depth;
- tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
- scsi_adjust_queue_depth(sdev, tag_type, qdepth);
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+}
+
+/**
+ * _scsih_change_queue_depth - setting device queue depth
+ * @sdev: scsi device struct
+ * @qdepth: requested queue depth
+ * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP
+ * (see include/scsi/scsi_host.h for definition)
+ *
+ * Returns queue depth.
+ */
+static int
+_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
+{
+ if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP)
+ _scsih_adjust_queue_depth(sdev, qdepth);
+ else if (reason == SCSI_QDEPTH_QFULL)
+ scsi_track_queue_full(sdev, qdepth);
+ else
+ return -EOPNOTSUPP;
if (sdev->inquiry_len > 7)
sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
struct scsi_target *starget = scmd->device->sdev_target;
- starget_printk(KERN_INFO, starget, "attempting target reset! "
+ starget_printk(KERN_INFO, starget, "attempting device reset! "
"scmd(%p)\n", scmd);
_scsih_tm_display_info(ioc, scmd);
sas_device_priv_data = scmd->device->hostdata;
if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- starget_printk(KERN_INFO, starget, "target been deleted! "
+ starget_printk(KERN_INFO, starget, "device been deleted! "
"scmd(%p)\n", scmd);
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
&sas_expander->sas_port_list, port_list) {
if (mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
+ SAS_EDGE_EXPANDER_DEVICE ||
mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
+ SAS_FANOUT_EXPANDER_DEVICE) {
spin_lock_irqsave(&ioc->sas_node_lock, flags);
expander_sibling =
_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
u8 msix_index, u32 reply)
{
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Mpi2SasIoUnitControlReply_t *mpi_reply =
mpt2sas_base_get_reply_virt_addr(ioc, reply);
-
+#endif
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
"sc_complete:handle(0x%04x), (open) "
"smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
* SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
*/
static int
-_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
+_scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
{
struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT2SAS_DEVICE *sas_device_priv_data;
return SCSI_MLQUEUE_HOST_BUSY;
}
+static DEF_SCSI_QCMD(_scsih_qcmd)
+
/**
* _scsih_normalize_sense - normalize descriptor and fixed format sense data
* @sense_buffer: sense data returned by target
Mpi2ConfigReply_t mpi_reply;
Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
u16 attached_handle;
+ u8 link_rate;
dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
"updating handles for sas_host(0x%016llx)\n",
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
goto out;
for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
+ link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4;
if (i == 0)
ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
PhyData[0].ControllerDevHandle);
ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
AttachedDevHandle);
+ if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
+ link_rate = MPI2_SAS_NEG_LINK_RATE_1_5;
mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
- attached_handle, i, sas_iounit_pg0->PhyData[i].
- NegotiatedLinkRate >> 4);
+ attached_handle, i, link_rate);
}
out:
kfree(sas_iounit_pg0);
}
/**
- * _scsih_expander_remove - removing expander object
+ * mpt2sas_expander_remove - removing expander object
* @ioc: per adapter object
* @sas_address: expander sas_address
*
* Return nothing.
*/
-static void
-_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
+void
+mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
{
struct _sas_node *sas_expander;
unsigned long flags;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
sas_address);
+ if (!sas_expander) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ return;
+ }
+ list_del(&sas_expander->list);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
_scsih_expander_node_remove(ioc, sas_expander);
}
sas_device_backup.sas_address));
}
+/**
+ * mpt2sas_device_remove - removing device object
+ * @ioc: per adapter object
+ * @sas_address: expander sas_address
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
+{
+ struct _sas_device *sas_device;
+ unsigned long flags;
+
+ if (ioc->shost_recovery)
+ return;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_address);
+ if (!sas_device) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ _scsih_remove_device(ioc, sas_device);
+}
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _scsih_sas_topology_change_event_debug - debug for topology event
int i;
u16 parent_handle, handle;
u16 reason_code;
- u8 phy_number;
+ u8 phy_number, max_phys;
struct _sas_node *sas_expander;
struct _sas_device *sas_device;
u64 sas_address;
sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
parent_handle);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (sas_expander)
+ if (sas_expander) {
sas_address = sas_expander->sas_address;
- else if (parent_handle < ioc->sas_hba.num_phys)
+ max_phys = sas_expander->num_phys;
+ } else if (parent_handle < ioc->sas_hba.num_phys) {
sas_address = ioc->sas_hba.sas_address;
- else
+ max_phys = ioc->sas_hba.num_phys;
+ } else
return;
/* handle siblings events */
ioc->pci_error_recovery)
return;
phy_number = event_data->StartPhyNum + i;
+ if (phy_number >= max_phys)
+ continue;
reason_code = event_data->PHY[i].PhyStatus &
MPI2_EVENT_SAS_TOPO_RC_MASK;
if ((event_data->PHY[i].PhyStatus &
/* handle expander removal */
if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
sas_expander)
- _scsih_expander_remove(ioc, sas_address);
+ mpt2sas_expander_remove(ioc, sas_address);
}
}
}
-/**
- * _scsih_task_set_full - handle task set full
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Throttle back qdepth.
- */
-static void
-_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
- *fw_event)
-{
- unsigned long flags;
- struct _sas_device *sas_device;
- static struct _raid_device *raid_device;
- struct scsi_device *sdev;
- int depth;
- u16 current_depth;
- u16 handle;
- int id, channel;
- u64 sas_address;
- Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
-
- current_depth = le16_to_cpu(event_data->CurrentDepth);
- handle = le16_to_cpu(event_data->DevHandle);
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- id = sas_device->id;
- channel = sas_device->channel;
- sas_address = sas_device->sas_address;
-
- /* if hidden raid component, then change to volume characteristics */
- if (test_bit(handle, ioc->pd_handles) && sas_device->volume_handle) {
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(
- ioc, sas_device->volume_handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (raid_device) {
- id = raid_device->id;
- channel = raid_device->channel;
- handle = raid_device->handle;
- sas_address = raid_device->wwid;
- }
- }
-
- if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
- starget_printk(KERN_INFO, sas_device->starget, "task set "
- "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
- handle, (unsigned long long)sas_address, current_depth);
-
- shost_for_each_device(sdev, ioc->shost) {
- if (sdev->id == id && sdev->channel == channel) {
- if (current_depth > sdev->queue_depth) {
- if (ioc->logging_level &
- MPT_DEBUG_TASK_SET_FULL)
- sdev_printk(KERN_INFO, sdev, "strange "
- "observation, the queue depth is"
- " (%d) meanwhile fw queue depth "
- "is (%d)\n", sdev->queue_depth,
- current_depth);
- continue;
- }
- depth = scsi_track_queue_full(sdev,
- current_depth - 1);
- if (depth > 0)
- sdev_printk(KERN_INFO, sdev, "Queue depth "
- "reduced to (%d)\n", depth);
- else if (depth < 0)
- sdev_printk(KERN_INFO, sdev, "Tagged Command "
- "Queueing is being disabled\n");
- else if (depth == 0)
- if (ioc->logging_level &
- MPT_DEBUG_TASK_SET_FULL)
- sdev_printk(KERN_INFO, sdev,
- "Queue depth not changed yet\n");
- }
- }
-}
-
/**
* _scsih_prep_device_scan - initialize parameters prior to device scan
* @ioc: per adapter object
sas_expander->responding = 0;
continue;
}
- _scsih_expander_remove(ioc, sas_expander->sas_address);
+ mpt2sas_expander_remove(ioc, sas_expander->sas_address);
goto retry_expander_search;
}
}
case MPI2_EVENT_IR_OPERATION_STATUS:
_scsih_sas_ir_operation_status_event(ioc, fw_event);
break;
- case MPI2_EVENT_TASK_SET_FULL:
- _scsih_task_set_full(ioc, fw_event);
- break;
}
_scsih_fw_event_free(ioc, fw_event);
}
case MPI2_EVENT_SAS_DISCOVERY:
case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
case MPI2_EVENT_IR_PHYSICAL_DISK:
- case MPI2_EVENT_TASK_SET_FULL:
break;
default: /* ignore the rest */
_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
struct _sas_node *sas_expander)
{
- struct _sas_port *mpt2sas_port;
- struct _sas_device *sas_device;
- struct _sas_node *expander_sibling;
- unsigned long flags;
-
- if (!sas_expander)
- return;
+ struct _sas_port *mpt2sas_port, *next;
/* remove sibling ports attached to this expander */
- retry_device_search:
- list_for_each_entry(mpt2sas_port,
- &sas_expander->sas_port_list, port_list) {
- if (mpt2sas_port->remote_identify.device_type ==
- SAS_END_DEVICE) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device =
- mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
- mpt2sas_port->remote_identify.sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device)
- continue;
- _scsih_remove_device(ioc, sas_device);
- if (ioc->shost_recovery)
- return;
- goto retry_device_search;
- }
- }
-
- retry_expander_search:
- list_for_each_entry(mpt2sas_port,
+ list_for_each_entry_safe(mpt2sas_port, next,
&sas_expander->sas_port_list, port_list) {
-
+ if (ioc->shost_recovery)
+ return;
if (mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
+ SAS_END_DEVICE)
+ mpt2sas_device_remove(ioc,
+ mpt2sas_port->remote_identify.sas_address);
+ else if (mpt2sas_port->remote_identify.device_type ==
+ SAS_EDGE_EXPANDER_DEVICE ||
mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- expander_sibling =
- mpt2sas_scsih_expander_find_by_sas_address(
- ioc, mpt2sas_port->remote_identify.sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (!expander_sibling)
- continue;
- _scsih_expander_remove(ioc,
- expander_sibling->sas_address);
- if (ioc->shost_recovery)
- return;
- goto retry_expander_search;
- }
+ SAS_FANOUT_EXPANDER_DEVICE)
+ mpt2sas_expander_remove(ioc,
+ mpt2sas_port->remote_identify.sas_address);
}
mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
sas_expander->handle, (unsigned long long)
sas_expander->sas_address);
- list_del(&sas_expander->list);
kfree(sas_expander->phy);
kfree(sas_expander);
}
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct _sas_port *mpt2sas_port;
- struct _sas_device *sas_device;
- struct _sas_node *expander_sibling;
+ struct _sas_port *mpt2sas_port, *next_port;
struct _raid_device *raid_device, *next;
struct MPT2SAS_TARGET *sas_target_priv_data;
struct workqueue_struct *wq;
}
/* free ports attached to the sas_host */
- retry_again:
- list_for_each_entry(mpt2sas_port,
+ list_for_each_entry_safe(mpt2sas_port, next_port,
&ioc->sas_hba.sas_port_list, port_list) {
if (mpt2sas_port->remote_identify.device_type ==
- SAS_END_DEVICE) {
- sas_device =
- mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
- mpt2sas_port->remote_identify.sas_address);
- if (sas_device) {
- _scsih_remove_device(ioc, sas_device);
- goto retry_again;
- }
- } else {
- expander_sibling =
- mpt2sas_scsih_expander_find_by_sas_address(ioc,
+ SAS_END_DEVICE)
+ mpt2sas_device_remove(ioc,
+ mpt2sas_port->remote_identify.sas_address);
+ else if (mpt2sas_port->remote_identify.device_type ==
+ SAS_EDGE_EXPANDER_DEVICE ||
+ mpt2sas_port->remote_identify.device_type ==
+ SAS_FANOUT_EXPANDER_DEVICE)
+ mpt2sas_expander_remove(ioc,
mpt2sas_port->remote_identify.sas_address);
- if (expander_sibling) {
- _scsih_expander_remove(ioc,
- expander_sibling->sas_address);
- goto retry_again;
- }
- }
}
/* free phys attached to the sas_host */
return rc;
}
+/**
+ * _transport_delete_port - helper function to removing a port
+ * @ioc: per adapter object
+ * @mpt2sas_port: mpt2sas per port object
+ *
+ * Returns nothing.
+ */
+static void
+_transport_delete_port(struct MPT2SAS_ADAPTER *ioc,
+ struct _sas_port *mpt2sas_port)
+{
+ u64 sas_address = mpt2sas_port->remote_identify.sas_address;
+ enum sas_device_type device_type =
+ mpt2sas_port->remote_identify.device_type;
+
+ dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
+ "remove: sas_addr(0x%016llx)\n",
+ (unsigned long long) sas_address);
+
+ ioc->logging_level |= MPT_DEBUG_TRANSPORT;
+ if (device_type == SAS_END_DEVICE)
+ mpt2sas_device_remove(ioc, sas_address);
+ else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
+ device_type == SAS_FANOUT_EXPANDER_DEVICE)
+ mpt2sas_expander_remove(ioc, sas_address);
+ ioc->logging_level &= ~MPT_DEBUG_TRANSPORT;
+}
/**
- * _transport_delete_duplicate_port - (see below description)
+ * _transport_delete_phy - helper function to removing single phy from port
* @ioc: per adapter object
- * @sas_node: sas node object (either expander or sas host)
- * @sas_address: sas address of device being added
- * @phy_num: phy number
+ * @mpt2sas_port: mpt2sas per port object
+ * @mpt2sas_phy: mpt2sas per phy object
*
- * This function is called when attempting to add a new port that is claiming
- * the same phy resources already in use by another port. If we don't release
- * the claimed phy resources, the sas transport layer will hang from the BUG
- * in sas_port_add_phy.
+ * Returns nothing.
+ */
+static void
+_transport_delete_phy(struct MPT2SAS_ADAPTER *ioc,
+ struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy)
+{
+ u64 sas_address = mpt2sas_port->remote_identify.sas_address;
+
+ dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
+ "remove: sas_addr(0x%016llx), phy(%d)\n",
+ (unsigned long long) sas_address, mpt2sas_phy->phy_id);
+
+ list_del(&mpt2sas_phy->port_siblings);
+ mpt2sas_port->num_phys--;
+ sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
+ mpt2sas_phy->phy_belongs_to_port = 0;
+}
+
+/**
+ * _transport_add_phy - helper function to adding single phy to port
+ * @ioc: per adapter object
+ * @mpt2sas_port: mpt2sas per port object
+ * @mpt2sas_phy: mpt2sas per phy object
*
- * The reason we would hit this issue is becuase someone is changing the
- * sas address of a device on the fly, meanwhile controller firmware sends
- * EVENTs out of order when removing the previous instance of the device.
+ * Returns nothing.
*/
static void
-_transport_delete_duplicate_port(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_node, u64 sas_address, int phy_num)
+_transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port,
+ struct _sas_phy *mpt2sas_phy)
{
- struct _sas_port *mpt2sas_port, *mpt2sas_port_duplicate;
- struct _sas_phy *mpt2sas_phy;
+ u64 sas_address = mpt2sas_port->remote_identify.sas_address;
- printk(MPT2SAS_ERR_FMT "new device located at sas_addr(0x%016llx), "
- "phy_id(%d)\n", ioc->name, (unsigned long long)sas_address,
- phy_num);
+ dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
+ "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long)
+ sas_address, mpt2sas_phy->phy_id);
- mpt2sas_port_duplicate = NULL;
- list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, port_list) {
- dev_printk(KERN_ERR, &mpt2sas_port->port->dev,
- "existing device at sas_addr(0x%016llx), num_phys(%d)\n",
- (unsigned long long)
- mpt2sas_port->remote_identify.sas_address,
- mpt2sas_port->num_phys);
- list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
+ list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list);
+ mpt2sas_port->num_phys++;
+ sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy);
+ mpt2sas_phy->phy_belongs_to_port = 1;
+}
+
+/**
+ * _transport_add_phy_to_an_existing_port - adding new phy to existing port
+ * @ioc: per adapter object
+ * @sas_node: sas node object (either expander or sas host)
+ * @mpt2sas_phy: mpt2sas per phy object
+ * @sas_address: sas address of device/expander were phy needs to be added to
+ *
+ * Returns nothing.
+ */
+static void
+_transport_add_phy_to_an_existing_port(struct MPT2SAS_ADAPTER *ioc,
+struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, u64 sas_address)
+{
+ struct _sas_port *mpt2sas_port;
+ struct _sas_phy *phy_srch;
+
+ if (mpt2sas_phy->phy_belongs_to_port == 1)
+ return;
+
+ list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list,
+ port_list) {
+ if (mpt2sas_port->remote_identify.sas_address !=
+ sas_address)
+ continue;
+ list_for_each_entry(phy_srch, &mpt2sas_port->phy_list,
port_siblings) {
- dev_printk(KERN_ERR, &mpt2sas_phy->phy->dev,
- "phy_number(%d)\n", mpt2sas_phy->phy_id);
- if (mpt2sas_phy->phy_id == phy_num)
- mpt2sas_port_duplicate = mpt2sas_port;
+ if (phy_srch == mpt2sas_phy)
+ return;
}
+ _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy);
+ return;
}
- if (!mpt2sas_port_duplicate)
+}
+
+/**
+ * _transport_del_phy_from_an_existing_port - delete phy from existing port
+ * @ioc: per adapter object
+ * @sas_node: sas node object (either expander or sas host)
+ * @mpt2sas_phy: mpt2sas per phy object
+ *
+ * Returns nothing.
+ */
+static void
+_transport_del_phy_from_an_existing_port(struct MPT2SAS_ADAPTER *ioc,
+ struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy)
+{
+ struct _sas_port *mpt2sas_port, *next;
+ struct _sas_phy *phy_srch;
+
+ if (mpt2sas_phy->phy_belongs_to_port == 0)
return;
- dev_printk(KERN_ERR, &mpt2sas_port_duplicate->port->dev,
- "deleting duplicate device at sas_addr(0x%016llx), phy(%d)!!!!\n",
- (unsigned long long)
- mpt2sas_port_duplicate->remote_identify.sas_address, phy_num);
- ioc->logging_level |= MPT_DEBUG_TRANSPORT;
- mpt2sas_transport_port_remove(ioc,
- mpt2sas_port_duplicate->remote_identify.sas_address,
- sas_node->sas_address);
- ioc->logging_level &= ~MPT_DEBUG_TRANSPORT;
+ list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
+ port_list) {
+ list_for_each_entry(phy_srch, &mpt2sas_port->phy_list,
+ port_siblings) {
+ if (phy_srch != mpt2sas_phy)
+ continue;
+ if (mpt2sas_port->num_phys == 1)
+ _transport_delete_port(ioc, mpt2sas_port);
+ else
+ _transport_delete_phy(ioc, mpt2sas_port,
+ mpt2sas_phy);
+ return;
+ }
+ }
}
/**
{
int i;
- for (i = 0; i < sas_node->num_phys; i++)
- if (sas_node->phy[i].remote_identify.sas_address == sas_address)
- if (sas_node->phy[i].phy_belongs_to_port)
- _transport_delete_duplicate_port(ioc, sas_node,
- sas_address, i);
+ for (i = 0; i < sas_node->num_phys; i++) {
+ if (sas_node->phy[i].remote_identify.sas_address != sas_address)
+ continue;
+ if (sas_node->phy[i].phy_belongs_to_port == 1)
+ _transport_del_phy_from_an_existing_port(ioc, sas_node,
+ &sas_node->phy[i]);
+ }
}
/**
mpt2sas_phy = &sas_node->phy[phy_number];
mpt2sas_phy->attached_handle = handle;
- if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
+ if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {
_transport_set_identify(ioc, handle,
&mpt2sas_phy->remote_identify);
- else
+ _transport_add_phy_to_an_existing_port(ioc, sas_node,
+ mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address);
+ } else
memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
sas_identify));
return 0;
}
-static int ncr53c8xx_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+static int ncr53c8xx_queue_command_lck (struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb;
unsigned long flags;
return sts;
}
+static DEF_SCSI_QCMD(ncr53c8xx_queue_command)
+
irqreturn_t ncr53c8xx_intr(int irq, void *dev_id)
{
unsigned long flags;
static int nsp32_proc_info (struct Scsi_Host *, char *, char **, off_t, int, int);
static int nsp32_detect (struct pci_dev *pdev);
-static int nsp32_queuecommand(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+static int nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static const char *nsp32_info (struct Scsi_Host *);
static int nsp32_release (struct Scsi_Host *);
return TRUE;
}
-static int nsp32_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
nsp32_target *target;
return 0;
}
+static DEF_SCSI_QCMD(nsp32_queuecommand)
+
/* initialize asic */
static int nsp32hw_init(nsp32_hw_data *data)
{
/* create a bio for continuation segment */
bio = bio_map_kern(req_q, or->cdb_cont.buff, or->cdb_cont.total_bytes,
GFP_KERNEL);
- if (unlikely(!bio))
- return -ENOMEM;
+ if (IS_ERR(bio))
+ return PTR_ERR(bio);
bio->bi_rw |= REQ_WRITE;
static int pas16_biosparam(struct scsi_device *, struct block_device *,
sector_t, int*);
static int pas16_detect(struct scsi_host_template *);
-static int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int pas16_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int pas16_bus_reset(Scsi_Cmnd *);
#ifndef CMD_PER_LUN
SCpnt->scsi_done(SCpnt);
}
-static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
+static int nsp_queuecommand_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
#ifdef NSP_DEBUG
return 0;
}
+static DEF_SCSI_QCMD(nsp_queuecommand)
+
/*
* setup PIO FIFO transfer mode and enable/disable to data out
*/
off_t offset,
int length,
int inout);
-static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
- void (* done)(struct scsi_cmnd *SCpnt));
+static int nsp_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *SCpnt);
/* Error handler */
/*static int nsp_eh_abort (struct scsi_cmnd *SCpnt);*/
}
static int
-SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+SYM53C500_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
int i;
int port_base = SCpnt->device->host->io_port;
return 0;
}
+static DEF_SCSI_QCMD(SYM53C500_queue)
+
static int
SYM53C500_host_reset(struct scsi_cmnd *SCpnt)
{
#include <linux/dma-mapping.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <scsi/libsas.h>
#include <scsi/scsi_tcq.h>
#include <scsi/sas_ata.h>
static unsigned int pmcraid_debug_log;
static unsigned int pmcraid_disable_aen;
static unsigned int pmcraid_log_level = IOASC_LOG_LEVEL_MUST;
+static unsigned int pmcraid_enable_msix;
/*
* Data structures to support multiple adapters by the LLD.
* SCSI_MLQUEUE_DEVICE_BUSY if device is busy
* SCSI_MLQUEUE_HOST_BUSY if host is busy
*/
-static int pmcraid_queuecommand(
+static int pmcraid_queuecommand_lck(
struct scsi_cmnd *scsi_cmd,
void (*done) (struct scsi_cmnd *)
)
return rc;
}
+static DEF_SCSI_QCMD(pmcraid_queuecommand)
+
/**
* pmcraid_open -char node "open" entry, allowed only users with admin access
*/
int rc;
struct pci_dev *pdev = pinstance->pdev;
- if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+ if ((pmcraid_enable_msix) &&
+ (pci_find_capability(pdev, PCI_CAP_ID_MSIX))) {
int num_hrrq = PMCRAID_NUM_MSIX_VECTORS;
struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS];
int i;
*/
#define PMCRAID_DRIVER_NAME "PMC MaxRAID"
#define PMCRAID_DEVFILE "pmcsas"
-#define PMCRAID_DRIVER_VERSION "2.0.3"
+#define PMCRAID_DRIVER_VERSION "1.0.3"
#define PMCRAID_DRIVER_DATE __DATE__
#define PMCRAID_FW_VERSION_1 0x002
__u8 lun[PMCRAID_LUN_LEN];
} __attribute__((packed, aligned(4)));
-/* extended configuration table sizes are of 64 bytes in size */
-#define PMCRAID_CFGTE_EXT_SIZE 32
+/* extended configuration table sizes are also of 32 bytes in size */
struct pmcraid_config_table_entry_ext {
struct pmcraid_config_table_entry cfgte;
- __u8 cfgte_ext[PMCRAID_CFGTE_EXT_SIZE];
};
/* resource types (config_table_entry.resource_type values) */
return 0;
}
-static int ppa_queuecommand(struct scsi_cmnd *cmd,
+static int ppa_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done) (struct scsi_cmnd *))
{
ppa_struct *dev = ppa_dev(cmd->device->host);
return 0;
}
+static DEF_SCSI_QCMD(ppa_queuecommand)
+
/*
* Apparently the disk->capacity attribute is off by 1 sector
* for all disk drives. We add the one here, but it should really
return 0;
}
-static int ps3rom_queuecommand(struct scsi_cmnd *cmd,
+static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct ps3rom_private *priv = shost_priv(cmd->device->host);
return 0;
}
+static DEF_SCSI_QCMD(ps3rom_queuecommand)
+
static int decode_lv1_status(u64 status, unsigned char *sense_key,
unsigned char *asc, unsigned char *ascq)
{
* context which is a big NO! NO!.
**************************************************************************/
static int
-qla1280_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+qla1280_queuecommand_lck(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
{
struct Scsi_Host *host = cmd->device->host;
struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
return status;
}
+static DEF_SCSI_QCMD(qla1280_queuecommand)
+
enum action {
ABORT_COMMAND,
DEVICE_RESET,
uint32_t enable_target_reset :1;
uint32_t enable_lip_full_login :1;
uint32_t enable_led_scheme :1;
- uint32_t inta_enabled :1;
uint32_t msi_enabled :1;
uint32_t msix_enabled :1;
uint32_t disable_serdes :1;
fcp_cmnd->additional_cdb_len |= 2;
int_to_scsilun(sp->cmd->device->lun, &fcp_cmnd->lun);
+ host_to_fcp_swap((uint8_t *)&fcp_cmnd->lun, sizeof(fcp_cmnd->lun));
memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len);
cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32(
skip_msi:
ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
- IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp);
+ ha->flags.msi_enabled ? 0 : IRQF_SHARED,
+ QLA2XXX_DRIVER_NAME, rsp);
if (ret) {
qla_printk(KERN_WARNING, ha,
"Failed to reserve interrupt %d already in use.\n",
ha->pdev->irq);
goto fail;
}
- ha->flags.inta_enabled = 1;
+
clear_risc_ints:
/*
goto queuing_error_fcp_cmnd;
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
+ host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
/* build FCP_CMND IU */
memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
static void qla2xxx_scan_start(struct Scsi_Host *);
static void qla2xxx_slave_destroy(struct scsi_device *);
-static int qla2xxx_queuecommand(struct scsi_cmnd *cmd,
- void (*fn)(struct scsi_cmnd *));
+static int qla2xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static int qla2xxx_eh_abort(struct scsi_cmnd *);
static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
static int qla2xxx_eh_target_reset(struct scsi_cmnd *);
}
static int
-qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
return 0;
}
+static DEF_SCSI_QCMD(qla2xxx_queuecommand)
+
/*
* qla2x00_eh_wait_on_command
{
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
srb_t *sp;
- int ret;
+ int ret = SUCCESS;
unsigned int id, lun;
unsigned long flags;
int wait = 0;
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
ha->gid_list_info_size = 8;
ha->optrom_size = OPTROM_SIZE_82XX;
+ ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
ha->isp_ops = &qla82xx_isp_ops;
ha->flash_conf_off = FARX_ACCESS_FLASH_CONF;
ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.03.04-k0"
+#define QLA2XXX_VERSION "8.03.05-k0"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3
-#define QLA_DRIVER_PATCH_VER 4
+#define QLA_DRIVER_PATCH_VER 5
#define QLA_DRIVER_BETA_VER 0
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
struct srb {
struct list_head list; /* (8) */
struct scsi_qla_host *ha; /* HA the SP is queued on */
- struct ddb_entry *ddb;
+ struct ddb_entry *ddb;
uint16_t flags; /* (1) Status flags. */
#define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */
struct scsi_cmnd *cmd; /* (4) SCSI command block */
dma_addr_t dma_handle; /* (4) for unmap of single transfers */
struct kref srb_ref; /* reference count for this srb */
- uint32_t fw_ddb_index;
uint8_t err_id; /* error id */
#define SRB_ERR_PORT 1 /* Request failed because "port down" */
#define SRB_ERR_LOOP 2 /* Request failed because "loop down" */
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/* mbox_sts[2] = Old ACB state
* mbox_sts[3] = new ACB state */
if ((mbox_sts[3] == ACB_STATE_VALID) &&
- (mbox_sts[2] == ACB_STATE_TENTATIVE))
+ ((mbox_sts[2] == ACB_STATE_TENTATIVE) ||
+ (mbox_sts[2] == ACB_STATE_ACQUIRING)))
set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
(mbox_sts[2] == ACB_STATE_VALID))
ret = pci_enable_msi(ha->pdev);
if (!ret) {
ret = request_irq(ha->pdev->irq, qla4_8xxx_msi_handler,
- IRQF_DISABLED|IRQF_SHARED, DRIVER_NAME, ha);
+ 0, DRIVER_NAME, ha);
if (!ret) {
DEBUG2(ql4_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
set_bit(AF_MSI_ENABLED, &ha->flags);
try_intx:
/* Trying INTx */
ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
- IRQF_DISABLED|IRQF_SHARED, DRIVER_NAME, ha);
+ IRQF_SHARED, DRIVER_NAME, ha);
if (!ret) {
DEBUG2(ql4_printk(KERN_INFO, ha, "INTx: Enabled.\n"));
set_bit(AF_INTx_ENABLED, &ha->flags);
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
*/
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (is_qla8022(ha)) {
- intr_status = readl(&ha->qla4_8xxx_reg->host_int);
- if (intr_status & ISRX_82XX_RISC_INT) {
- /* Service existing interrupt */
- DEBUG2(printk("scsi%ld: %s: "
- "servicing existing interrupt\n",
- ha->host_no, __func__));
- intr_status = readl(&ha->qla4_8xxx_reg->host_status);
- ha->isp_ops->interrupt_service_routine(ha, intr_status);
- clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
- if (test_bit(AF_INTERRUPTS_ON, &ha->flags) &&
- test_bit(AF_INTx_ENABLED, &ha->flags))
- qla4_8xxx_wr_32(ha,
- ha->nx_legacy_intr.tgt_mask_reg,
- 0xfbff);
- }
- } else {
+ if (!is_qla8022(ha)) {
intr_status = readl(&ha->reg->ctrl_status);
if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
/* Service existing interrupt */
return status;
mbox_cmd[0] = MBOX_CMD_ABORT_TASK;
- mbox_cmd[1] = srb->fw_ddb_index;
+ mbox_cmd[1] = srb->ddb->fw_ddb_index;
mbox_cmd[2] = index;
/* Immediate Command Enable */
mbox_cmd[5] = 0x01;
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2009 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/* Halt all the indiviual PEGs and other blocks of the ISP */
qla4_8xxx_rom_lock(ha);
+
+ /* mask all niu interrupts */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff);
+ /* disable xge rx/tx */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00);
+ /* disable xg1 rx/tx */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00);
+
+ /* halt sre */
+ val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_SRE + 0x1000, val & (~(0x1)));
+
+ /* halt epg */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_EPG + 0x1300, 0x1);
+
+ /* halt timers */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x0, 0x0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x8, 0x0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0);
+
+ /* halt pegs */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c, 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1);
+
+ /* big hammer */
+ msleep(1000);
if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
/* don't reset CAM block on reset */
qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff);
else
qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff);
+ /* reset ms */
+ val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4);
+ val |= (1 << 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val);
+
+ msleep(20);
+ /* unreset ms */
+ val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4);
+ val &= ~(1 << 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val);
+ msleep(20);
+
qla4_8xxx_rom_unlock(ha);
/* Read the signature value from the flash.
static int
qla4_8xxx_load_from_flash(struct scsi_qla_host *ha, uint32_t image_start)
{
- int i;
+ int i, rval = 0;
long size = 0;
long flashaddr, memaddr;
u64 data;
u32 high, low;
flashaddr = memaddr = ha->hw.flt_region_bootload;
- size = (image_start - flashaddr)/8;
+ size = (image_start - flashaddr) / 8;
DEBUG2(printk("scsi%ld: %s: bootldr=0x%lx, fw_image=0x%x\n",
ha->host_no, __func__, flashaddr, image_start));
if ((qla4_8xxx_rom_fast_read(ha, flashaddr, (int *)&low)) ||
(qla4_8xxx_rom_fast_read(ha, flashaddr + 4,
(int *)&high))) {
- return -1;
+ rval = -1;
+ goto exit_load_from_flash;
}
data = ((u64)high << 32) | low ;
- qla4_8xxx_pci_mem_write_2M(ha, memaddr, &data, 8);
+ rval = qla4_8xxx_pci_mem_write_2M(ha, memaddr, &data, 8);
+ if (rval)
+ goto exit_load_from_flash;
+
flashaddr += 8;
memaddr += 8;
- if (i%0x1000 == 0)
+ if (i % 0x1000 == 0)
msleep(1);
}
qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
read_unlock(&ha->hw_lock);
- return 0;
+exit_load_from_flash:
+ return rval;
}
static int qla4_8xxx_load_fw(struct scsi_qla_host *ha, uint32_t image_start)
/*
- * QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2010 QLogic Corporation
*
- * See LICENSE.qla2xxx for copyright and licensing details.
+ * See LICENSE.qla4xxx for copyright and licensing details.
*/
#ifndef __QLA_NX_H
#define __QLA_NX_H
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
/*
* SCSI host template entry points
*/
-static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
- void (*done) (struct scsi_cmnd *));
+static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
* completion handling). Unfortunely, it sometimes calls the scheduler
* in interrupt context which is a big NO! NO!.
**/
-static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
+static int qla4xxx_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
return 0;
}
+static DEF_SCSI_QCMD(qla4xxx_queuecommand)
+
/**
* qla4xxx_mem_free - frees memory allocated to adapter
* @ha: Pointer to host adapter structure.
dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
/* don't poll if reset is going on */
- if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags)) {
+ if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags))) {
if (dev_state == QLA82XX_DEV_NEED_RESET &&
!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
- printk("scsi%ld: %s: HW State: NEED RESET!\n",
- ha->host_no, __func__);
- set_bit(DPC_RESET_HA, &ha->dpc_flags);
- qla4xxx_wake_dpc(ha);
- qla4xxx_mailbox_premature_completion(ha);
+ if (!ql4xdontresethba) {
+ ql4_printk(KERN_INFO, ha, "%s: HW State: "
+ "NEED RESET!\n", __func__);
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ qla4xxx_wake_dpc(ha);
+ qla4xxx_mailbox_premature_completion(ha);
+ }
} else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
!test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
- printk("scsi%ld: %s: HW State: NEED QUIES!\n",
- ha->host_no, __func__);
+ ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n",
+ __func__);
set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags);
qla4xxx_wake_dpc(ha);
} else {
if (!test_bit(AF_ONLINE, &ha->flags)) {
ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
+ if (is_qla8022(ha) && ql4xdontresethba) {
+ /* Put the device in failed state. */
+ DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
+ qla4_8xxx_idc_lock(ha);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+ QLA82XX_DEV_FAILED);
+ qla4_8xxx_idc_unlock(ha);
+ }
ret = -ENODEV;
goto probe_failed;
}
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.02.00-k4"
+#define QLA4XXX_DRIVER_VERSION "5.02.00-k5"
* Queued command
*/
-int qlogicfas408_queuecommand(struct scsi_cmnd *cmd,
+static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done) (struct scsi_cmnd *))
{
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
return 0;
}
+DEF_SCSI_QCMD(qlogicfas408_queuecommand)
+
/*
* Return bios parameters
*/
#define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0])
irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id);
-int qlogicfas408_queuecommand(struct scsi_cmnd * cmd,
- void (*done) (struct scsi_cmnd *));
+int qlogicfas408_queuecommand(struct Scsi_Host *h, struct scsi_cmnd * cmd);
int qlogicfas408_biosparam(struct scsi_device * disk,
struct block_device *dev,
sector_t capacity, int ip[]);
*
* "This code must fly." -davem
*/
-static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *))
+static int qlogicpti_queuecommand_lck(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = Cmnd->device->host;
struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
return 1;
}
+static DEF_SCSI_QCMD(qlogicpti_queuecommand)
+
static int qlogicpti_return_status(struct Status_Entry *sts, int id)
{
int host_status = DID_ERROR;
* Description: a serial number identifies a request for error recovery
* and debugging purposes. Protected by the Host_Lock of host.
*/
-static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{
cmd->serial_number = host->cmd_serial_number++;
if (cmd->serial_number == 0)
cmd->serial_number = host->cmd_serial_number++;
}
+EXPORT_SYMBOL(scsi_cmd_get_serial);
/**
* scsi_dispatch_command - Dispatch a command to the low-level driver.
int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
{
struct Scsi_Host *host = cmd->device->host;
- unsigned long flags = 0;
unsigned long timeout;
int rtn = 0;
goto out;
}
- spin_lock_irqsave(host->host_lock, flags);
- /*
- * AK: unlikely race here: for some reason the timer could
- * expire before the serial number is set up below.
- *
- * TODO: kill serial or move to blk layer
- */
- scsi_cmd_get_serial(host, cmd);
-
if (unlikely(host->shost_state == SHOST_DEL)) {
cmd->result = (DID_NO_CONNECT << 16);
scsi_done(cmd);
} else {
trace_scsi_dispatch_cmd_start(cmd);
- rtn = host->hostt->queuecommand(cmd, scsi_done);
+ cmd->scsi_done = scsi_done;
+ rtn = host->hostt->queuecommand(host, cmd);
}
- spin_unlock_irqrestore(host->host_lock, flags);
+
if (rtn) {
trace_scsi_dispatch_cmd_error(cmd, rtn);
if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
devip->sense_buff[5] = (ret >> 8) & 0xff;
devip->sense_buff[6] = ret & 0xff;
}
+ scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
return check_condition_result;
}
}
static
-int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
+int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
{
unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
int len, k;
(delay_override ? 0 : scsi_debug_delay));
}
+static DEF_SCSI_QCMD(scsi_debug_queuecommand)
+
static struct scsi_host_template sdebug_driver_template = {
.proc_info = scsi_debug_proc_info,
.proc_name = sdebug_proc_name,
return rtn;
}
-static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
{
if (!scmd->device->host->hostt->eh_abort_handler)
return FAILED;
return scmd->device->host->hostt->eh_abort_handler(scmd);
}
-/**
- * scsi_try_to_abort_cmd - Ask host to abort a running command.
- * @scmd: SCSI cmd to abort from Lower Level.
- *
- * Notes:
- * This function will not return until the user's completion function
- * has been called. there is no timeout on this operation. if the
- * author of the low-level driver wishes this operation to be timed,
- * they can provide this facility themselves. helper functions in
- * scsi_error.c can be supplied to make this easier to do.
- */
-static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
-{
- /*
- * scsi_done was called just after the command timed out and before
- * we had a chance to process it. (db)
- */
- if (scmd->serial_number == 0)
- return SUCCESS;
- return __scsi_try_to_abort_cmd(scmd);
-}
-
static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
{
- if (__scsi_try_to_abort_cmd(scmd) != SUCCESS)
+ if (scsi_try_to_abort_cmd(scmd) != SUCCESS)
if (scsi_try_bus_device_reset(scmd) != SUCCESS)
if (scsi_try_target_reset(scmd) != SUCCESS)
if (scsi_try_bus_reset(scmd) != SUCCESS)
struct Scsi_Host *shost = sdev->host;
DECLARE_COMPLETION_ONSTACK(done);
unsigned long timeleft;
- unsigned long flags;
struct scsi_eh_save ses;
int rtn;
scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
shost->eh_action = &done;
- spin_lock_irqsave(shost->host_lock, flags);
scsi_log_send(scmd);
- shost->hostt->queuecommand(scmd, scsi_eh_done);
- spin_unlock_irqrestore(shost->host_lock, flags);
+ scmd->scsi_done = scsi_eh_done;
+ shost->hostt->queuecommand(shost, scmd);
timeleft = wait_for_completion_timeout(&done, timeout);
struct list_head *work_q,
struct list_head *done_q)
{
- struct scsi_cmnd *scmd, *tgtr_scmd, *next;
- unsigned int id = 0;
- int rtn;
+ LIST_HEAD(tmp_list);
- do {
- tgtr_scmd = NULL;
- list_for_each_entry(scmd, work_q, eh_entry) {
- if (id == scmd_id(scmd)) {
- tgtr_scmd = scmd;
- break;
- }
- }
- if (!tgtr_scmd) {
- /* not one exactly equal; find the next highest */
- list_for_each_entry(scmd, work_q, eh_entry) {
- if (scmd_id(scmd) > id &&
- (!tgtr_scmd ||
- scmd_id(tgtr_scmd) > scmd_id(scmd)))
- tgtr_scmd = scmd;
- }
- }
- if (!tgtr_scmd)
- /* no more commands, that's it */
- break;
+ list_splice_init(work_q, &tmp_list);
+
+ while (!list_empty(&tmp_list)) {
+ struct scsi_cmnd *next, *scmd;
+ int rtn;
+ unsigned int id;
+
+ scmd = list_entry(tmp_list.next, struct scsi_cmnd, eh_entry);
+ id = scmd_id(scmd);
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset "
"to target %d\n",
current->comm, id));
- rtn = scsi_try_target_reset(tgtr_scmd);
- if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
- list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
- if (id == scmd_id(scmd))
- if (!scsi_device_online(scmd->device) ||
- rtn == FAST_IO_FAIL ||
- !scsi_eh_tur(tgtr_scmd))
- scsi_eh_finish_cmd(scmd,
- done_q);
- }
- } else
+ rtn = scsi_try_target_reset(scmd);
+ if (rtn != SUCCESS && rtn != FAST_IO_FAIL)
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Target reset"
" failed target: "
"%d\n",
current->comm, id));
- id++;
- } while(id != 0);
+ list_for_each_entry_safe(scmd, next, &tmp_list, eh_entry) {
+ if (scmd_id(scmd) != id)
+ continue;
+
+ if ((rtn == SUCCESS || rtn == FAST_IO_FAIL)
+ && (!scsi_device_online(scmd->device) ||
+ rtn == FAST_IO_FAIL || !scsi_eh_tur(scmd)))
+ scsi_eh_finish_cmd(scmd, done_q);
+ else
+ /* push back on work queue for further processing */
+ list_move(&scmd->eh_entry, work_q);
+ }
+ }
return list_empty(work_q);
}
}
if (scsi_target_is_busy(starget)) {
- if (list_empty(&sdev->starved_entry)) {
+ if (list_empty(&sdev->starved_entry))
list_add_tail(&sdev->starved_entry,
&shost->starved_list);
- return 0;
- }
+ return 0;
}
/* We're OK to process the command, so we can't be starved */
INIT_LIST_HEAD(&cmd->eh_entry);
- /*
- * Set the serial numbers back to zero
- */
- cmd->serial_number = 0;
-
atomic_inc(&cmd->device->iodone_cnt);
if (cmd->result)
atomic_inc(&cmd->device->ioerr_cnt);
MODULE_DESCRIPTION("iSCSI Transport Interface");
MODULE_LICENSE("GPL");
MODULE_VERSION(ISCSI_TRANSPORT_VERSION);
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_ISCSI);
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/delay.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/string_helpers.h>
#include <linux/async.h>
* quietly refuse to do anything to a changed disc until
* the changed bit has been reset
*/
- /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
+ /* printk("SCSI disk has been changed or is not present. Prohibiting further I/O.\n"); */
goto out;
}
*/
if (!scsi_device_online(sdp)) {
set_media_not_present(sdkp);
- retval = 1;
goto out;
}
if (retval) {
set_media_not_present(sdkp);
- retval = 1;
goto out;
}
*/
sdkp->media_present = 1;
- retval = sdp->changed;
- sdp->changed = 0;
out:
- if (retval != sdkp->previous_state)
+ /*
+ * Report a media change under the following conditions:
+ *
+ * Medium is present now and wasn't present before.
+ * Medium wasn't present before and is present now.
+ * Medium was present at all times, but it changed while
+ * we weren't looking (sdp->changed is set).
+ *
+ * If there was no medium before and there is no medium now then
+ * don't report a change, even if a medium was inserted and removed
+ * while we weren't looking.
+ */
+ retval = (sdkp->media_present != sdkp->previous_state ||
+ (sdkp->media_present && sdp->changed));
+ if (retval)
sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
- sdkp->previous_state = retval;
+ sdkp->previous_state = sdkp->media_present;
+
+ /* sdp->changed indicates medium was changed or is not present */
+ sdp->changed = !sdkp->media_present;
kfree(sshdr);
return retval;
}
u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512);
u64 bad_lba;
int info_valid;
+ /*
+ * resid is optional but mostly filled in. When it's unused,
+ * its value is zero, so we assume the whole buffer transferred
+ */
+ unsigned int transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd);
+ unsigned int good_bytes;
if (scmd->request->cmd_type != REQ_TYPE_FS)
return 0;
/* This computation should always be done in terms of
* the resolution of the device's medium.
*/
- return (bad_lba - start_lba) * scmd->device->sector_size;
+ good_bytes = (bad_lba - start_lba) * scmd->device->sector_size;
+ return min(good_bytes, transferred);
}
/**
int old_rcd = sdkp->RCD;
int old_dpofua = sdkp->DPOFUA;
- if (sdp->skip_ms_page_8)
- goto defaults;
-
- if (sdp->type == TYPE_RBC) {
+ if (sdp->skip_ms_page_8) {
+ if (sdp->type == TYPE_RBC)
+ goto defaults;
+ else {
+ modepage = 0x3F;
+ dbd = 0;
+ }
+ } else if (sdp->type == TYPE_RBC) {
modepage = 6;
dbd = 8;
} else {
*/
if (len < 3)
goto bad_sense;
- if (len > 20)
- len = 20;
-
- /* Take headers and block descriptors into account */
- len += data.header_length + data.block_descriptor_length;
- if (len > SD_BUF_SIZE)
- goto bad_sense;
+ else if (len > SD_BUF_SIZE) {
+ sd_printk(KERN_NOTICE, sdkp, "Truncating mode parameter "
+ "data from %d to %d bytes\n", len, SD_BUF_SIZE);
+ len = SD_BUF_SIZE;
+ }
/* Get the data */
res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr);
if (scsi_status_is_good(res)) {
int offset = data.header_length + data.block_descriptor_length;
- if (offset >= SD_BUF_SIZE - 2) {
- sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n");
- goto defaults;
+ while (offset < len) {
+ u8 page_code = buffer[offset] & 0x3F;
+ u8 spf = buffer[offset] & 0x40;
+
+ if (page_code == 8 || page_code == 6) {
+ /* We're interested only in the first 3 bytes.
+ */
+ if (len - offset <= 2) {
+ sd_printk(KERN_ERR, sdkp, "Incomplete "
+ "mode parameter data\n");
+ goto defaults;
+ } else {
+ modepage = page_code;
+ goto Page_found;
+ }
+ } else {
+ /* Go to the next page */
+ if (spf && len - offset > 3)
+ offset += 4 + (buffer[offset+2] << 8) +
+ buffer[offset+3];
+ else if (!spf && len - offset > 1)
+ offset += 2 + buffer[offset+1];
+ else {
+ sd_printk(KERN_ERR, sdkp, "Incomplete "
+ "mode parameter data\n");
+ goto defaults;
+ }
+ }
}
- if ((buffer[offset] & 0x3f) != modepage) {
+ if (modepage == 0x3F) {
+ sd_printk(KERN_ERR, sdkp, "No Caching mode page "
+ "present\n");
+ goto defaults;
+ } else if ((buffer[offset] & 0x3f) != modepage) {
sd_printk(KERN_ERR, sdkp, "Got wrong page\n");
goto defaults;
}
-
+ Page_found:
if (modepage == 8) {
sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0);
sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0);
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static const char *verstr = "20100829";
+static const char *verstr = "20101219";
#include <linux/module.h>
b_size = PAGE_SIZE << order;
} else {
for (b_size = PAGE_SIZE, order = 0;
- order < ST_MAX_ORDER && b_size < new_size;
+ order < ST_MAX_ORDER &&
+ max_segs * (PAGE_SIZE << order) < new_size;
order++, b_size *= 2)
; /* empty */
+ STbuffer->reserved_page_order = order;
}
if (max_segs * (PAGE_SIZE << order) < new_size) {
if (order == ST_MAX_ORDER)
segs++;
}
STbuffer->b_data = page_address(STbuffer->reserved_pages[0]);
- STbuffer->reserved_page_order = order;
return 1;
}
}
static int
-stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+stex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct st_hba *hba;
struct Scsi_Host *host;
return 0;
}
+static DEF_SCSI_QCMD(stex_queuecommand)
+
static void stex_scsi_done(struct st_ccb *ccb)
{
struct scsi_cmnd *cmd = ccb->cmd;
*/
/* Only make static if a wrapper function is used */
-static int NCR5380_queue_command(struct scsi_cmnd *cmd,
+static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
SETUP_HOSTDATA(cmd->device->host);
return 0;
}
+static DEF_SCSI_QCMD(NCR5380_queue_command)
+
/*
* Function : NCR5380_main (void)
*
static int sun3scsi_detect (struct scsi_host_template *);
static const char *sun3scsi_info (struct Scsi_Host *);
static int sun3scsi_bus_reset(struct scsi_cmnd *);
-static int sun3scsi_queue_command(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+static int sun3scsi_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int sun3scsi_release (struct Scsi_Host *);
#ifndef CMD_PER_LUN
return info;
}
-int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int sym53c416_queuecommand_lck(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
int base;
unsigned long flags = 0;
return 0;
}
+DEF_SCSI_QCMD(sym53c416_queuecommand)
+
static int sym53c416_host_reset(Scsi_Cmnd *SCpnt)
{
int base;
static int sym53c416_detect(struct scsi_host_template *);
static const char *sym53c416_info(struct Scsi_Host *);
static int sym53c416_release(struct Scsi_Host *);
-static int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int sym53c416_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int sym53c416_host_reset(Scsi_Cmnd *);
static int sym53c416_bios_param(struct scsi_device *, struct block_device *,
sector_t, int *);
* queuecommand method. Entered with the host adapter lock held and
* interrupts disabled.
*/
-static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
+static int sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct sym_hcb *np = SYM_SOFTC_PTR(cmd);
return 0;
}
+static DEF_SCSI_QCMD(sym53c8xx_queue_command)
+
/*
* Linux entry point of the interrupt handler.
*/
static int t128_biosparam(struct scsi_device *, struct block_device *,
sector_t, int*);
static int t128_detect(struct scsi_host_template *);
-static int t128_queue_command(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+static int t128_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int t128_bus_reset(struct scsi_cmnd *);
#ifndef CMD_PER_LUN
return;
}
-static int DC390_queuecommand(struct scsi_cmnd *cmd,
+static int DC390_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct scsi_device *sdev = cmd->device;
return SCSI_MLQUEUE_DEVICE_BUSY;
}
+static DEF_SCSI_QCMD(DC390_queuecommand)
+
static void dc390_dumpinfo (struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
{
struct pci_dev *pdev;
static int u14_34f_detect(struct scsi_host_template *);
static int u14_34f_release(struct Scsi_Host *);
-static int u14_34f_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+static int u14_34f_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int u14_34f_eh_abort(struct scsi_cmnd *);
static int u14_34f_eh_host_reset(struct scsi_cmnd *);
static int u14_34f_bios_param(struct scsi_device *, struct block_device *,
}
-static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) {
+static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) {
unsigned int i, j, k;
struct mscp *cpp;
return 0;
}
+static DEF_SCSI_QCMD(u14_34f_queuecommand)
+
static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
unsigned int i, j;
mscp->transfer_data_length = transfer_length;
}
-static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
+static int ultrastor_queuecommand_lck(struct scsi_cmnd *SCpnt,
void (*done) (struct scsi_cmnd *))
{
struct mscp *my_mscp;
return 0;
}
+static DEF_SCSI_QCMD(ultrastor_queuecommand)
+
/* This code must deal with 2 cases:
1. The command has not been written to the OGM. In this case, set
static int ultrastor_detect(struct scsi_host_template *);
static const char *ultrastor_info(struct Scsi_Host *shpnt);
-static int ultrastor_queuecommand(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+static int ultrastor_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int ultrastor_abort(struct scsi_cmnd *);
static int ultrastor_host_reset(struct scsi_cmnd *);
static int ultrastor_biosparam(struct scsi_device *, struct block_device *,
return 0;
}
-static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = cmd->device->host;
struct pvscsi_adapter *adapter = shost_priv(host);
return 0;
}
+static DEF_SCSI_QCMD(pvscsi_queue)
+
static int pvscsi_abort(struct scsi_cmnd *cmd)
{
struct pvscsi_adapter *adapter = shost_priv(cmd->device->host);
msg[1] = offset;
}
-int
-wd33c93_queuecommand(struct scsi_cmnd *cmd,
+static int
+wd33c93_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct WD33C93_hostdata *hostdata;
return 0;
}
+DEF_SCSI_QCMD(wd33c93_queuecommand)
+
/*
* This routine attempts to start a scsi command. If the host_card is
* already connected, we give up immediately. Otherwise, look through
void wd33c93_init (struct Scsi_Host *instance, const wd33c93_regs regs,
dma_setup_t setup, dma_stop_t stop, int clock_freq);
int wd33c93_abort (struct scsi_cmnd *cmd);
-int wd33c93_queuecommand (struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *));
+int wd33c93_queuecommand (struct Scsi_Host *h, struct scsi_cmnd *cmd);
void wd33c93_intr (struct Scsi_Host *instance);
int wd33c93_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
int wd33c93_host_reset (struct scsi_cmnd *);
return IRQ_HANDLED;
}
-static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
+static int wd7000_queuecommand_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
Scb *scb;
return 0;
}
+static DEF_SCSI_QCMD(wd7000_queuecommand)
+
static int wd7000_diagnostics(Adapter * host, int code)
{
static IcbDiag icb = { ICB_OP_DIAGNOSTICS };
.device = uart_console_device,
.setup = serial8250_console_setup,
.early_setup = serial8250_console_early_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER | CON_ANYTIME,
.index = -1,
.data = &serial8250_reg,
};
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
-#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
static void kgdboc_restore_input(void)
{
- schedule_work(&kgdboc_restore_input_work);
+ if (likely(system_state == SYSTEM_RUNNING))
+ schedule_work(&kgdboc_restore_input_work);
}
static int kgdboc_register_kbd(char **cptr)
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
- u32 mul = 0x3600;
- u32 ps = 0x10;
+ u32 ps, mul;
switch (termios->c_cflag & CSIZE) {
case CS5:
baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
quot = 1;
+ ps = 0x10;
+ mul = 0x3600;
switch (baud) {
case 3500000:
mul = 0x3345;
ps = 0xC;
break;
- case 3000000:
- mul = 0x2EE0;
- break;
- case 2500000:
- mul = 0x2710;
- break;
- case 2000000:
- mul = 0x1F40;
- break;
case 1843200:
mul = 0x2400;
break;
+ case 3000000:
+ case 2500000:
+ case 2000000:
case 1500000:
- mul = 0x1770;
- break;
case 1000000:
- mul = 0xFA0;
- break;
case 500000:
- mul = 0x7D0;
+ /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */
+ mul = baud / 500000 * 0x9C4;
break;
default:
/* Use uart_get_divisor to get quot for other baud rates */
#include <linux/console.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
#include <linux/serial_core.h>
list_add(&clk->sibling, &root_clks);
list_add(&clk->node, &clock_list);
+
+#ifdef CONFIG_SH_CLK_CPG_LEGACY
if (clk->ops && clk->ops->init)
clk->ops->init(clk);
+#endif
out_unlock:
mutex_unlock(&clock_list_sem);
EXPORT_SYMBOL_GPL(clk_get_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- return clk_set_rate_ex(clk, rate, 0);
-}
-EXPORT_SYMBOL_GPL(clk_set_rate);
-
-int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
{
int ret = -EOPNOTSUPP;
unsigned long flags;
spin_lock_irqsave(&clock_lock, flags);
if (likely(clk->ops && clk->ops->set_rate)) {
- ret = clk->ops->set_rate(clk, rate, algo_id);
+ ret = clk->ops->set_rate(clk, rate);
if (ret != 0)
goto out_unlock;
} else {
return ret;
}
-EXPORT_SYMBOL_GPL(clk_set_rate_ex);
+EXPORT_SYMBOL_GPL(clk_set_rate);
int clk_set_parent(struct clk *clk, struct clk *parent)
{
clkp->ops->set_parent(clkp,
clkp->parent);
if (likely(clkp->ops->set_rate))
- clkp->ops->set_rate(clkp,
- rate, NO_CHANGE);
+ clkp->ops->set_rate(clkp, rate);
else if (likely(clkp->ops->recalc))
clkp->rate = clkp->ops->recalc(clkp);
}
return 0;
}
-static int sh_clk_div6_set_rate(struct clk *clk,
- unsigned long rate, int algo_id)
+static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long value;
int idx;
unsigned long value;
int ret;
- ret = sh_clk_div6_set_rate(clk, clk->rate, 0);
+ ret = sh_clk_div6_set_rate(clk, clk->rate);
if (ret == 0) {
value = __raw_readl(clk->enable_reg);
value &= ~0x100; /* clear stop bit to enable clock */
return 0;
}
-static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
{
struct clk_div4_table *d4t = clk->priv;
unsigned long value;
xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS;
if (xfer->tx_buf) {
+ /* tx_buf is a const void* where we need a void * for the dma
+ * mapping */
+ void *nonconst_tx = (void *)xfer->tx_buf;
+
xfer->tx_dma = dma_map_single(dev,
- (void *) xfer->tx_buf, xfer->len,
+ nonconst_tx, xfer->len,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, xfer->tx_dma))
return -ENOMEM;
{
while (dws->write(dws))
dws->read(dws);
+ /*
+ * There is a possibility that the last word of a transaction
+ * will be lost if data is not ready. Re-read to solve this issue.
+ */
+ dws->read(dws);
transfer_complete(dws);
}
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4315) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BCM_GVC, 0x4318) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
#define ASUS_OLED_DEVICE_ATTR(_file) dev_attr_asus_oled_##_file
-static DEVICE_ATTR(asus_oled_enabled, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(asus_oled_enabled, S_IWUSR | S_IRUGO,
get_enabled, set_enabled);
-static DEVICE_ATTR(asus_oled_picture, S_IWUGO , NULL, set_picture);
+static DEVICE_ATTR(asus_oled_picture, S_IWUSR , NULL, set_picture);
-static DEVICE_ATTR(enabled, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO,
class_get_enabled, class_set_enabled);
-static DEVICE_ATTR(picture, S_IWUGO, NULL, class_set_picture);
+static DEVICE_ATTR(picture, S_IWUSR, NULL, class_set_picture);
static int asus_oled_probe(struct usb_interface *interface,
const struct usb_device_id *id)
return;
batman_if->if_status = IF_TO_BE_REMOVED;
-
- /* caller must take if_list_lock */
- list_del_rcu(&batman_if->list);
synchronize_rcu();
sysfs_del_hardif(&batman_if->hardif_obj);
hardif_put(batman_if);
void hardif_remove_interfaces(void)
{
struct batman_if *batman_if, *batman_if_tmp;
+ struct list_head if_queue;
+
+ INIT_LIST_HEAD(&if_queue);
- rtnl_lock();
spin_lock(&if_list_lock);
list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) {
- hardif_remove_interface(batman_if);
+ list_del_rcu(&batman_if->list);
+ list_add_tail(&batman_if->list, &if_queue);
}
spin_unlock(&if_list_lock);
+
+ rtnl_lock();
+ list_for_each_entry_safe(batman_if, batman_if_tmp, &if_queue, list) {
+ hardif_remove_interface(batman_if);
+ }
rtnl_unlock();
}
break;
case NETDEV_UNREGISTER:
spin_lock(&if_list_lock);
- hardif_remove_interface(batman_if);
+ list_del_rcu(&batman_if->list);
spin_unlock(&if_list_lock);
+
+ hardif_remove_interface(batman_if);
break;
case NETDEV_CHANGEMTU:
if (batman_if->soft_iface)
struct bat_priv *priv = netdev_priv(soft_iface);
/* check if enough space is available for pulling, and pull */
- if (!pskb_may_pull(skb, hdr_size)) {
- kfree_skb(skb);
- return;
- }
+ if (!pskb_may_pull(skb, hdr_size))
+ goto dropped;
+
skb_pull_rcsum(skb, hdr_size);
/* skb_set_mac_header(skb, -sizeof(struct ethhdr));*/
/* skb->dev & skb->pkt_type are set here */
+ if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
+ goto dropped;
skb->protocol = eth_type_trans(skb, soft_iface);
/* should not be neccesary anymore as we use skb_pull_rcsum()
soft_iface->last_rx = jiffies;
netif_rx(skb);
+ return;
+
+dropped:
+ kfree_skb(skb);
+ return;
}
#ifdef HAVE_NET_DEVICE_OPS
Contact Info:
=============
-Brett Rudley brudley@broadcom.com
-Henry Ptasinski henryp@broadcom.com
-Dowan Kim dowan@broadcom.com
+Brett Rudley brudley@broadcom.com
+Henry Ptasinski henryp@broadcom.com
+Dowan Kim dowan@broadcom.com
+Roland Vossen rvossen@broadcom.com
+Arend van Spriel arend@broadcom.com
Brett Rudley <brudley@broadcom.com>
Henry Ptasinski <henryp@broadcom.com>
Dowan Kim <dowan@broadcom.com>
+Roland Vossen <rvossen@broadcom.com>
+Arend van Spriel <arend@broadcom.com>
usbduxsub_tmp->inBuffer = NULL;
kfree(usbduxsub_tmp->insnBuffer);
usbduxsub_tmp->insnBuffer = NULL;
- kfree(usbduxsub_tmp->inBuffer);
- usbduxsub_tmp->inBuffer = NULL;
+ kfree(usbduxsub_tmp->outBuffer);
+ usbduxsub_tmp->outBuffer = NULL;
kfree(usbduxsub_tmp->dac_commands);
usbduxsub_tmp->dac_commands = NULL;
kfree(usbduxsub_tmp->dux_commands);
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/kref.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/uaccess.h>
t->value = temp; \
return count; \
} \
- static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+ static DEVICE_ATTR(value, S_IWUSR | S_IRUGO, show_##value, set_##value);
show_int(enable);
show_int(offline);
struct go7007 *go = i2c_get_adapdata(adapter);
struct v4l2_device *v4l2_dev = &go->v4l2_dev;
- if (v4l2_i2c_new_subdev(v4l2_dev, adapter, NULL, type, addr, NULL))
+ if (v4l2_i2c_new_subdev(v4l2_dev, adapter, type, addr, NULL))
return 0;
printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", type);
/* Static decl */
static int storvsc_probe(struct device *dev);
-static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
- void (*done)(struct scsi_cmnd *));
+static int storvsc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd);
static int storvsc_device_alloc(struct scsi_device *);
static int storvsc_device_configure(struct scsi_device *);
static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd);
/*
* storvsc_queuecommand - Initiate command processing
*/
-static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
+static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
void (*done)(struct scsi_cmnd *))
{
int ret;
return ret;
}
+static DEF_SCSI_QCMD(storvsc_queuecommand)
+
static int storvsc_merge_bvec(struct request_queue *q,
struct bvec_merge_data *bmd, struct bio_vec *bvec)
{
adis16220_write_reset, 0);
#define IIO_DEV_ATTR_CAPTURE(_store) \
- IIO_DEVICE_ATTR(capture, S_IWUGO, NULL, _store, 0)
+ IIO_DEVICE_ATTR(capture, S_IWUSR, NULL, _store, 0)
static IIO_DEV_ATTR_CAPTURE(adis16220_write_capture);
#include <linux/uaccess.h>
#include <linux/firmware.h>
#include <linux/ioctl.h>
-#include <linux/smp_lock.h>
#ifdef CONFIG_MRST_RAR_HANDLER
#include <linux/rar_register.h>
#include "../../../drivers/staging/memrar/memrar.h"
dbufs->output_bytes_produced = total_output;
str_info->status = str_info->prev;
str_info->prev = STREAM_DECODE;
- str_info->decode_ibuf = NULL;
kfree(str_info->decode_ibuf);
+ str_info->decode_ibuf = NULL;
return retval;
}
/* This is always called with scsi_lock(host) held */
//----- queuecommand() ---------------------
-static int queuecommand(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *))
+static int queuecommand_lck(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *))
{
struct us_data *us = host_to_us(srb->device->host);
return 0;
}
+static DEF_SCSI_QCMD(queuecommand)
+
/***********************************************************************
* Error handling functions
***********************************************************************/
VARIAX_PARAM_R(float, mix1);
VARIAX_PARAM_R(int, pickup_wiring);
-static DEVICE_ATTR(tweak, S_IWUGO | S_IRUGO, pod_get_tweak, pod_set_tweak);
-static DEVICE_ATTR(wah_position, S_IWUGO | S_IRUGO, pod_get_wah_position,
+static DEVICE_ATTR(tweak, S_IWUSR | S_IRUGO, pod_get_tweak, pod_set_tweak);
+static DEVICE_ATTR(wah_position, S_IWUSR | S_IRUGO, pod_get_wah_position,
pod_set_wah_position);
-static DEVICE_ATTR(compression_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(compression_gain, S_IWUSR | S_IRUGO,
pod_get_compression_gain, pod_set_compression_gain);
-static DEVICE_ATTR(vol_pedal_position, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(vol_pedal_position, S_IWUSR | S_IRUGO,
pod_get_vol_pedal_position, pod_set_vol_pedal_position);
-static DEVICE_ATTR(compression_threshold, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(compression_threshold, S_IWUSR | S_IRUGO,
pod_get_compression_threshold,
pod_set_compression_threshold);
-static DEVICE_ATTR(pan, S_IWUGO | S_IRUGO, pod_get_pan, pod_set_pan);
-static DEVICE_ATTR(amp_model_setup, S_IWUGO | S_IRUGO, pod_get_amp_model_setup,
+static DEVICE_ATTR(pan, S_IWUSR | S_IRUGO, pod_get_pan, pod_set_pan);
+static DEVICE_ATTR(amp_model_setup, S_IWUSR | S_IRUGO, pod_get_amp_model_setup,
pod_set_amp_model_setup);
-static DEVICE_ATTR(amp_model, S_IWUGO | S_IRUGO, pod_get_amp_model,
+static DEVICE_ATTR(amp_model, S_IWUSR | S_IRUGO, pod_get_amp_model,
pod_set_amp_model);
-static DEVICE_ATTR(drive, S_IWUGO | S_IRUGO, pod_get_drive, pod_set_drive);
-static DEVICE_ATTR(bass, S_IWUGO | S_IRUGO, pod_get_bass, pod_set_bass);
-static DEVICE_ATTR(mid, S_IWUGO | S_IRUGO, pod_get_mid, pod_set_mid);
-static DEVICE_ATTR(lowmid, S_IWUGO | S_IRUGO, pod_get_lowmid, pod_set_lowmid);
-static DEVICE_ATTR(treble, S_IWUGO | S_IRUGO, pod_get_treble, pod_set_treble);
-static DEVICE_ATTR(highmid, S_IWUGO | S_IRUGO, pod_get_highmid,
+static DEVICE_ATTR(drive, S_IWUSR | S_IRUGO, pod_get_drive, pod_set_drive);
+static DEVICE_ATTR(bass, S_IWUSR | S_IRUGO, pod_get_bass, pod_set_bass);
+static DEVICE_ATTR(mid, S_IWUSR | S_IRUGO, pod_get_mid, pod_set_mid);
+static DEVICE_ATTR(lowmid, S_IWUSR | S_IRUGO, pod_get_lowmid, pod_set_lowmid);
+static DEVICE_ATTR(treble, S_IWUSR | S_IRUGO, pod_get_treble, pod_set_treble);
+static DEVICE_ATTR(highmid, S_IWUSR | S_IRUGO, pod_get_highmid,
pod_set_highmid);
-static DEVICE_ATTR(chan_vol, S_IWUGO | S_IRUGO, pod_get_chan_vol,
+static DEVICE_ATTR(chan_vol, S_IWUSR | S_IRUGO, pod_get_chan_vol,
pod_set_chan_vol);
-static DEVICE_ATTR(reverb_mix, S_IWUGO | S_IRUGO, pod_get_reverb_mix,
+static DEVICE_ATTR(reverb_mix, S_IWUSR | S_IRUGO, pod_get_reverb_mix,
pod_set_reverb_mix);
-static DEVICE_ATTR(effect_setup, S_IWUGO | S_IRUGO, pod_get_effect_setup,
+static DEVICE_ATTR(effect_setup, S_IWUSR | S_IRUGO, pod_get_effect_setup,
pod_set_effect_setup);
-static DEVICE_ATTR(band_1_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_1_frequency, S_IWUSR | S_IRUGO,
pod_get_band_1_frequency, pod_set_band_1_frequency);
-static DEVICE_ATTR(presence, S_IWUGO | S_IRUGO, pod_get_presence,
+static DEVICE_ATTR(presence, S_IWUSR | S_IRUGO, pod_get_presence,
pod_set_presence);
-static DEVICE_ATTR2(treble__bass, treble, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(treble__bass, treble, S_IWUSR | S_IRUGO,
pod_get_treble__bass, pod_set_treble__bass);
-static DEVICE_ATTR(noise_gate_enable, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(noise_gate_enable, S_IWUSR | S_IRUGO,
pod_get_noise_gate_enable, pod_set_noise_gate_enable);
-static DEVICE_ATTR(gate_threshold, S_IWUGO | S_IRUGO, pod_get_gate_threshold,
+static DEVICE_ATTR(gate_threshold, S_IWUSR | S_IRUGO, pod_get_gate_threshold,
pod_set_gate_threshold);
-static DEVICE_ATTR(gate_decay_time, S_IWUGO | S_IRUGO, pod_get_gate_decay_time,
+static DEVICE_ATTR(gate_decay_time, S_IWUSR | S_IRUGO, pod_get_gate_decay_time,
pod_set_gate_decay_time);
-static DEVICE_ATTR(stomp_enable, S_IWUGO | S_IRUGO, pod_get_stomp_enable,
+static DEVICE_ATTR(stomp_enable, S_IWUSR | S_IRUGO, pod_get_stomp_enable,
pod_set_stomp_enable);
-static DEVICE_ATTR(comp_enable, S_IWUGO | S_IRUGO, pod_get_comp_enable,
+static DEVICE_ATTR(comp_enable, S_IWUSR | S_IRUGO, pod_get_comp_enable,
pod_set_comp_enable);
-static DEVICE_ATTR(stomp_time, S_IWUGO | S_IRUGO, pod_get_stomp_time,
+static DEVICE_ATTR(stomp_time, S_IWUSR | S_IRUGO, pod_get_stomp_time,
pod_set_stomp_time);
-static DEVICE_ATTR(delay_enable, S_IWUGO | S_IRUGO, pod_get_delay_enable,
+static DEVICE_ATTR(delay_enable, S_IWUSR | S_IRUGO, pod_get_delay_enable,
pod_set_delay_enable);
-static DEVICE_ATTR(mod_param_1, S_IWUGO | S_IRUGO, pod_get_mod_param_1,
+static DEVICE_ATTR(mod_param_1, S_IWUSR | S_IRUGO, pod_get_mod_param_1,
pod_set_mod_param_1);
-static DEVICE_ATTR(delay_param_1, S_IWUGO | S_IRUGO, pod_get_delay_param_1,
+static DEVICE_ATTR(delay_param_1, S_IWUSR | S_IRUGO, pod_get_delay_param_1,
pod_set_delay_param_1);
-static DEVICE_ATTR(delay_param_1_note_value, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(delay_param_1_note_value, S_IWUSR | S_IRUGO,
pod_get_delay_param_1_note_value,
pod_set_delay_param_1_note_value);
-static DEVICE_ATTR2(band_2_frequency__bass, band_2_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_2_frequency__bass, band_2_frequency, S_IWUSR | S_IRUGO,
pod_get_band_2_frequency__bass,
pod_set_band_2_frequency__bass);
-static DEVICE_ATTR(delay_param_2, S_IWUGO | S_IRUGO, pod_get_delay_param_2,
+static DEVICE_ATTR(delay_param_2, S_IWUSR | S_IRUGO, pod_get_delay_param_2,
pod_set_delay_param_2);
-static DEVICE_ATTR(delay_volume_mix, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(delay_volume_mix, S_IWUSR | S_IRUGO,
pod_get_delay_volume_mix, pod_set_delay_volume_mix);
-static DEVICE_ATTR(delay_param_3, S_IWUGO | S_IRUGO, pod_get_delay_param_3,
+static DEVICE_ATTR(delay_param_3, S_IWUSR | S_IRUGO, pod_get_delay_param_3,
pod_set_delay_param_3);
-static DEVICE_ATTR(reverb_enable, S_IWUGO | S_IRUGO, pod_get_reverb_enable,
+static DEVICE_ATTR(reverb_enable, S_IWUSR | S_IRUGO, pod_get_reverb_enable,
pod_set_reverb_enable);
-static DEVICE_ATTR(reverb_type, S_IWUGO | S_IRUGO, pod_get_reverb_type,
+static DEVICE_ATTR(reverb_type, S_IWUSR | S_IRUGO, pod_get_reverb_type,
pod_set_reverb_type);
-static DEVICE_ATTR(reverb_decay, S_IWUGO | S_IRUGO, pod_get_reverb_decay,
+static DEVICE_ATTR(reverb_decay, S_IWUSR | S_IRUGO, pod_get_reverb_decay,
pod_set_reverb_decay);
-static DEVICE_ATTR(reverb_tone, S_IWUGO | S_IRUGO, pod_get_reverb_tone,
+static DEVICE_ATTR(reverb_tone, S_IWUSR | S_IRUGO, pod_get_reverb_tone,
pod_set_reverb_tone);
-static DEVICE_ATTR(reverb_pre_delay, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(reverb_pre_delay, S_IWUSR | S_IRUGO,
pod_get_reverb_pre_delay, pod_set_reverb_pre_delay);
-static DEVICE_ATTR(reverb_pre_post, S_IWUGO | S_IRUGO, pod_get_reverb_pre_post,
+static DEVICE_ATTR(reverb_pre_post, S_IWUSR | S_IRUGO, pod_get_reverb_pre_post,
pod_set_reverb_pre_post);
-static DEVICE_ATTR(band_2_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_2_frequency, S_IWUSR | S_IRUGO,
pod_get_band_2_frequency, pod_set_band_2_frequency);
-static DEVICE_ATTR2(band_3_frequency__bass, band_3_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_3_frequency__bass, band_3_frequency, S_IWUSR | S_IRUGO,
pod_get_band_3_frequency__bass,
pod_set_band_3_frequency__bass);
-static DEVICE_ATTR(wah_enable, S_IWUGO | S_IRUGO, pod_get_wah_enable,
+static DEVICE_ATTR(wah_enable, S_IWUSR | S_IRUGO, pod_get_wah_enable,
pod_set_wah_enable);
-static DEVICE_ATTR(modulation_lo_cut, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(modulation_lo_cut, S_IWUSR | S_IRUGO,
pod_get_modulation_lo_cut, pod_set_modulation_lo_cut);
-static DEVICE_ATTR(delay_reverb_lo_cut, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(delay_reverb_lo_cut, S_IWUSR | S_IRUGO,
pod_get_delay_reverb_lo_cut, pod_set_delay_reverb_lo_cut);
-static DEVICE_ATTR(volume_pedal_minimum, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(volume_pedal_minimum, S_IWUSR | S_IRUGO,
pod_get_volume_pedal_minimum, pod_set_volume_pedal_minimum);
-static DEVICE_ATTR(eq_pre_post, S_IWUGO | S_IRUGO, pod_get_eq_pre_post,
+static DEVICE_ATTR(eq_pre_post, S_IWUSR | S_IRUGO, pod_get_eq_pre_post,
pod_set_eq_pre_post);
-static DEVICE_ATTR(volume_pre_post, S_IWUGO | S_IRUGO, pod_get_volume_pre_post,
+static DEVICE_ATTR(volume_pre_post, S_IWUSR | S_IRUGO, pod_get_volume_pre_post,
pod_set_volume_pre_post);
-static DEVICE_ATTR(di_model, S_IWUGO | S_IRUGO, pod_get_di_model,
+static DEVICE_ATTR(di_model, S_IWUSR | S_IRUGO, pod_get_di_model,
pod_set_di_model);
-static DEVICE_ATTR(di_delay, S_IWUGO | S_IRUGO, pod_get_di_delay,
+static DEVICE_ATTR(di_delay, S_IWUSR | S_IRUGO, pod_get_di_delay,
pod_set_di_delay);
-static DEVICE_ATTR(mod_enable, S_IWUGO | S_IRUGO, pod_get_mod_enable,
+static DEVICE_ATTR(mod_enable, S_IWUSR | S_IRUGO, pod_get_mod_enable,
pod_set_mod_enable);
-static DEVICE_ATTR(mod_param_1_note_value, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(mod_param_1_note_value, S_IWUSR | S_IRUGO,
pod_get_mod_param_1_note_value,
pod_set_mod_param_1_note_value);
-static DEVICE_ATTR(mod_param_2, S_IWUGO | S_IRUGO, pod_get_mod_param_2,
+static DEVICE_ATTR(mod_param_2, S_IWUSR | S_IRUGO, pod_get_mod_param_2,
pod_set_mod_param_2);
-static DEVICE_ATTR(mod_param_3, S_IWUGO | S_IRUGO, pod_get_mod_param_3,
+static DEVICE_ATTR(mod_param_3, S_IWUSR | S_IRUGO, pod_get_mod_param_3,
pod_set_mod_param_3);
-static DEVICE_ATTR(mod_param_4, S_IWUGO | S_IRUGO, pod_get_mod_param_4,
+static DEVICE_ATTR(mod_param_4, S_IWUSR | S_IRUGO, pod_get_mod_param_4,
pod_set_mod_param_4);
-static DEVICE_ATTR(mod_param_5, S_IWUGO | S_IRUGO, pod_get_mod_param_5,
+static DEVICE_ATTR(mod_param_5, S_IWUSR | S_IRUGO, pod_get_mod_param_5,
pod_set_mod_param_5);
-static DEVICE_ATTR(mod_volume_mix, S_IWUGO | S_IRUGO, pod_get_mod_volume_mix,
+static DEVICE_ATTR(mod_volume_mix, S_IWUSR | S_IRUGO, pod_get_mod_volume_mix,
pod_set_mod_volume_mix);
-static DEVICE_ATTR(mod_pre_post, S_IWUGO | S_IRUGO, pod_get_mod_pre_post,
+static DEVICE_ATTR(mod_pre_post, S_IWUSR | S_IRUGO, pod_get_mod_pre_post,
pod_set_mod_pre_post);
-static DEVICE_ATTR(modulation_model, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(modulation_model, S_IWUSR | S_IRUGO,
pod_get_modulation_model, pod_set_modulation_model);
-static DEVICE_ATTR(band_3_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_3_frequency, S_IWUSR | S_IRUGO,
pod_get_band_3_frequency, pod_set_band_3_frequency);
-static DEVICE_ATTR2(band_4_frequency__bass, band_4_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_4_frequency__bass, band_4_frequency, S_IWUSR | S_IRUGO,
pod_get_band_4_frequency__bass,
pod_set_band_4_frequency__bass);
-static DEVICE_ATTR(mod_param_1_double_precision, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(mod_param_1_double_precision, S_IWUSR | S_IRUGO,
pod_get_mod_param_1_double_precision,
pod_set_mod_param_1_double_precision);
-static DEVICE_ATTR(delay_param_1_double_precision, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(delay_param_1_double_precision, S_IWUSR | S_IRUGO,
pod_get_delay_param_1_double_precision,
pod_set_delay_param_1_double_precision);
-static DEVICE_ATTR(eq_enable, S_IWUGO | S_IRUGO, pod_get_eq_enable,
+static DEVICE_ATTR(eq_enable, S_IWUSR | S_IRUGO, pod_get_eq_enable,
pod_set_eq_enable);
-static DEVICE_ATTR(tap, S_IWUGO | S_IRUGO, pod_get_tap, pod_set_tap);
-static DEVICE_ATTR(volume_tweak_pedal_assign, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(tap, S_IWUSR | S_IRUGO, pod_get_tap, pod_set_tap);
+static DEVICE_ATTR(volume_tweak_pedal_assign, S_IWUSR | S_IRUGO,
pod_get_volume_tweak_pedal_assign,
pod_set_volume_tweak_pedal_assign);
-static DEVICE_ATTR(band_5_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_5_frequency, S_IWUSR | S_IRUGO,
pod_get_band_5_frequency, pod_set_band_5_frequency);
-static DEVICE_ATTR(tuner, S_IWUGO | S_IRUGO, pod_get_tuner, pod_set_tuner);
-static DEVICE_ATTR(mic_selection, S_IWUGO | S_IRUGO, pod_get_mic_selection,
+static DEVICE_ATTR(tuner, S_IWUSR | S_IRUGO, pod_get_tuner, pod_set_tuner);
+static DEVICE_ATTR(mic_selection, S_IWUSR | S_IRUGO, pod_get_mic_selection,
pod_set_mic_selection);
-static DEVICE_ATTR(cabinet_model, S_IWUGO | S_IRUGO, pod_get_cabinet_model,
+static DEVICE_ATTR(cabinet_model, S_IWUSR | S_IRUGO, pod_get_cabinet_model,
pod_set_cabinet_model);
-static DEVICE_ATTR(stomp_model, S_IWUGO | S_IRUGO, pod_get_stomp_model,
+static DEVICE_ATTR(stomp_model, S_IWUSR | S_IRUGO, pod_get_stomp_model,
pod_set_stomp_model);
-static DEVICE_ATTR(roomlevel, S_IWUGO | S_IRUGO, pod_get_roomlevel,
+static DEVICE_ATTR(roomlevel, S_IWUSR | S_IRUGO, pod_get_roomlevel,
pod_set_roomlevel);
-static DEVICE_ATTR(band_4_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_4_frequency, S_IWUSR | S_IRUGO,
pod_get_band_4_frequency, pod_set_band_4_frequency);
-static DEVICE_ATTR(band_6_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_6_frequency, S_IWUSR | S_IRUGO,
pod_get_band_6_frequency, pod_set_band_6_frequency);
-static DEVICE_ATTR(stomp_param_1_note_value, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(stomp_param_1_note_value, S_IWUSR | S_IRUGO,
pod_get_stomp_param_1_note_value,
pod_set_stomp_param_1_note_value);
-static DEVICE_ATTR(stomp_param_2, S_IWUGO | S_IRUGO, pod_get_stomp_param_2,
+static DEVICE_ATTR(stomp_param_2, S_IWUSR | S_IRUGO, pod_get_stomp_param_2,
pod_set_stomp_param_2);
-static DEVICE_ATTR(stomp_param_3, S_IWUGO | S_IRUGO, pod_get_stomp_param_3,
+static DEVICE_ATTR(stomp_param_3, S_IWUSR | S_IRUGO, pod_get_stomp_param_3,
pod_set_stomp_param_3);
-static DEVICE_ATTR(stomp_param_4, S_IWUGO | S_IRUGO, pod_get_stomp_param_4,
+static DEVICE_ATTR(stomp_param_4, S_IWUSR | S_IRUGO, pod_get_stomp_param_4,
pod_set_stomp_param_4);
-static DEVICE_ATTR(stomp_param_5, S_IWUGO | S_IRUGO, pod_get_stomp_param_5,
+static DEVICE_ATTR(stomp_param_5, S_IWUSR | S_IRUGO, pod_get_stomp_param_5,
pod_set_stomp_param_5);
-static DEVICE_ATTR(stomp_param_6, S_IWUGO | S_IRUGO, pod_get_stomp_param_6,
+static DEVICE_ATTR(stomp_param_6, S_IWUSR | S_IRUGO, pod_get_stomp_param_6,
pod_set_stomp_param_6);
-static DEVICE_ATTR(amp_switch_select, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(amp_switch_select, S_IWUSR | S_IRUGO,
pod_get_amp_switch_select, pod_set_amp_switch_select);
-static DEVICE_ATTR(delay_param_4, S_IWUGO | S_IRUGO, pod_get_delay_param_4,
+static DEVICE_ATTR(delay_param_4, S_IWUSR | S_IRUGO, pod_get_delay_param_4,
pod_set_delay_param_4);
-static DEVICE_ATTR(delay_param_5, S_IWUGO | S_IRUGO, pod_get_delay_param_5,
+static DEVICE_ATTR(delay_param_5, S_IWUSR | S_IRUGO, pod_get_delay_param_5,
pod_set_delay_param_5);
-static DEVICE_ATTR(delay_pre_post, S_IWUGO | S_IRUGO, pod_get_delay_pre_post,
+static DEVICE_ATTR(delay_pre_post, S_IWUSR | S_IRUGO, pod_get_delay_pre_post,
pod_set_delay_pre_post);
-static DEVICE_ATTR(delay_model, S_IWUGO | S_IRUGO, pod_get_delay_model,
+static DEVICE_ATTR(delay_model, S_IWUSR | S_IRUGO, pod_get_delay_model,
pod_set_delay_model);
-static DEVICE_ATTR(delay_verb_model, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(delay_verb_model, S_IWUSR | S_IRUGO,
pod_get_delay_verb_model, pod_set_delay_verb_model);
-static DEVICE_ATTR(tempo_msb, S_IWUGO | S_IRUGO, pod_get_tempo_msb,
+static DEVICE_ATTR(tempo_msb, S_IWUSR | S_IRUGO, pod_get_tempo_msb,
pod_set_tempo_msb);
-static DEVICE_ATTR(tempo_lsb, S_IWUGO | S_IRUGO, pod_get_tempo_lsb,
+static DEVICE_ATTR(tempo_lsb, S_IWUSR | S_IRUGO, pod_get_tempo_lsb,
pod_set_tempo_lsb);
-static DEVICE_ATTR(wah_model, S_IWUGO | S_IRUGO, pod_get_wah_model,
+static DEVICE_ATTR(wah_model, S_IWUSR | S_IRUGO, pod_get_wah_model,
pod_set_wah_model);
-static DEVICE_ATTR(bypass_volume, S_IWUGO | S_IRUGO, pod_get_bypass_volume,
+static DEVICE_ATTR(bypass_volume, S_IWUSR | S_IRUGO, pod_get_bypass_volume,
pod_set_bypass_volume);
-static DEVICE_ATTR(fx_loop_on_off, S_IWUGO | S_IRUGO, pod_get_fx_loop_on_off,
+static DEVICE_ATTR(fx_loop_on_off, S_IWUSR | S_IRUGO, pod_get_fx_loop_on_off,
pod_set_fx_loop_on_off);
-static DEVICE_ATTR(tweak_param_select, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(tweak_param_select, S_IWUSR | S_IRUGO,
pod_get_tweak_param_select, pod_set_tweak_param_select);
-static DEVICE_ATTR(amp1_engage, S_IWUGO | S_IRUGO, pod_get_amp1_engage,
+static DEVICE_ATTR(amp1_engage, S_IWUSR | S_IRUGO, pod_get_amp1_engage,
pod_set_amp1_engage);
-static DEVICE_ATTR(band_1_gain, S_IWUGO | S_IRUGO, pod_get_band_1_gain,
+static DEVICE_ATTR(band_1_gain, S_IWUSR | S_IRUGO, pod_get_band_1_gain,
pod_set_band_1_gain);
-static DEVICE_ATTR2(band_2_gain__bass, band_2_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_2_gain__bass, band_2_gain, S_IWUSR | S_IRUGO,
pod_get_band_2_gain__bass, pod_set_band_2_gain__bass);
-static DEVICE_ATTR(band_2_gain, S_IWUGO | S_IRUGO, pod_get_band_2_gain,
+static DEVICE_ATTR(band_2_gain, S_IWUSR | S_IRUGO, pod_get_band_2_gain,
pod_set_band_2_gain);
-static DEVICE_ATTR2(band_3_gain__bass, band_3_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_3_gain__bass, band_3_gain, S_IWUSR | S_IRUGO,
pod_get_band_3_gain__bass, pod_set_band_3_gain__bass);
-static DEVICE_ATTR(band_3_gain, S_IWUGO | S_IRUGO, pod_get_band_3_gain,
+static DEVICE_ATTR(band_3_gain, S_IWUSR | S_IRUGO, pod_get_band_3_gain,
pod_set_band_3_gain);
-static DEVICE_ATTR2(band_4_gain__bass, band_4_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_4_gain__bass, band_4_gain, S_IWUSR | S_IRUGO,
pod_get_band_4_gain__bass, pod_set_band_4_gain__bass);
-static DEVICE_ATTR2(band_5_gain__bass, band_5_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_5_gain__bass, band_5_gain, S_IWUSR | S_IRUGO,
pod_get_band_5_gain__bass, pod_set_band_5_gain__bass);
-static DEVICE_ATTR(band_4_gain, S_IWUGO | S_IRUGO, pod_get_band_4_gain,
+static DEVICE_ATTR(band_4_gain, S_IWUSR | S_IRUGO, pod_get_band_4_gain,
pod_set_band_4_gain);
-static DEVICE_ATTR2(band_6_gain__bass, band_6_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_6_gain__bass, band_6_gain, S_IWUSR | S_IRUGO,
pod_get_band_6_gain__bass, pod_set_band_6_gain__bass);
static DEVICE_ATTR(body, S_IRUGO, variax_get_body, line6_nop_write);
static DEVICE_ATTR(pickup1_enable, S_IRUGO, variax_get_pickup1_enable,
return count;
}
-static DEVICE_ATTR(midi_mask_transmit, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(midi_mask_transmit, S_IWUSR | S_IRUGO,
midi_get_midi_mask_transmit, midi_set_midi_mask_transmit);
-static DEVICE_ATTR(midi_mask_receive, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(midi_mask_receive, S_IWUSR | S_IRUGO,
midi_get_midi_mask_receive, midi_set_midi_mask_receive);
/* MIDI device destructor */
return count;
}
-static DEVICE_ATTR(impulse_volume, S_IWUGO | S_IRUGO, pcm_get_impulse_volume,
+static DEVICE_ATTR(impulse_volume, S_IWUSR | S_IRUGO, pcm_get_impulse_volume,
pcm_set_impulse_volume);
-static DEVICE_ATTR(impulse_period, S_IWUGO | S_IRUGO, pcm_get_impulse_period,
+static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period,
pcm_set_impulse_period);
#endif
#undef GET_SYSTEM_PARAM
/* POD special files: */
-static DEVICE_ATTR(channel, S_IWUGO | S_IRUGO, pod_get_channel,
+static DEVICE_ATTR(channel, S_IWUSR | S_IRUGO, pod_get_channel,
pod_set_channel);
static DEVICE_ATTR(clip, S_IRUGO, pod_wait_for_clip, line6_nop_write);
static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
static DEVICE_ATTR(dirty, S_IRUGO, pod_get_dirty, line6_nop_write);
-static DEVICE_ATTR(dump, S_IWUGO | S_IRUGO, pod_get_dump, pod_set_dump);
-static DEVICE_ATTR(dump_buf, S_IWUGO | S_IRUGO, pod_get_dump_buf,
+static DEVICE_ATTR(dump, S_IWUSR | S_IRUGO, pod_get_dump, pod_set_dump);
+static DEVICE_ATTR(dump_buf, S_IWUSR | S_IRUGO, pod_get_dump_buf,
pod_set_dump_buf);
-static DEVICE_ATTR(finish, S_IWUGO, line6_nop_read, pod_set_finish);
+static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish);
static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
line6_nop_write);
-static DEVICE_ATTR(midi_postprocess, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO,
pod_get_midi_postprocess, pod_set_midi_postprocess);
-static DEVICE_ATTR(monitor_level, S_IWUGO | S_IRUGO, pod_get_monitor_level,
+static DEVICE_ATTR(monitor_level, S_IWUSR | S_IRUGO, pod_get_monitor_level,
pod_set_monitor_level);
static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write);
static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write);
-static DEVICE_ATTR(retrieve_amp_setup, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(retrieve_amp_setup, S_IWUSR, line6_nop_read,
pod_set_retrieve_amp_setup);
-static DEVICE_ATTR(retrieve_channel, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(retrieve_channel, S_IWUSR, line6_nop_read,
pod_set_retrieve_channel);
-static DEVICE_ATTR(retrieve_effects_setup, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(retrieve_effects_setup, S_IWUSR, line6_nop_read,
pod_set_retrieve_effects_setup);
-static DEVICE_ATTR(routing, S_IWUGO | S_IRUGO, pod_get_routing,
+static DEVICE_ATTR(routing, S_IWUSR | S_IRUGO, pod_get_routing,
pod_set_routing);
static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
line6_nop_write);
-static DEVICE_ATTR(store_amp_setup, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(store_amp_setup, S_IWUSR, line6_nop_read,
pod_set_store_amp_setup);
-static DEVICE_ATTR(store_channel, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(store_channel, S_IWUSR, line6_nop_read,
pod_set_store_channel);
-static DEVICE_ATTR(store_effects_setup, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(store_effects_setup, S_IWUSR, line6_nop_read,
pod_set_store_effects_setup);
-static DEVICE_ATTR(tuner_freq, S_IWUGO | S_IRUGO, pod_get_tuner_freq,
+static DEVICE_ATTR(tuner_freq, S_IWUSR | S_IRUGO, pod_get_tuner_freq,
pod_set_tuner_freq);
-static DEVICE_ATTR(tuner_mute, S_IWUGO | S_IRUGO, pod_get_tuner_mute,
+static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute,
pod_set_tuner_mute);
static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
#ifdef CONFIG_LINE6_USB_RAW
-static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
+static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
#endif
/* control info callback */
return count;
}
-static DEVICE_ATTR(led_red, S_IWUGO | S_IRUGO, line6_nop_read,
+static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
toneport_set_led_red);
-static DEVICE_ATTR(led_green, S_IWUGO | S_IRUGO, line6_nop_read,
+static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
toneport_set_led_green);
static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
#endif
/* Variax workbench special files: */
-static DEVICE_ATTR(model, S_IWUGO | S_IRUGO, variax_get_model,
+static DEVICE_ATTR(model, S_IWUSR | S_IRUGO, variax_get_model,
variax_set_model);
-static DEVICE_ATTR(volume, S_IWUGO | S_IRUGO, variax_get_volume,
+static DEVICE_ATTR(volume, S_IWUSR | S_IRUGO, variax_get_volume,
variax_set_volume);
-static DEVICE_ATTR(tone, S_IWUGO | S_IRUGO, variax_get_tone, variax_set_tone);
+static DEVICE_ATTR(tone, S_IWUSR | S_IRUGO, variax_get_tone, variax_set_tone);
static DEVICE_ATTR(name, S_IRUGO, variax_get_name, line6_nop_write);
static DEVICE_ATTR(bank, S_IRUGO, variax_get_bank, line6_nop_write);
static DEVICE_ATTR(dump, S_IRUGO, variax_get_dump, line6_nop_write);
-static DEVICE_ATTR(active, S_IWUGO | S_IRUGO, variax_get_active,
+static DEVICE_ATTR(active, S_IWUSR | S_IRUGO, variax_get_active,
variax_set_active);
static DEVICE_ATTR(guitar, S_IRUGO, variax_get_guitar, line6_nop_write);
#ifdef CONFIG_LINE6_USB_RAW
-static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
-static DEVICE_ATTR(raw2, S_IWUGO, line6_nop_read, variax_set_raw2);
+static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
+static DEVICE_ATTR(raw2, S_IWUSR, line6_nop_read, variax_set_raw2);
#endif
/*
static void quickstart_exit(void)
{
input_unregister_device(quickstart_input);
- input_free_device(quickstart_input);
device_remove_file(&pf_device->dev, &dev_attr_pressed_button);
device_remove_file(&pf_device->dev, &dev_attr_buttons);
{
struct quickstart_btn **ptr = &quickstart_data.btn_lst;
int count;
+ int ret;
quickstart_input = input_allocate_device();
ptr = &((*ptr)->next);
}
- return input_register_device(quickstart_input);
+ ret = input_register_device(quickstart_input);
+ if (ret) {
+ input_free_device(quickstart_input);
+ return ret;
+ }
+
+ return 0;
}
static int __init quickstart_init(void)
{USB_DEVICE(0x2001, 0x3C09)}, /* D-Link */
{USB_DEVICE(0x2001, 0x3C0A)}, /* D-Link 3072 */
{USB_DEVICE(0x2019, 0xED14)}, /* Planex Communications, Inc. */
+ {USB_DEVICE(0x0411, 0x015D)}, /* Buffalo Airstation WLI-UC-GN */
{} /* Terminating entry */
};
udelay(10);
}
- if (TryCnt == TC_3W_POLL_MAX_TRY_CNT)
- panic("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear!!\n", u1bTmp);
+ if (TryCnt == TC_3W_POLL_MAX_TRY_CNT) {
+ printk(KERN_ERR "rtl8187se: HwThreeWire(): CmdReg:"
+ " %#X RE|WE bits are not clear!!\n", u1bTmp);
+ dump_stack();
+ return 0;
+ }
/* RTL8187S HSSI Read/Write Function */
u1bTmp = read_nic_byte(dev, RF_SW_CONFIG);
int idx;
int ByteCnt = nDataBufBitCnt / 8;
/* printk("%d\n",nDataBufBitCnt); */
- if ((nDataBufBitCnt % 8) != 0)
- panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n",
- nDataBufBitCnt);
+ if ((nDataBufBitCnt % 8) != 0) {
+ printk(KERN_ERR "rtl8187se: "
+ "HwThreeWire(): nDataBufBitCnt(%d)"
+ " should be multiple of 8!!!\n",
+ nDataBufBitCnt);
+ dump_stack();
+ nDataBufBitCnt += 8;
+ nDataBufBitCnt &= ~7;
+ }
- if (nDataBufBitCnt > 64)
- panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n",
- nDataBufBitCnt);
+ if (nDataBufBitCnt > 64) {
+ printk(KERN_ERR "rtl8187se: HwThreeWire():"
+ " nDataBufBitCnt(%d) should <= 64!!!\n",
+ nDataBufBitCnt);
+ dump_stack();
+ nDataBufBitCnt = 64;
+ }
for (idx = 0; idx < ByteCnt; idx++)
write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx));
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kref.h>
-#include <linux/smp_lock.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/usb.h>
{
u8 val8 = 0;
u8 ret = _SUCCESS;
- u8 PollingCnt = 20;
+ int PollingCnt = 20;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
if (pregistrypriv->chip_version == RTL8712_FPGA) {
}
return count;
}
-static DEVICE_ATTR(silent, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(silent, S_IWUSR | S_IRUGO,
get_silent_state, set_silent_state);
#include <linux/console.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/wait.h>
{
if (virt_keyboard != NULL) {
input_unregister_device(virt_keyboard);
- input_free_device(virt_keyboard);
virt_keyboard = NULL;
}
}
/* Here we force report 512 byte hardware sector size to Kernel */
blk_queue_logical_block_size(dev->queue, 512);
- blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH);
+ blk_queue_flush(dev->queue, REQ_FLUSH);
dev->thread = kthread_run(spectra_trans_thread, dev, "nand_thd");
if (IS_ERR(dev->thread)) {
config VIDEO_STRADIS
tristate "Stradis 4:2:2 MPEG-2 video driver (DEPRECATED)"
- depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
+ depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS && BKL
help
Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
driver for PCI. There is a product page at
/* Load tuner module */
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tuner", dev->tuner_addr, NULL);
+ "tuner", dev->tuner_addr, NULL);
memset(&tun_setup, 0, sizeof(tun_setup));
tun_setup.type = dev->tuner_type;
if (dev->caps.has_tda9874)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tvaudio", I2C_ADDR_TDA9874, NULL);
+ "tvaudio", I2C_ADDR_TDA9874, NULL);
/* register and initialize V4L2 */
rc = tm6000_v4l2_register(dev);
__ATTR_RO(metrics_bytes_identical),
__ATTR_RO(metrics_bytes_sent),
__ATTR_RO(metrics_cpu_kcycles_used),
- __ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
+ __ATTR(metrics_reset, S_IWUSR, NULL, metrics_reset_store),
};
/*
#ifndef SYS_DEF_H
#define SYS_DEF_H
+
+#include <linux/delay.h>
+
#define WB_LINUX
#define WB_LINUX_WPA_PSK
return sprintf(buf, "%llu\n", val);
}
-static DEVICE_ATTR(disksize, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
disksize_show, disksize_store);
static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
-static DEVICE_ATTR(reset, S_IWUGO, NULL, reset_store);
+static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL);
static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL);
static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL);
#ifdef CONFIG_INPUT
/* Simple translation table for the SysRq keys */
-static const unsigned char sysrq_xlate[KEY_MAX + 1] =
+static const unsigned char sysrq_xlate[KEY_CNT] =
"\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
"qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
"dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
"\r\000/"; /* 0x60 - 0x6f */
-static bool sysrq_down;
-static int sysrq_alt_use;
-static int sysrq_alt;
-static DEFINE_SPINLOCK(sysrq_event_lock);
+struct sysrq_state {
+ struct input_handle handle;
+ struct work_struct reinject_work;
+ unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+ unsigned int alt;
+ unsigned int alt_use;
+ bool active;
+ bool need_reinject;
+};
+
+static void sysrq_reinject_alt_sysrq(struct work_struct *work)
+{
+ struct sysrq_state *sysrq =
+ container_of(work, struct sysrq_state, reinject_work);
+ struct input_handle *handle = &sysrq->handle;
+ unsigned int alt_code = sysrq->alt_use;
+
+ if (sysrq->need_reinject) {
+ /* Simulate press and release of Alt + SysRq */
+ input_inject_event(handle, EV_KEY, alt_code, 1);
+ input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1);
+ input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
+
+ input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0);
+ input_inject_event(handle, EV_KEY, alt_code, 0);
+ input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
+ }
+}
-static bool sysrq_filter(struct input_handle *handle, unsigned int type,
- unsigned int code, int value)
+static bool sysrq_filter(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
{
+ struct sysrq_state *sysrq = handle->private;
+ bool was_active = sysrq->active;
bool suppress;
- /* We are called with interrupts disabled, just take the lock */
- spin_lock(&sysrq_event_lock);
+ switch (type) {
- if (type != EV_KEY)
- goto out;
+ case EV_SYN:
+ suppress = false;
+ break;
- switch (code) {
+ case EV_KEY:
+ switch (code) {
- case KEY_LEFTALT:
- case KEY_RIGHTALT:
- if (value)
- sysrq_alt = code;
- else {
- if (sysrq_down && code == sysrq_alt_use)
- sysrq_down = false;
+ case KEY_LEFTALT:
+ case KEY_RIGHTALT:
+ if (!value) {
+ /* One of ALTs is being released */
+ if (sysrq->active && code == sysrq->alt_use)
+ sysrq->active = false;
- sysrq_alt = 0;
+ sysrq->alt = KEY_RESERVED;
+
+ } else if (value != 2) {
+ sysrq->alt = code;
+ sysrq->need_reinject = false;
+ }
+ break;
+
+ case KEY_SYSRQ:
+ if (value == 1 && sysrq->alt != KEY_RESERVED) {
+ sysrq->active = true;
+ sysrq->alt_use = sysrq->alt;
+ /*
+ * If nothing else will be pressed we'll need
+ * to * re-inject Alt-SysRq keysroke.
+ */
+ sysrq->need_reinject = true;
+ }
+
+ /*
+ * Pretend that sysrq was never pressed at all. This
+ * is needed to properly handle KGDB which will try
+ * to release all keys after exiting debugger. If we
+ * do not clear key bit it KGDB will end up sending
+ * release events for Alt and SysRq, potentially
+ * triggering print screen function.
+ */
+ if (sysrq->active)
+ clear_bit(KEY_SYSRQ, handle->dev->key);
+
+ break;
+
+ default:
+ if (sysrq->active && value && value != 2) {
+ sysrq->need_reinject = false;
+ __handle_sysrq(sysrq_xlate[code], true);
+ }
+ break;
}
- break;
- case KEY_SYSRQ:
- if (value == 1 && sysrq_alt) {
- sysrq_down = true;
- sysrq_alt_use = sysrq_alt;
+ suppress = sysrq->active;
+
+ if (!sysrq->active) {
+ /*
+ * If we are not suppressing key presses keep track of
+ * keyboard state so we can release keys that have been
+ * pressed before entering SysRq mode.
+ */
+ if (value)
+ set_bit(code, sysrq->key_down);
+ else
+ clear_bit(code, sysrq->key_down);
+
+ if (was_active)
+ schedule_work(&sysrq->reinject_work);
+
+ } else if (value == 0 &&
+ test_and_clear_bit(code, sysrq->key_down)) {
+ /*
+ * Pass on release events for keys that was pressed before
+ * entering SysRq mode.
+ */
+ suppress = false;
}
break;
default:
- if (sysrq_down && value && value != 2)
- __handle_sysrq(sysrq_xlate[code], true);
+ suppress = sysrq->active;
break;
}
-out:
- suppress = sysrq_down;
- spin_unlock(&sysrq_event_lock);
-
return suppress;
}
struct input_dev *dev,
const struct input_device_id *id)
{
- struct input_handle *handle;
+ struct sysrq_state *sysrq;
int error;
- sysrq_down = false;
- sysrq_alt = 0;
-
- handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
- if (!handle)
+ sysrq = kzalloc(sizeof(struct sysrq_state), GFP_KERNEL);
+ if (!sysrq)
return -ENOMEM;
- handle->dev = dev;
- handle->handler = handler;
- handle->name = "sysrq";
+ INIT_WORK(&sysrq->reinject_work, sysrq_reinject_alt_sysrq);
+
+ sysrq->handle.dev = dev;
+ sysrq->handle.handler = handler;
+ sysrq->handle.name = "sysrq";
+ sysrq->handle.private = sysrq;
- error = input_register_handle(handle);
+ error = input_register_handle(&sysrq->handle);
if (error) {
pr_err("Failed to register input sysrq handler, error %d\n",
error);
goto err_free;
}
- error = input_open_device(handle);
+ error = input_open_device(&sysrq->handle);
if (error) {
pr_err("Failed to open input device, error %d\n", error);
goto err_unregister;
return 0;
err_unregister:
- input_unregister_handle(handle);
+ input_unregister_handle(&sysrq->handle);
err_free:
- kfree(handle);
+ kfree(sysrq);
return error;
}
static void sysrq_disconnect(struct input_handle *handle)
{
+ struct sysrq_state *sysrq = handle->private;
+
input_close_device(handle);
+ cancel_work_sync(&sysrq->reinject_work);
input_unregister_handle(handle);
- kfree(handle);
+ kfree(sysrq);
}
/*
tty_lock();
+ /* some functions below drop BTM, so we need this bit */
+ set_bit(TTY_HUPPING, &tty->flags);
+
/* inuse_filps is protected by the single tty lock,
this really needs to change if we want to flush the
workqueue with the lock held */
}
spin_unlock(&tty_files_lock);
+ /*
+ * it drops BTM and thus races with reopen
+ * we protect the race by TTY_HUPPING
+ */
tty_ldisc_hangup(tty);
read_lock(&tasklist_lock);
tty->session = NULL;
tty->pgrp = NULL;
tty->ctrl_status = 0;
- set_bit(TTY_HUPPED, &tty->flags);
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
/* Account for the p->signal references we killed */
* can't yet guarantee all that.
*/
set_bit(TTY_HUPPED, &tty->flags);
+ clear_bit(TTY_HUPPING, &tty->flags);
tty_ldisc_enable(tty);
tty_unlock();
{
struct tty_driver *driver = tty->driver;
- if (test_bit(TTY_CLOSING, &tty->flags))
+ if (test_bit(TTY_CLOSING, &tty->flags) ||
+ test_bit(TTY_HUPPING, &tty->flags) ||
+ test_bit(TTY_LDISC_CHANGING, &tty->flags))
return -EIO;
if (driver->type == TTY_DRIVER_TYPE_PTY &&
/* BTM here locks versus a hangup event */
WARN_ON(!tty_locked());
ret = ld->ops->open(tty);
+ if (ret)
+ clear_bit(TTY_LDISC_OPEN, &tty->flags);
return ret;
}
return 0;
*
* Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de>
* Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de>
- * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de>
+ * Copyright(C) 2006, Hans J. Koch <hjk@hansjkoch.de>
* Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com>
*
* Userspace IO
/*
* UIO Hilscher CIF card driver
*
- * (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * (C) 2007 Hans J. Koch <hjk@hansjkoch.de>
* Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de>
*
* Licensed under GPL version 2 only.
* UIO driver for Hilscher NetX based fieldbus cards (cifX, comX).
* See http://www.hilscher.com for details.
*
- * (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * (C) 2007 Hans J. Koch <hjk@hansjkoch.de>
* (C) 2008 Manuel Traut <manut@linutronix.de>
*
* Licensed under GPL version 2 only.
return ret;
}
-static DEVICE_ATTR(stat_status, S_IWUGO | S_IRUGO, read_status, reboot);
+static DEVICE_ATTR(stat_status, S_IWUSR | S_IRUGO, read_status, reboot);
static ssize_t read_human_status(struct device *dev,
struct device_attribute *attr, char *buf)
return ret;
}
-static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO,
- read_human_status, NULL);
+static DEVICE_ATTR(stat_human_status, S_IRUGO, read_human_status, NULL);
static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
char *buf)
return ret;
}
-static DEVICE_ATTR(stat_delin, S_IWUGO | S_IRUGO, read_delin, NULL);
+static DEVICE_ATTR(stat_delin, S_IRUGO, read_delin, NULL);
#define UEA_ATTR(name, reset) \
\
* condition: callbacks we register can be executed at once, before we have
* initialized the struct atm_dev. To protect against this, all callbacks
* abort if atm_dev->dev_data is NULL. */
- atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL);
+ atm_dev = atm_dev_register(instance->driver_name,
+ &instance->usb_intf->dev, &usbatm_atm_devops,
+ -1, NULL);
if (!atm_dev) {
usb_err(instance, "%s: failed to register ATM device!\n", __func__);
return -1;
/* temp init ATM device, set to 128kbit */
atm_dev->link_rate = 128 * 1000 / 424;
- ret = sysfs_create_link(&atm_dev->class_dev.kobj,
- &instance->usb_intf->dev.kobj, "device");
- if (ret) {
- atm_err(instance, "%s: sysfs_create_link failed: %d\n",
- __func__, ret);
- goto fail_sysfs;
- }
-
if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) {
atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret);
goto fail;
return 0;
fail:
- sysfs_remove_link(&atm_dev->class_dev.kobj, "device");
- fail_sysfs:
instance->atm_dev = NULL;
atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */
return ret;
/* ATM finalize */
if (instance->atm_dev) {
- sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
atm_dev_deregister(instance->atm_dev);
instance->atm_dev = NULL;
}
#include <linux/gfp.h>
#include <linux/poll.h>
#include <linux/usb.h>
-#include <linux/smp_lock.h>
#include <linux/usbdevice_fs.h>
#include <linux/usb/hcd.h>
#include <linux/mutex.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include "usb.h"
*/
if (usb_endpoint_xfer_control(&urb->ep->desc)) {
+ if (hcd->self.uses_pio_for_control)
+ return ret;
if (hcd->self.uses_dma) {
urb->setup_dma = dma_map_single(
hcd->self.controller,
#include <linux/parser.h>
#include <linux/notifier.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/usb/hcd.h>
#include <asm/byteorder.h>
#include "usb.h"
}
} else {
/* gpio_request fail so use -EINVAL for gpio_is_valid */
- ubc->vbus_pin = -EINVAL;
+ udc->vbus_pin = -EINVAL;
}
}
#include <linux/blkdev.h>
#include <linux/pagemap.h>
#include <asm/unaligned.h>
-#include <linux/smp_lock.h>
#include <linux/usb/composite.h>
#include <linux/usb/functionfs.h>
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/usb/g_hid.h>
&debug_registers_fops))
goto file_error;
- if (!debugfs_create_file("lpm", S_IRUGO|S_IWUGO, ehci->debug_dir, bus,
+ if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus,
&debug_lpm_fops))
goto file_error;
tmp && tmp != qh;
tmp = tmp->qh_next.qh)
continue;
- /* periodic qh self-unlinks on empty */
- if (!tmp)
- goto nogood;
- unlink_async (ehci, qh);
+ /* periodic qh self-unlinks on empty, and a COMPLETING qh
+ * may already be unlinked.
+ */
+ if (tmp)
+ unlink_async(ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
case QH_STATE_UNLINK_WAIT:
}
/* else FALL THROUGH */
default:
-nogood:
/* caller was supposed to have unlinked any requests;
* that's not our job. just leak this memory.
*/
qh_put (ehci->async);
ehci->async = NULL;
+ if (ehci->dummy)
+ qh_put(ehci->dummy);
+ ehci->dummy = NULL;
+
/* DMA consistent memory and pools */
if (ehci->qtd_pool)
dma_pool_destroy (ehci->qtd_pool);
if (ehci->periodic == NULL) {
goto fail;
}
- for (i = 0; i < ehci->periodic_size; i++)
- ehci->periodic [i] = EHCI_LIST_END(ehci);
+
+ if (ehci->use_dummy_qh) {
+ struct ehci_qh_hw *hw;
+ ehci->dummy = ehci_qh_alloc(ehci, flags);
+ if (!ehci->dummy)
+ goto fail;
+
+ hw = ehci->dummy->hw;
+ hw->hw_next = EHCI_LIST_END(ehci);
+ hw->hw_qtd_next = EHCI_LIST_END(ehci);
+ hw->hw_alt_next = EHCI_LIST_END(ehci);
+ hw->hw_token &= ~QTD_STS_ACTIVE;
+ ehci->dummy->hw = hw;
+
+ for (i = 0; i < ehci->periodic_size; i++)
+ ehci->periodic[i] = ehci->dummy->qh_dma;
+ } else {
+ for (i = 0; i < ehci->periodic_size; i++)
+ ehci->periodic[i] = EHCI_LIST_END(ehci);
+ }
/* software shadow of hardware table */
ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
if (retval)
return retval;
+ if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) ||
+ (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) {
+ /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
+ * read/write memory space which does not belong to it when
+ * there is NULL pointer with T-bit set to 1 in the frame list
+ * table. To avoid the issue, the frame list link pointer
+ * should always contain a valid pointer to a inactive qh.
+ */
+ ehci->use_dummy_qh = 1;
+ ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI "
+ "dummy qh workaround\n");
+ }
+
/* data structure init */
retval = ehci_init(hcd);
if (retval)
if (pdev->revision < 0xa4)
ehci->no_selective_suspend = 1;
break;
+
+ /* MCP89 chips on the MacBookAir3,1 give EPROTO when
+ * fetching device descriptors unless LPM is disabled.
+ * There are also intermittent problems enumerating
+ * devices with PPCD enabled.
+ */
+ case 0x0d9d:
+ ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
+ ehci->has_lpm = 0;
+ ehci->has_ppcd = 0;
+ ehci->command &= ~CMD_PPCEE;
+ break;
}
break;
case PCI_VENDOR_ID_VIA:
*/
*prev_p = *periodic_next_shadow(ehci, &here,
Q_NEXT_TYPE(ehci, *hw_p));
- *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p));
+
+ if (!ehci->use_dummy_qh ||
+ *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p))
+ != EHCI_LIST_END(ehci))
+ *hw_p = *shadow_next_periodic(ehci, &here,
+ Q_NEXT_TYPE(ehci, *hw_p));
+ else
+ *hw_p = ehci->dummy->qh_dma;
}
/* how many of the uframe's 125 usecs are allocated? */
* pointer for much longer, if at all.
*/
*q_p = q.itd->itd_next;
- *hw_p = q.itd->hw_next;
+ if (!ehci->use_dummy_qh ||
+ q.itd->hw_next != EHCI_LIST_END(ehci))
+ *hw_p = q.itd->hw_next;
+ else
+ *hw_p = ehci->dummy->qh_dma;
type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
wmb();
modified = itd_complete (ehci, q.itd);
* URB completion.
*/
*q_p = q.sitd->sitd_next;
- *hw_p = q.sitd->hw_next;
+ if (!ehci->use_dummy_qh ||
+ q.sitd->hw_next != EHCI_LIST_END(ehci))
+ *hw_p = q.sitd->hw_next;
+ else
+ *hw_p = ehci->dummy->qh_dma;
type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
wmb();
modified = sitd_complete (ehci, q.sitd);
/* async schedule support */
struct ehci_qh *async;
+ struct ehci_qh *dummy; /* For AMD quirk use */
struct ehci_qh *reclaim;
unsigned scanning : 1;
unsigned need_io_watchdog:1;
unsigned broken_periodic:1;
unsigned fs_i_thresh:1; /* Intel iso scheduling */
+ unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/list.h>
return 0;
}
-static int __init isp1362_probe(struct platform_device *pdev)
+static int __devinit isp1362_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct isp1362_hcd *isp1362_hcd;
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
-#include <linux/smp_lock.h>
#include <asm/io.h>
#include "uhci-hcd.h"
static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
u32 __iomem *addr, u32 port_status)
{
+ /* Don't allow the USB core to disable SuperSpeed ports. */
+ if (xhci->port_array[wIndex] == 0x03) {
+ xhci_dbg(xhci, "Ignoring request to disable "
+ "SuperSpeed port.\n");
+ return;
+ }
+
/* Write 1 to disable the port */
xhci_writel(xhci, port_status | PORT_PE, addr);
port_status = xhci_readl(xhci, addr);
if (udev->speed == USB_SPEED_SUPER)
return ep->ss_ep_comp.wBytesPerInterval;
- max_packet = ep->desc.wMaxPacketSize & 0x3ff;
+ max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
/* A 0 in max burst means 1 transfer per ESIT */
return max_packet * (max_burst + 1);
/* Fall through */
case USB_SPEED_FULL:
case USB_SPEED_LOW:
- max_packet = ep->desc.wMaxPacketSize & 0x3ff;
+ max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
break;
default:
xhci->dcbaa = NULL;
scratchpad_free(xhci);
+
+ xhci->num_usb2_ports = 0;
+ xhci->num_usb3_ports = 0;
+ kfree(xhci->usb2_ports);
+ kfree(xhci->usb3_ports);
+ kfree(xhci->port_array);
+
xhci->page_size = 0;
xhci->page_shift = 0;
xhci->bus_suspended = 0;
&xhci->ir_set->erst_dequeue);
}
+static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
+ u32 __iomem *addr, u8 major_revision)
+{
+ u32 temp, port_offset, port_count;
+ int i;
+
+ if (major_revision > 0x03) {
+ xhci_warn(xhci, "Ignoring unknown port speed, "
+ "Ext Cap %p, revision = 0x%x\n",
+ addr, major_revision);
+ /* Ignoring port protocol we can't understand. FIXME */
+ return;
+ }
+
+ /* Port offset and count in the third dword, see section 7.2 */
+ temp = xhci_readl(xhci, addr + 2);
+ port_offset = XHCI_EXT_PORT_OFF(temp);
+ port_count = XHCI_EXT_PORT_COUNT(temp);
+ xhci_dbg(xhci, "Ext Cap %p, port offset = %u, "
+ "count = %u, revision = 0x%x\n",
+ addr, port_offset, port_count, major_revision);
+ /* Port count includes the current port offset */
+ if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
+ /* WTF? "Valid values are ‘1’ to MaxPorts" */
+ return;
+ port_offset--;
+ for (i = port_offset; i < (port_offset + port_count); i++) {
+ /* Duplicate entry. Ignore the port if the revisions differ. */
+ if (xhci->port_array[i] != 0) {
+ xhci_warn(xhci, "Duplicate port entry, Ext Cap %p,"
+ " port %u\n", addr, i);
+ xhci_warn(xhci, "Port was marked as USB %u, "
+ "duplicated as USB %u\n",
+ xhci->port_array[i], major_revision);
+ /* Only adjust the roothub port counts if we haven't
+ * found a similar duplicate.
+ */
+ if (xhci->port_array[i] != major_revision &&
+ xhci->port_array[i] != (u8) -1) {
+ if (xhci->port_array[i] == 0x03)
+ xhci->num_usb3_ports--;
+ else
+ xhci->num_usb2_ports--;
+ xhci->port_array[i] = (u8) -1;
+ }
+ /* FIXME: Should we disable the port? */
+ }
+ xhci->port_array[i] = major_revision;
+ if (major_revision == 0x03)
+ xhci->num_usb3_ports++;
+ else
+ xhci->num_usb2_ports++;
+ }
+ /* FIXME: Should we disable ports not in the Extended Capabilities? */
+}
+
+/*
+ * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that
+ * specify what speeds each port is supposed to be. We can't count on the port
+ * speed bits in the PORTSC register being correct until a device is connected,
+ * but we need to set up the two fake roothubs with the correct number of USB
+ * 3.0 and USB 2.0 ports at host controller initialization time.
+ */
+static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
+{
+ u32 __iomem *addr;
+ u32 offset;
+ unsigned int num_ports;
+ int i, port_index;
+
+ addr = &xhci->cap_regs->hcc_params;
+ offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr));
+ if (offset == 0) {
+ xhci_err(xhci, "No Extended Capability registers, "
+ "unable to set up roothub.\n");
+ return -ENODEV;
+ }
+
+ num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
+ xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags);
+ if (!xhci->port_array)
+ return -ENOMEM;
+
+ /*
+ * For whatever reason, the first capability offset is from the
+ * capability register base, not from the HCCPARAMS register.
+ * See section 5.3.6 for offset calculation.
+ */
+ addr = &xhci->cap_regs->hc_capbase + offset;
+ while (1) {
+ u32 cap_id;
+
+ cap_id = xhci_readl(xhci, addr);
+ if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)
+ xhci_add_in_port(xhci, num_ports, addr,
+ (u8) XHCI_EXT_PORT_MAJOR(cap_id));
+ offset = XHCI_EXT_CAPS_NEXT(cap_id);
+ if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports)
+ == num_ports)
+ break;
+ /*
+ * Once you're into the Extended Capabilities, the offset is
+ * always relative to the register holding the offset.
+ */
+ addr += offset;
+ }
+
+ if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) {
+ xhci_warn(xhci, "No ports on the roothubs?\n");
+ return -ENODEV;
+ }
+ xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n",
+ xhci->num_usb2_ports, xhci->num_usb3_ports);
+ /*
+ * Note we could have all USB 3.0 ports, or all USB 2.0 ports.
+ * Not sure how the USB core will handle a hub with no ports...
+ */
+ if (xhci->num_usb2_ports) {
+ xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)*
+ xhci->num_usb2_ports, flags);
+ if (!xhci->usb2_ports)
+ return -ENOMEM;
+
+ port_index = 0;
+ for (i = 0; i < num_ports; i++)
+ if (xhci->port_array[i] != 0x03) {
+ xhci->usb2_ports[port_index] =
+ &xhci->op_regs->port_status_base +
+ NUM_PORT_REGS*i;
+ xhci_dbg(xhci, "USB 2.0 port at index %u, "
+ "addr = %p\n", i,
+ xhci->usb2_ports[port_index]);
+ port_index++;
+ }
+ }
+ if (xhci->num_usb3_ports) {
+ xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)*
+ xhci->num_usb3_ports, flags);
+ if (!xhci->usb3_ports)
+ return -ENOMEM;
+
+ port_index = 0;
+ for (i = 0; i < num_ports; i++)
+ if (xhci->port_array[i] == 0x03) {
+ xhci->usb3_ports[port_index] =
+ &xhci->op_regs->port_status_base +
+ NUM_PORT_REGS*i;
+ xhci_dbg(xhci, "USB 3.0 port at index %u, "
+ "addr = %p\n", i,
+ xhci->usb3_ports[port_index]);
+ port_index++;
+ }
+ }
+ return 0;
+}
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
if (scratchpad_alloc(xhci, flags))
goto fail;
+ if (xhci_setup_port_arrays(xhci, flags))
+ goto fail;
return 0;
if (!(status & STS_EINT)) {
spin_unlock(&xhci->lock);
- xhci_warn(xhci, "Spurious interrupt.\n");
return IRQ_NONE;
}
xhci_dbg(xhci, "op reg status = %08x\n", status);
xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
}
+static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
+{
+ u64 val_64;
+
+ /* step 2: initialize command ring buffer */
+ val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+ val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
+ (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
+ xhci->cmd_ring->dequeue) &
+ (u64) ~CMD_RING_RSVD_BITS) |
+ xhci->cmd_ring->cycle_state;
+ xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
+ (long unsigned long) val_64);
+ xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
+}
+
+/*
+ * The whole command ring must be cleared to zero when we suspend the host.
+ *
+ * The host doesn't save the command ring pointer in the suspend well, so we
+ * need to re-program it on resume. Unfortunately, the pointer must be 64-byte
+ * aligned, because of the reserved bits in the command ring dequeue pointer
+ * register. Therefore, we can't just set the dequeue pointer back in the
+ * middle of the ring (TRBs are 16-byte aligned).
+ */
+static void xhci_clear_command_ring(struct xhci_hcd *xhci)
+{
+ struct xhci_ring *ring;
+ struct xhci_segment *seg;
+
+ ring = xhci->cmd_ring;
+ seg = ring->deq_seg;
+ do {
+ memset(seg->trbs, 0, SEGMENT_SIZE);
+ seg = seg->next;
+ } while (seg != ring->deq_seg);
+
+ /* Reset the software enqueue and dequeue pointers */
+ ring->deq_seg = ring->first_seg;
+ ring->dequeue = ring->first_seg->trbs;
+ ring->enq_seg = ring->deq_seg;
+ ring->enqueue = ring->dequeue;
+
+ /*
+ * Ring is now zeroed, so the HW should look for change of ownership
+ * when the cycle bit is set to 1.
+ */
+ ring->cycle_state = 1;
+
+ /*
+ * Reset the hardware dequeue pointer.
+ * Yes, this will need to be re-written after resume, but we're paranoid
+ * and want to make sure the hardware doesn't access bogus memory
+ * because, say, the BIOS or an SMI started the host without changing
+ * the command ring pointers.
+ */
+ xhci_set_cmd_ring_deq(xhci);
+}
+
/*
* Stop HC (not bus-specific)
*
spin_unlock_irq(&xhci->lock);
return -ETIMEDOUT;
}
+ xhci_clear_command_ring(xhci);
/* step 3: save registers */
xhci_save_registers(xhci);
u32 command, temp = 0;
struct usb_hcd *hcd = xhci_to_hcd(xhci);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
- u64 val_64;
int old_state, retval;
old_state = hcd->state;
/* step 1: restore register */
xhci_restore_registers(xhci);
/* step 2: initialize command ring buffer */
- val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
- val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
- (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
- xhci->cmd_ring->dequeue) &
- (u64) ~CMD_RING_RSVD_BITS) |
- xhci->cmd_ring->cycle_state;
- xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
- (long unsigned long) val_64);
- xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
+ xhci_set_cmd_ring_deq(xhci);
/* step 3: restore state and start state*/
/* step 3: set CRS flag */
command = xhci_readl(xhci, &xhci->op_regs->command);
return retval;
}
+ spin_unlock_irq(&xhci->lock);
/* Re-setup MSI-X */
if (hcd->irq)
free_irq(hcd->irq, hcd);
hcd->irq = pdev->irq;
}
+ spin_lock_irq(&xhci->lock);
/* step 4: set Run/Stop bit */
command = xhci_readl(xhci, &xhci->op_regs->command);
command |= CMD_RUN;
cmd_completion = command->completion;
cmd_status = &command->status;
command->command_trb = xhci->cmd_ring->enqueue;
+
+ /* Enqueue pointer can be left pointing to the link TRB,
+ * we must handle that
+ */
+ if ((command->command_trb->link.control & TRB_TYPE_BITMASK)
+ == TRB_TYPE(TRB_LINK))
+ command->command_trb =
+ xhci->cmd_ring->enq_seg->next->trbs;
+
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
} else {
in_ctx = virt_dev->in_ctx;
/* Attempt to submit the Reset Device command to the command ring */
spin_lock_irqsave(&xhci->lock, flags);
reset_device_cmd->command_trb = xhci->cmd_ring->enqueue;
+
+ /* Enqueue pointer can be left pointing to the link TRB,
+ * we must handle that
+ */
+ if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK)
+ == TRB_TYPE(TRB_LINK))
+ reset_device_cmd->command_trb =
+ xhci->cmd_ring->enq_seg->next->trbs;
+
list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
ret = xhci_queue_reset_device(xhci, slot_id);
if (ret) {
#define STREAM_ID_TO_DB(p) (((p) & 0xffff) << 16)
+/**
+ * struct xhci_protocol_caps
+ * @revision: major revision, minor revision, capability ID,
+ * and next capability pointer.
+ * @name_string: Four ASCII characters to say which spec this xHC
+ * follows, typically "USB ".
+ * @port_info: Port offset, count, and protocol-defined information.
+ */
+struct xhci_protocol_caps {
+ u32 revision;
+ u32 name_string;
+ u32 port_info;
+};
+
+#define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff)
+#define XHCI_EXT_PORT_OFF(x) ((x) & 0xff)
+#define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff)
+
/**
* struct xhci_container_ctx
* @type: Type of context. Used to calculated offsets to contained contexts.
#define MAX_PACKET_MASK (0xffff << 16)
#define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff)
+/* Get max packet size from ep desc. Bit 10..0 specify the max packet size.
+ * USB2.0 spec 9.6.6.
+ */
+#define GET_MAX_PACKET(p) ((p) & 0x7ff)
+
/* tx_info bitmasks */
#define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff)
#define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16)
u32 suspended_ports[8]; /* which ports are
suspended */
unsigned long resume_done[MAX_HC_PORTS];
+ /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
+ u8 *port_array;
+ /* Array of pointers to USB 3.0 PORTSC registers */
+ u32 __iomem **usb3_ports;
+ unsigned int num_usb3_ports;
+ /* Array of pointers to USB 2.0 PORTSC registers */
+ u32 __iomem **usb2_ports;
+ unsigned int num_usb2_ports;
};
/* For testing purposes */
}
static int
-mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback);
+mts_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *srb);
static void mts_transfer_cleanup( struct urb *transfer );
static void mts_do_sg(struct urb * transfer);
static int
-mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
+mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
{
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
int err = 0;
return err;
}
+static DEF_SCSI_QCMD(mts_scsi_queuecommand)
+
static struct scsi_host_template mts_scsi_host_template = {
.module = THIS_MODULE,
.name = "microtekX6",
return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1);
}
-static DEVICE_ATTR(port0, S_IWUGO | S_IRUGO,
- get_port0_handler, set_port0_handler);
+static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR, get_port0_handler, set_port0_handler);
-static DEVICE_ATTR(port1, S_IWUGO | S_IRUGO,
- get_port1_handler, set_port1_handler);
+static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR, get_port1_handler, set_port1_handler);
static int cypress_probe(struct usb_interface *interface,
return count;
}
-static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed);
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR, show_speed, set_speed);
static int tv_probe(struct usb_interface *interface,
const struct usb_device_id *id)
change_color(led); \
return count; \
} \
-static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value);
show_set(blue);
show_set(red);
show_set(green);
\
return count; \
} \
-static DEVICE_ATTR(name, S_IWUGO | S_IRUGO, show_attr_##name, set_attr_##name);
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_attr_##name, set_attr_##name);
static ssize_t show_attr_text(struct device *dev,
struct device_attribute *attr, char *buf)
return count;
}
-static DEVICE_ATTR(text, S_IWUGO | S_IRUGO, show_attr_text, set_attr_text);
+static DEVICE_ATTR(text, S_IRUGO | S_IWUSR, show_attr_text, set_attr_text);
static ssize_t show_attr_decimals(struct device *dev,
struct device_attribute *attr, char *buf)
return count;
}
-static DEVICE_ATTR(decimals, S_IWUGO | S_IRUGO,
- show_attr_decimals, set_attr_decimals);
+static DEVICE_ATTR(decimals, S_IRUGO | S_IWUSR, show_attr_decimals, set_attr_decimals);
static ssize_t show_attr_textmode(struct device *dev,
struct device_attribute *attr, char *buf)
return -EINVAL;
}
-static DEVICE_ATTR(textmode, S_IWUGO | S_IRUGO,
- show_attr_textmode, set_attr_textmode);
+static DEVICE_ATTR(textmode, S_IRUGO | S_IWUSR, show_attr_textmode, set_attr_textmode);
MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered);
.open = yurex_open,
.release = yurex_release,
.fasync = yurex_fasync,
+ .llseek = default_llseek,
};
#include <linux/poll.h>
#include <linux/compat.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include "usb_mon.h"
* Otherwise, wait till the gadget driver hooks up.
*/
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
MUSB_HST_MODE(musb);
musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_IDLE;
status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+ hcd->self.uses_pio_for_control = 1;
DBG(1, "%s mode, status %d, devctl %02x %c\n",
"HOST", status,
musb_readb(musb->mregs, MUSB_DEVCTL),
/* ----------------------------------------------------------------------- */
+/* Maps the buffer to dma */
+
+static inline void map_dma_buffer(struct musb_request *request,
+ struct musb *musb)
+{
+ if (request->request.dma == DMA_ADDR_INVALID) {
+ request->request.dma = dma_map_single(
+ musb->controller,
+ request->request.buf,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->mapped = 1;
+ } else {
+ dma_sync_single_for_device(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->mapped = 0;
+ }
+}
+
+/* Unmap the buffer from dma and maps it back to cpu */
+static inline void unmap_dma_buffer(struct musb_request *request,
+ struct musb *musb)
+{
+ if (request->request.dma == DMA_ADDR_INVALID) {
+ DBG(20, "not unmapping a never mapped buffer\n");
+ return;
+ }
+ if (request->mapped) {
+ dma_unmap_single(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->request.dma = DMA_ADDR_INVALID;
+ request->mapped = 0;
+ } else {
+ dma_sync_single_for_cpu(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ }
+}
+
/*
* Immediately complete a request.
*
ep->busy = 1;
spin_unlock(&musb->lock);
- if (is_dma_capable()) {
- if (req->mapped) {
- dma_unmap_single(musb->controller,
- req->request.dma,
- req->request.length,
- req->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->request.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else if (req->request.dma != DMA_ADDR_INVALID)
- dma_sync_single_for_cpu(musb->controller,
- req->request.dma,
- req->request.length,
- req->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- }
+ if (is_dma_capable() && ep->dma)
+ unmap_dma_buffer(req, musb);
if (request->status == 0)
DBG(5, "%s done request %p, %d/%d\n",
ep->end_point.name, request,
#endif
if (!use_dma) {
+ /*
+ * Unmap the dma buffer back to cpu if dma channel
+ * programming fails
+ */
+ if (is_dma_capable() && musb_ep->dma)
+ unmap_dma_buffer(req, musb);
+
musb_write_fifo(musb_ep->hw_ep, fifo_count,
(u8 *) (request->buf + request->actual));
request->actual += fifo_count;
return;
}
#endif
+ /*
+ * Unmap the dma buffer back to cpu if dma channel
+ * programming fails. This buffer is mapped if the
+ * channel allocation is successful
+ */
+ if (is_dma_capable() && musb_ep->dma) {
+ unmap_dma_buffer(req, musb);
+
+ /*
+ * Clear DMAENAB and AUTOCLEAR for the
+ * PIO mode transfer
+ */
+ csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
(request->buf + request->actual));
if (!request)
return;
}
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
exit:
+#endif
/* Analyze request */
rxstate(musb, to_musb_request(request));
}
request->epnum = musb_ep->current_epnum;
request->tx = musb_ep->is_in;
- if (is_dma_capable() && musb_ep->dma) {
- if (request->request.dma == DMA_ADDR_INVALID) {
- request->request.dma = dma_map_single(
- musb->controller,
- request->request.buf,
- request->request.length,
- request->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- request->mapped = 1;
- } else {
- dma_sync_single_for_device(musb->controller,
- request->request.dma,
- request->request.length,
- request->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- request->mapped = 0;
- }
- } else
+ if (is_dma_capable() && musb_ep->dma)
+ map_dma_buffer(request, musb);
+ else
request->mapped = 0;
spin_lock_irqsave(&musb->lock, lockflags);
spin_unlock_irqrestore(&musb->lock, flags);
if (is_otg_enabled(musb)) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
DBG(3, "OTG startup...\n");
/* REVISIT: funcall to other code, which also
musb->gadget_driver = NULL;
musb->g.dev.driver = NULL;
spin_unlock_irqrestore(&musb->lock, flags);
+ } else {
+ hcd->self.uses_pio_for_control = 1;
}
}
}
}
return count;
}
-static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req);
+static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req);
static ssize_t
get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
}
return count;
}
-static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO,
- get_a_bus_drop, set_a_bus_drop);
+static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, set_a_bus_drop);
static ssize_t
get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
}
return count;
}
-static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req);
+static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req);
static ssize_t
set_a_clr_err(struct device *dev, struct device_attribute *attr,
}
return count;
}
-static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err);
+static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
static struct attribute *inputs_attrs[] = {
&dev_attr_a_bus_req.attr,
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },
+ { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) },
.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
/* Lenz LI-USB Computer Interface. */
#define FTDI_LENZ_LIUSB_PID 0xD780
+/* Vardaan Enterprises Serial Interface VEUSB422R3 */
+#define FTDI_VARDAAN_PID 0xF070
+
/*
* Xsens Technologies BV products (http://www.xsens.com).
*/
*/
#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */
+#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */
/*
* Bayer Ascensia Contour blood glucose meter USB-converter cable.
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
.no_dynamic_id = 1,
+ .supports_autosuspend = 1,
};
/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
return -ENODEV;
fixup_generic(driver);
+ if (driver->usb_driver)
+ driver->usb_driver->supports_autosuspend = 1;
if (!driver->description)
driver->description = driver->driver.name;
/* queue a command */
/* This is always called with scsi_lock(host) held */
-static int queuecommand(struct scsi_cmnd *srb,
+static int queuecommand_lck(struct scsi_cmnd *srb,
void (*done)(struct scsi_cmnd *))
{
struct us_data *us = host_to_us(srb->device->host);
return 0;
}
+static DEF_SCSI_QCMD(queuecommand)
+
/***********************************************************************
* Error handling functions
***********************************************************************/
}
return result;
}
-static DEVICE_ATTR(truinst, S_IWUGO | S_IRUGO, show_truinst, NULL);
+static DEVICE_ATTR(truinst, S_IRUGO, show_truinst, NULL);
int sierra_ms_init(struct us_data *us)
{
return 0;
}
-static int uas_queuecommand(struct scsi_cmnd *cmnd,
+static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
void (*done)(struct scsi_cmnd *))
{
struct scsi_device *sdev = cmnd->device;
return 0;
}
+static DEF_SCSI_QCMD(uas_queuecommand)
+
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
{
struct scsi_device *sdev = cmnd->device;
size_t hdr_size;
struct socket *sock;
- sock = rcu_dereference_check(vq->private_data,
- lockdep_is_held(&vq->mutex));
+ /* TODO: check that we are running from vhost_worker?
+ * Not sure it's worth it, it's straight-forward enough. */
+ sock = rcu_dereference_check(vq->private_data, 1);
if (!sock)
return;
int r;
if (!write_length)
return 0;
+ write_length += write_address % VHOST_PAGE_SIZE;
write_address /= VHOST_PAGE_SIZE;
for (;;) {
u64 base = (u64)(unsigned long)log_base;
if (write_length <= VHOST_PAGE_SIZE)
break;
write_length -= VHOST_PAGE_SIZE;
- write_address += VHOST_PAGE_SIZE;
+ write_address += 1;
}
return r;
}
{
struct backlight_device *bd = to_backlight_device(dev);
- if (bd->ops->options & BL_CORE_SUSPENDRESUME) {
- mutex_lock(&bd->ops_lock);
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
bd->props.state |= BL_CORE_SUSPENDED;
backlight_update_status(bd);
- mutex_unlock(&bd->ops_lock);
}
+ mutex_unlock(&bd->ops_lock);
return 0;
}
{
struct backlight_device *bd = to_backlight_device(dev);
- if (bd->ops->options & BL_CORE_SUSPENDRESUME) {
- mutex_lock(&bd->ops_lock);
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
bd->props.state &= ~BL_CORE_SUSPENDED;
backlight_update_status(bd);
- mutex_unlock(&bd->ops_lock);
}
+ mutex_unlock(&bd->ops_lock);
return 0;
}
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/screen_info.h>
-#include <linux/smp_lock.h>
#include <video/vga.h>
#include <asm/io.h>
goto err_release_pl_mem;
}
- ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
- if (ret)
- goto err_release_pl_mem;
-
/* Initialize par */
da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp;
ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
if (ret)
- goto err_free_irq;
+ goto err_release_pl_mem;
da8xx_fb_info->cmap.len = par->palette_sz;
/* initialize var_screeninfo */
goto err_cpu_freq;
}
#endif
+
+ ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
+ if (ret)
+ goto irq_freq;
return 0;
+irq_freq:
#ifdef CONFIG_CPU_FREQ
err_cpu_freq:
unregister_framebuffer(da8xx_fb_info);
err_dealloc_cmap:
fb_dealloc_cmap(&da8xx_fb_info->cmap);
-err_free_irq:
- free_irq(par->irq, par);
-
err_release_pl_mem:
dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base,
par->p_palette_base);
* @cmap: frame buffer colormap structure
* @len: length of @cmap
* @transp: boolean, 1 if there is transparency, 0 otherwise
+ * @flags: flags for kmalloc memory allocation
*
* Allocates memory for a colormap @cmap. @len is the
* number of entries in the palette.
*
*/
-int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
+int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
{
- int size = len*sizeof(u16);
-
- if (cmap->len != len) {
- fb_dealloc_cmap(cmap);
- if (!len)
- return 0;
- if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
- goto fail;
- if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
- goto fail;
- if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
- goto fail;
- if (transp) {
- if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
+ int size = len * sizeof(u16);
+ int ret = -ENOMEM;
+
+ if (cmap->len != len) {
+ fb_dealloc_cmap(cmap);
+ if (!len)
+ return 0;
+
+ cmap->red = kmalloc(size, flags);
+ if (!cmap->red)
+ goto fail;
+ cmap->green = kmalloc(size, flags);
+ if (!cmap->green)
+ goto fail;
+ cmap->blue = kmalloc(size, flags);
+ if (!cmap->blue)
+ goto fail;
+ if (transp) {
+ cmap->transp = kmalloc(size, flags);
+ if (!cmap->transp)
+ goto fail;
+ } else {
+ cmap->transp = NULL;
+ }
+ }
+ cmap->start = 0;
+ cmap->len = len;
+ ret = fb_copy_cmap(fb_default_cmap(len), cmap);
+ if (ret)
goto fail;
- } else
- cmap->transp = NULL;
- }
- cmap->start = 0;
- cmap->len = len;
- fb_copy_cmap(fb_default_cmap(len), cmap);
- return 0;
+ return 0;
fail:
- fb_dealloc_cmap(cmap);
- return -ENOMEM;
+ fb_dealloc_cmap(cmap);
+ return ret;
+}
+
+int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
+{
+ return fb_alloc_cmap_gfp(cmap, len, transp, GFP_ATOMIC);
}
/**
int rc, size = cmap->len * sizeof(u16);
struct fb_cmap umap;
+ if (size < 0 || size < cmap->len)
+ return -E2BIG;
+
memset(&umap, 0, sizeof(struct fb_cmap));
- rc = fb_alloc_cmap(&umap, cmap->len, cmap->transp != NULL);
+ rc = fb_alloc_cmap_gfp(&umap, cmap->len, cmap->transp != NULL,
+ GFP_KERNEL);
if (rc)
return rc;
if (copy_from_user(umap.red, cmap->red, size) ||
#define DC_HFILT_COUNT 0x100
#define DC_VFILT_COUNT 0x100
#define VP_COEFF_SIZE 0x1000
+#define VP_PAL_COUNT 0x100
#define OUTPUT_CRT 0x01
#define OUTPUT_PANEL 0x02
uint64_t vp[VP_REG_COUNT];
uint64_t fp[FP_REG_COUNT];
- uint32_t pal[DC_PAL_COUNT];
+ uint32_t dc_pal[DC_PAL_COUNT];
+ uint32_t vp_pal[VP_PAL_COUNT];
uint32_t hcoeff[DC_HFILT_COUNT * 2];
uint32_t vcoeff[DC_VFILT_COUNT];
uint32_t vp_coeff[VP_COEFF_SIZE / 4];
write_fp(par, FP_PT1, 0);
temp = FP_PT2_SCRC;
- if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
temp |= FP_PT2_HSP;
- if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
temp |= FP_PT2_VSP;
write_fp(par, FP_PT2, temp);
memcpy(par->vp, par->vp_regs, sizeof(par->vp));
memcpy(par->fp, par->vp_regs + VP_FP_START, sizeof(par->fp));
- /* save the palette */
+ /* save the display controller palette */
write_dc(par, DC_PAL_ADDRESS, 0);
- for (i = 0; i < ARRAY_SIZE(par->pal); i++)
- par->pal[i] = read_dc(par, DC_PAL_DATA);
+ for (i = 0; i < ARRAY_SIZE(par->dc_pal); i++)
+ par->dc_pal[i] = read_dc(par, DC_PAL_DATA);
+
+ /* save the video processor palette */
+ write_vp(par, VP_PAR, 0);
+ for (i = 0; i < ARRAY_SIZE(par->vp_pal); i++)
+ par->vp_pal[i] = read_vp(par, VP_PDR);
/* save the horizontal filter coefficients */
filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL;
/* restore the palette */
write_dc(par, DC_PAL_ADDRESS, 0);
- for (i = 0; i < ARRAY_SIZE(par->pal); i++)
- write_dc(par, DC_PAL_DATA, par->pal[i]);
+ for (i = 0; i < ARRAY_SIZE(par->dc_pal); i++)
+ write_dc(par, DC_PAL_DATA, par->dc_pal[i]);
/* restore the horizontal filter coefficients */
filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL;
}
}
+ /* restore video processor palette */
+ write_vp(par, VP_PAR, 0);
+ for (i = 0; i < ARRAY_SIZE(par->vp_pal); i++)
+ write_vp(par, VP_PDR, par->vp_pal[i]);
+
/* restore video coeff ram */
memcpy(par->vp_regs + VP_VCR, par->vp_coeff, sizeof(par->vp_coeff));
}
abs(cmode->yres - mode->yres);
if (diff > d) {
diff = d;
+ diff_refresh = abs(cmode->refresh - mode->refresh);
best = cmode;
} else if (diff == d) {
d = abs(cmode->refresh - mode->refresh);
#include <linux/clk.h>
#include <linux/mutex.h>
+#include <mach/dma.h>
#include <mach/hardware.h>
#include <mach/ipu.h>
#include <mach/mx3fb.h>
struct device *dev;
struct mx3fb_platform_data *mx3fb_pdata;
+ if (!imx_dma_is_ipu(chan))
+ return false;
+
if (!rq)
return false;
/* Couldn't reconfigure, hopefully, can continue as before */
return;
- info->fix.line_length = mode2.xres * (ch->cfg.bpp / 8);
+ info->fix.line_length = mode1.xres * (ch->cfg.bpp / 8);
/*
* fb_set_var() calls the notifier change internally, only if
* user event, we have to call the chain ourselves.
*/
event.info = info;
- event.data = &mode2;
+ event.data = &mode1;
fb_notifier_call_chain(evnt, &event);
}
#include "init.h"
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
#include "300vtbl.h"
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
#include "310vtbl.h"
#endif
/* POINTER INITIALIZATION */
/*********************************************/
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static void
InitCommonPointer(struct SiS_Private *SiS_Pr)
{
}
#endif
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static void
InitTo300Pointer(struct SiS_Private *SiS_Pr)
{
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
InitTo310Pointer(struct SiS_Private *SiS_Pr)
{
SiSInitPtr(struct SiS_Private *SiS_Pr)
{
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
InitTo300Pointer(SiS_Pr);
#else
return false;
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
InitTo310Pointer(SiS_Pr);
#else
return false;
/* HELPER: Get ModeID */
/*********************************************/
-#ifndef SIS_XORG_XF86
static
-#endif
unsigned short
SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay,
int Depth, bool FSTN, int LCDwidth, int LCDheight)
void
SiS_SetReg(SISIOADDRESS port, unsigned short index, unsigned short data)
{
- OutPortByte(port, index);
- OutPortByte(port + 1, data);
+ outb((u8)index, port);
+ outb((u8)data, port + 1);
}
void
SiS_SetRegByte(SISIOADDRESS port, unsigned short data)
{
- OutPortByte(port, data);
+ outb((u8)data, port);
}
void
SiS_SetRegShort(SISIOADDRESS port, unsigned short data)
{
- OutPortWord(port, data);
+ outw((u16)data, port);
}
void
SiS_SetRegLong(SISIOADDRESS port, unsigned int data)
{
- OutPortLong(port, data);
+ outl((u32)data, port);
}
unsigned char
SiS_GetReg(SISIOADDRESS port, unsigned short index)
{
- OutPortByte(port, index);
- return(InPortByte(port + 1));
+ outb((u8)index, port);
+ return inb(port + 1);
}
unsigned char
SiS_GetRegByte(SISIOADDRESS port)
{
- return(InPortByte(port));
+ return inb(port);
}
unsigned short
SiS_GetRegShort(SISIOADDRESS port)
{
- return(InPortWord(port));
+ return inw(port);
}
unsigned int
SiS_GetRegLong(SISIOADDRESS port)
{
- return(InPortLong(port));
+ return inl(port);
}
void
SiSInitPCIetc(struct SiS_Private *SiS_Pr)
{
switch(SiS_Pr->ChipType) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
case SIS_300:
case SIS_540:
case SIS_630:
SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x5A);
break;
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
case SIS_315H:
case SIS_315:
case SIS_315PRO:
/* HELPER: SetLVDSetc */
/*********************************************/
-#ifdef SIS_LINUX_KERNEL
static
-#endif
void
SiSSetLVDSetc(struct SiS_Private *SiS_Pr)
{
if((temp == 1) || (temp == 2)) return;
switch(SiS_Pr->ChipType) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
case SIS_540:
case SIS_630:
case SIS_730:
}
break;
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
case SIS_550:
case SIS_650:
case SIS_740:
/* HELPER: GetVBType */
/*********************************************/
-#ifdef SIS_LINUX_KERNEL
static
-#endif
void
SiS_GetVBType(struct SiS_Private *SiS_Pr)
{
/* HELPER: Check RAM size */
/*********************************************/
-#ifdef SIS_LINUX_KERNEL
static bool
SiS_CheckMemorySize(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex)
if(AdapterMemSize < memorysize) return false;
return true;
}
-#endif
/*********************************************/
/* HELPER: Get DRAM type */
/*********************************************/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static unsigned char
SiS_Get310DRAMType(struct SiS_Private *SiS_Pr)
{
/* HELPER: ClearBuffer */
/*********************************************/
-#ifdef SIS_LINUX_KERNEL
static void
SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
if(SiS_Pr->SiS_ModeType >= ModeEGA) {
if(ModeNo > 0x13) {
- SiS_SetMemory(memaddr, memsize, 0);
+ memset_io(memaddr, 0, memsize);
} else {
pBuffer = (unsigned short SISIOMEMTYPE *)memaddr;
for(i = 0; i < 0x4000; i++) writew(0x0000, &pBuffer[i]);
pBuffer = (unsigned short SISIOMEMTYPE *)memaddr;
for(i = 0; i < 0x4000; i++) writew(0x0720, &pBuffer[i]);
} else {
- SiS_SetMemory(memaddr, 0x8000, 0);
+ memset_io(memaddr, 0, 0x8000);
}
}
-#endif
/*********************************************/
/* HELPER: SearchModeID */
SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F);
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType == XGI_20) {
SiS_SetReg(SiS_Pr->SiS_P3d4,0x04,crt1data[4] - 1);
if(!(temp = crt1data[5] & 0x1f)) {
SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,clkb);
if(SiS_Pr->ChipType >= SIS_315H) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x01);
if(SiS_Pr->ChipType == XGI_20) {
unsigned short mf = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex);
/* FIFO */
/*********************************************/
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
void
SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1,
unsigned short *idx2)
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data);
/* Write foreground and background queue */
-#ifdef SIS_LINUX_KERNEL
templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50);
-#else
- templ = pciReadLong(0x00000000, 0x50);
-#endif
if(SiS_Pr->ChipType == SIS_730) {
}
-#ifdef SIS_LINUX_KERNEL
sisfb_write_nbridge_pci_dword(SiS_Pr, 0x50, templ);
templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xA0);
-#else
- pciWriteLong(0x00000000, 0x50, templ);
- templ = pciReadLong(0x00000000, 0xA0);
-#endif
/* GUI grant timer (PCI config 0xA3) */
if(SiS_Pr->ChipType == SIS_730) {
}
-#ifdef SIS_LINUX_KERNEL
sisfb_write_nbridge_pci_dword(SiS_Pr, 0xA0, templ);
-#else
- pciWriteLong(0x00000000, 0xA0, templ);
-#endif
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex)
{
}
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(VCLK > 150) data |= 0x80;
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data);
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data);
#endif
} else if(SiS_Pr->ChipType < XGI_20) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(VCLK >= 166) data |= 0x0c;
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
}
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(VCLK >= 200) data |= 0x0c;
if(SiS_Pr->ChipType == XGI_20) data &= ~0x04;
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
unsigned short ModeIdIndex, unsigned short RRTI)
{
unsigned short data, infoflag = 0, modeflag, resindex;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned short data2, data3;
#endif
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data);
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb);
}
SiS_SetVCLKState(SiS_Pr, ModeNo, RRTI, ModeIdIndex);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) ||
(SiS_Pr->ChipType == XGI_40)) {
if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
#endif
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
SiS_SetupDualChip(struct SiS_Private *SiS_Pr)
{
SiS_Pr->SiS_SelectCRT2Rate = 0;
SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
-#ifdef SIS_XORG_XF86
- xf86DrvMsgVerb(0, X_PROBED, 4, "(init: VBType=0x%04x, VBInfo=0x%04x)\n",
- SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo);
-#endif
-
if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) {
if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
}
switch(SiS_Pr->ChipType) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
case SIS_300:
SiS_SetCRT1FIFO_300(SiS_Pr, ModeNo, RefreshRateTableIndex);
break;
break;
#endif
default:
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType == XGI_20) {
unsigned char sr2b = 0, sr2c = 0;
switch(ModeNo) {
SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType == XGI_40) {
SiS_SetupDualChip(SiS_Pr);
}
SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex);
-#ifdef SIS_LINUX_KERNEL
if(SiS_Pr->SiS_flag_clearbuffer) {
SiS_ClearBuffer(SiS_Pr, ModeNo);
}
-#endif
if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA))) {
SiS_WaitRetrace1(SiS_Pr);
static void
SiS_ResetVB(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned short temp;
* which locks CRT2 in some way to CRT1 timing. Disable
* this here.
*/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if((IS_SIS651) || (IS_SISM650) ||
SiS_Pr->ChipType == SIS_340 ||
SiS_Pr->ChipType == XGI_40) {
static void
SiS_Handle760(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned int somebase;
unsigned char temp1, temp2, temp3;
(!(SiS_Pr->SiS_SysFlags & SF_760UMA)) )
return;
-#ifdef SIS_LINUX_KERNEL
somebase = sisfb_read_mio_pci_word(SiS_Pr, 0x74);
-#else
- somebase = pciReadWord(0x00001000, 0x74);
-#endif
somebase &= 0xffff;
if(somebase == 0) return;
temp2 = 0x0b;
}
-#ifdef SIS_LINUX_KERNEL
sisfb_write_nbridge_pci_byte(SiS_Pr, 0x7e, temp1);
sisfb_write_nbridge_pci_byte(SiS_Pr, 0x8d, temp2);
-#else
- pciWriteByte(0x00000000, 0x7e, temp1);
- pciWriteByte(0x00000000, 0x8d, temp2);
-#endif
SiS_SetRegByte((somebase + 0x85), temp3);
#endif
}
-/*********************************************/
-/* X.org/XFree86: SET SCREEN PITCH */
-/*********************************************/
-
-#ifdef SIS_XORG_XF86
-static void
-SiS_SetPitchCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
-{
- SISPtr pSiS = SISPTR(pScrn);
- unsigned short HDisplay = pSiS->scrnPitch >> 3;
-
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,(HDisplay & 0xFF));
- SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,(HDisplay >> 8));
-}
-
-static void
-SiS_SetPitchCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
-{
- SISPtr pSiS = SISPTR(pScrn);
- unsigned short HDisplay = pSiS->scrnPitch2 >> 3;
-
- /* Unlock CRT2 */
- if(pSiS->VGAEngine == SIS_315_VGA)
- SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2F, 0x01);
- else
- SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24, 0x01);
-
- SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(HDisplay & 0xFF));
- SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0xF0,(HDisplay >> 8));
-}
-
-static void
-SiS_SetPitch(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
-{
- SISPtr pSiS = SISPTR(pScrn);
- bool isslavemode = false;
-
- if( (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
- ( ((pSiS->VGAEngine == SIS_300_VGA) &&
- (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
- ((pSiS->VGAEngine == SIS_315_VGA) &&
- (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) {
- isslavemode = true;
- }
-
- /* We need to set pitch for CRT1 if bridge is in slave mode, too */
- if((pSiS->VBFlags & DISPTYPE_DISP1) || (isslavemode)) {
- SiS_SetPitchCRT1(SiS_Pr, pScrn);
- }
- /* We must not set the pitch for CRT2 if bridge is in slave mode */
- if((pSiS->VBFlags & DISPTYPE_DISP2) && (!isslavemode)) {
- SiS_SetPitchCRT2(SiS_Pr, pScrn);
- }
-}
-#endif
-
/*********************************************/
/* SiSSetMode() */
/*********************************************/
-#ifdef SIS_XORG_XF86
-/* We need pScrn for setting the pitch correctly */
-bool
-SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo, bool dosetpitch)
-#else
bool
SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
-#endif
{
SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
unsigned short RealModeNo, ModeIdIndex;
unsigned char backupreg = 0;
-#ifdef SIS_LINUX_KERNEL
unsigned short KeepLockReg;
SiS_Pr->UseCustomMode = false;
SiS_Pr->CRT1UsesCustomMode = false;
-#endif
SiS_Pr->SiS_flag_clearbuffer = 0;
if(SiS_Pr->UseCustomMode) {
ModeNo = 0xfe;
} else {
-#ifdef SIS_LINUX_KERNEL
if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1;
-#endif
ModeNo &= 0x7f;
}
SiS_GetSysFlags(SiS_Pr);
SiS_Pr->SiS_VGAINFO = 0x11;
-#if defined(SIS_XORG_XF86) && (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__))
- if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
-#endif
-#ifdef SIS_LINUX_KERNEL
KeepLockReg = SiS_GetReg(SiS_Pr->SiS_P3c4,0x05);
-#endif
SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
SiSInitPCIetc(SiS_Pr);
SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex);
SiS_SetLowModeTest(SiS_Pr, ModeNo);
-#ifdef SIS_LINUX_KERNEL
/* Check memory size (kernel framebuffer driver only) */
if(!SiS_CheckMemorySize(SiS_Pr, ModeNo, ModeIdIndex)) {
return false;
}
-#endif
SiS_OpenCRTC(SiS_Pr);
SiS_DisplayOn(SiS_Pr);
SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
if(!(SiS_IsDualEdge(SiS_Pr))) {
if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
if(SiS_Pr->ChipType >= SIS_315H) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(!SiS_Pr->SiS_ROMNew) {
if(SiS_IsVAMode(SiS_Pr)) {
SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
}
}
-#ifdef SIS_XORG_XF86
- if(pScrn) {
- /* SetPitch: Adapt to virtual size & position */
- if((ModeNo > 0x13) && (dosetpitch)) {
- SiS_SetPitch(SiS_Pr, pScrn);
- }
-
- /* Backup/Set ModeNo in BIOS scratch area */
- SiS_GetSetModeID(pScrn, ModeNo);
- }
-#endif
-
SiS_CloseCRTC(SiS_Pr);
SiS_Handle760(SiS_Pr);
-#ifdef SIS_LINUX_KERNEL
/* We never lock registers in XF86 */
if(KeepLockReg != 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00);
-#endif
return true;
}
-/*********************************************/
-/* X.org/XFree86: SiSBIOSSetMode() */
-/* for non-Dual-Head mode */
-/*********************************************/
-
-#ifdef SIS_XORG_XF86
-bool
-SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom)
-{
- SISPtr pSiS = SISPTR(pScrn);
- unsigned short ModeNo = 0;
-
- SiS_Pr->UseCustomMode = false;
-
- if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d\n",
- SiS_Pr->CHDisplay,
- (mode->Flags & V_INTERLACE ? SiS_Pr->CVDisplay * 2 :
- (mode->Flags & V_DBLSCAN ? SiS_Pr->CVDisplay / 2 :
- SiS_Pr->CVDisplay)));
-
- } else {
-
- /* Don't need vbflags here; checks done earlier */
- ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags);
- if(!ModeNo) return false;
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo);
-
- }
-
- return(SiSSetMode(SiS_Pr, pScrn, ModeNo, true));
-}
-
-/*********************************************/
-/* X.org/XFree86: SiSBIOSSetModeCRT2() */
-/* for Dual-Head modes */
-/*********************************************/
-
-bool
-SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom)
-{
- SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
- SISPtr pSiS = SISPTR(pScrn);
-#ifdef SISDUALHEAD
- SISEntPtr pSiSEnt = pSiS->entityPrivate;
-#endif
- unsigned short ModeIdIndex;
- unsigned short ModeNo = 0;
- unsigned char backupreg = 0;
-
- SiS_Pr->UseCustomMode = false;
-
- /* Remember: Custom modes for CRT2 are ONLY supported
- * -) on the 30x/B/C, and
- * -) if CRT2 is LCD or VGA, or CRT1 is LCDA
- */
-
- if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
-
- ModeNo = 0xfe;
-
- } else {
-
- ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags);
- if(!ModeNo) return false;
-
- }
-
- SiSRegInit(SiS_Pr, BaseAddr);
- SiSInitPtr(SiS_Pr);
- SiS_GetSysFlags(SiS_Pr);
-#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__)
- SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
-#else
- SiS_Pr->SiS_VGAINFO = 0x11;
-#endif
-
- SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
-
- SiSInitPCIetc(SiS_Pr);
- SiSSetLVDSetc(SiS_Pr);
- SiSDetermineROMUsage(SiS_Pr);
-
- /* Save mode info so we can set it from within SetMode for CRT1 */
-#ifdef SISDUALHEAD
- if(pSiS->DualHeadMode) {
- pSiSEnt->CRT2ModeNo = ModeNo;
- pSiSEnt->CRT2DMode = mode;
- pSiSEnt->CRT2IsCustom = IsCustom;
- pSiSEnt->CRT2CR30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
- pSiSEnt->CRT2CR31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
- pSiSEnt->CRT2CR35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
- pSiSEnt->CRT2CR38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
-#if 0
- /* We can't set CRT2 mode before CRT1 mode is set - says who...? */
- if(pSiSEnt->CRT1ModeNo == -1) {
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "Setting CRT2 mode delayed until after setting CRT1 mode\n");
- return true;
- }
-#endif
- pSiSEnt->CRT2ModeSet = true;
- }
-#endif
-
- if(SiS_Pr->UseCustomMode) {
-
- unsigned short temptemp = SiS_Pr->CVDisplay;
-
- if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1;
- else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "Setting custom mode %dx%d on CRT2\n",
- SiS_Pr->CHDisplay, temptemp);
-
- } else {
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "Setting standard mode 0x%x on CRT2\n", ModeNo);
-
- }
-
- SiS_UnLockCRT2(SiS_Pr);
-
- if(!SiS_Pr->UseCustomMode) {
- if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
- } else {
- ModeIdIndex = 0;
- }
-
- SiS_GetVBType(SiS_Pr);
-
- SiS_InitVB(SiS_Pr);
- if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
- if(SiS_Pr->ChipType >= SIS_315H) {
- SiS_ResetVB(SiS_Pr);
- SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
- SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c);
- backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
- } else {
- backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
- }
- }
-
- /* Get VB information (connectors, connected devices) */
- if(!SiS_Pr->UseCustomMode) {
- SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 1);
- } else {
- /* If this is a custom mode, we don't check the modeflag for CRT2Mode */
- SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 0);
- }
- SiS_SetYPbPr(SiS_Pr);
- SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex);
- SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex);
- SiS_SetLowModeTest(SiS_Pr, ModeNo);
-
- SiS_ResetSegmentRegisters(SiS_Pr);
-
- /* Set mode on CRT2 */
- if( (SiS_Pr->SiS_VBType & VB_SISVB) ||
- (SiS_Pr->SiS_IF_DEF_LVDS == 1) ||
- (SiS_Pr->SiS_IF_DEF_CH70xx != 0) ||
- (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) {
- SiS_SetCRT2Group(SiS_Pr, ModeNo);
- }
-
- SiS_StrangeStuff(SiS_Pr);
-
- SiS_DisplayOn(SiS_Pr);
- SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
-
- if(SiS_Pr->ChipType >= SIS_315H) {
- if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
- if(!(SiS_IsDualEdge(SiS_Pr))) {
- SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
- }
- }
- }
-
- if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
- if(SiS_Pr->ChipType >= SIS_315H) {
- if(!SiS_Pr->SiS_ROMNew) {
- if(SiS_IsVAMode(SiS_Pr)) {
- SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
- } else {
- SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE);
- }
- }
-
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
-
- if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) {
- SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
- }
- } else if((SiS_Pr->ChipType == SIS_630) ||
- (SiS_Pr->ChipType == SIS_730)) {
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
- }
- }
-
- /* SetPitch: Adapt to virtual size & position */
- SiS_SetPitchCRT2(SiS_Pr, pScrn);
-
- SiS_Handle760(SiS_Pr);
-
- return true;
-}
-
-/*********************************************/
-/* X.org/XFree86: SiSBIOSSetModeCRT1() */
-/* for Dual-Head modes */
-/*********************************************/
-
-bool
-SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom)
-{
- SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
- SISPtr pSiS = SISPTR(pScrn);
- unsigned short ModeIdIndex, ModeNo = 0;
- unsigned char backupreg = 0;
-#ifdef SISDUALHEAD
- SISEntPtr pSiSEnt = pSiS->entityPrivate;
- unsigned char backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0;
- bool backupcustom;
-#endif
-
- SiS_Pr->UseCustomMode = false;
-
- if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
-
- unsigned short temptemp = SiS_Pr->CVDisplay;
-
- if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1;
- else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "Setting custom mode %dx%d on CRT1\n",
- SiS_Pr->CHDisplay, temptemp);
- ModeNo = 0xfe;
-
- } else {
-
- ModeNo = SiS_GetModeNumber(pScrn, mode, 0); /* don't give VBFlags */
- if(!ModeNo) return false;
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "Setting standard mode 0x%x on CRT1\n", ModeNo);
- }
-
- SiSInitPtr(SiS_Pr);
- SiSRegInit(SiS_Pr, BaseAddr);
- SiS_GetSysFlags(SiS_Pr);
-#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__)
- SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
-#else
- SiS_Pr->SiS_VGAINFO = 0x11;
-#endif
-
- SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
-
- SiSInitPCIetc(SiS_Pr);
- SiSSetLVDSetc(SiS_Pr);
- SiSDetermineROMUsage(SiS_Pr);
-
- SiS_UnLockCRT2(SiS_Pr);
-
- if(!SiS_Pr->UseCustomMode) {
- if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
- } else {
- ModeIdIndex = 0;
- }
-
- /* Determine VBType */
- SiS_GetVBType(SiS_Pr);
-
- SiS_InitVB(SiS_Pr);
- if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
- if(SiS_Pr->ChipType >= SIS_315H) {
- backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
- } else {
- backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
- }
- }
-
- /* Get VB information (connectors, connected devices) */
- /* (We don't care if the current mode is a CRT2 mode) */
- SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 0);
- SiS_SetYPbPr(SiS_Pr);
- SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex);
- SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex);
- SiS_SetLowModeTest(SiS_Pr, ModeNo);
-
- SiS_OpenCRTC(SiS_Pr);
-
- /* Set mode on CRT1 */
- SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex);
- if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
- SiS_SetCRT2Group(SiS_Pr, ModeNo);
- }
-
- /* SetPitch: Adapt to virtual size & position */
- SiS_SetPitchCRT1(SiS_Pr, pScrn);
-
- SiS_HandleCRT1(SiS_Pr);
-
- SiS_StrangeStuff(SiS_Pr);
-
- SiS_CloseCRTC(SiS_Pr);
-
-#ifdef SISDUALHEAD
- if(pSiS->DualHeadMode) {
- pSiSEnt->CRT1ModeNo = ModeNo;
- pSiSEnt->CRT1DMode = mode;
- }
-#endif
-
- if(SiS_Pr->UseCustomMode) {
- SiS_Pr->CRT1UsesCustomMode = true;
- SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
- SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
- } else {
- SiS_Pr->CRT1UsesCustomMode = false;
- }
-
- /* Reset CRT2 if changing mode on CRT1 */
-#ifdef SISDUALHEAD
- if(pSiS->DualHeadMode) {
- if(pSiSEnt->CRT2ModeNo != -1) {
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "(Re-)Setting mode for CRT2\n");
- backupcustom = SiS_Pr->UseCustomMode;
- backupcr30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
- backupcr31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
- backupcr35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
- backupcr38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
- if(SiS_Pr->SiS_VBType & VB_SISVB) {
- /* Backup LUT-enable */
- if(pSiSEnt->CRT2ModeSet) {
- backupp40d = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0d) & 0x08;
- }
- }
- if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,pSiSEnt->CRT2CR30);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,pSiSEnt->CRT2CR31);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,pSiSEnt->CRT2CR35);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,pSiSEnt->CRT2CR38);
- }
-
- SiSBIOSSetModeCRT2(SiS_Pr, pSiSEnt->pScrn_1,
- pSiSEnt->CRT2DMode, pSiSEnt->CRT2IsCustom);
-
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,backupcr30);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,backupcr31);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupcr35);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupcr38);
- if(SiS_Pr->SiS_VBType & VB_SISVB) {
- SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d, ~0x08, backupp40d);
- }
- SiS_Pr->UseCustomMode = backupcustom;
- }
- }
-#endif
-
- /* Warning: From here, the custom mode entries in SiS_Pr are
- * possibly overwritten
- */
-
- SiS_DisplayOn(SiS_Pr);
- SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
-
- if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
- if(SiS_Pr->ChipType >= SIS_315H) {
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
- } else if((SiS_Pr->ChipType == SIS_630) ||
- (SiS_Pr->ChipType == SIS_730)) {
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
- }
- }
-
- SiS_Handle760(SiS_Pr);
-
- /* Backup/Set ModeNo in BIOS scratch area */
- SiS_GetSetModeID(pScrn,ModeNo);
-
- return true;
-}
-#endif /* Linux_XF86 */
-
#ifndef GETBITSTR
#define BITMASK(h,l) (((unsigned)(1U << ((h)-(l)+1))-1)<<(l))
#define GENMASK(mask) BITMASK(1?mask,0?mask)
SiS_Pr->CVBlankStart = SiS_Pr->SiS_VGAVDE;
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
tempbx = SiS_Pr->SiS_VGAHT;
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
tempbx = SiS_Pr->PanelHT;
remaining = tempbx % 8;
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
/* OK for LCDA, LVDS */
tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes;
tempax = SiS_Pr->SiS_VGAHDE; /* not /2 ! */
SiS_Pr->CHTotal = SiS_Pr->CHBlankEnd = tempbx;
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_VGAHDE == SiS_Pr->PanelXRes) {
SiS_Pr->CHSyncStart = SiS_Pr->SiS_VGAHDE + ((SiS_Pr->PanelHRS + 1) & ~1);
SiS_Pr->CHSyncEnd = SiS_Pr->CHSyncStart + SiS_Pr->PanelHRE;
}
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
tempax = VGAHDE;
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
tempbx = SiS_Pr->PanelXRes;
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
tempax = SiS_Pr->PanelYRes;
} else if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
/* Stupid hack for 640x400/320x200 */
if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
if((tempax + tempbx) == 438) tempbx += 16;
if(modeflag & DoubleScanMode) tempax |= 0x80;
SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,tempax);
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "%d %d %d %d %d %d %d %d (%d %d %d %d)\n",
- SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal,
- SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal,
- SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd);
- xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
- SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1],
- SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3],
- SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5],
- SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]);
- xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
- SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9],
- SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11],
- SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13],
- SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]);
- xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]);
-#endif
-#endif
}
void
SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
int xres, int yres,
-#ifdef SIS_XORG_XF86
- DisplayModePtr current
-#endif
-#ifdef SIS_LINUX_KERNEL
struct fb_var_screeninfo *var, bool writeres
-#endif
)
{
unsigned short HRE, HBE, HRS, HBS, HDE, HT;
D = B - F - C;
-#ifdef SIS_XORG_XF86
- current->HDisplay = (E * 8);
- current->HSyncStart = (E * 8) + (F * 8);
- current->HSyncEnd = (E * 8) + (F * 8) + (C * 8);
- current->HTotal = (E * 8) + (F * 8) + (C * 8) + (D * 8);
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO,
- "H: A %d B %d C %d D %d E %d F %d HT %d HDE %d HRS %d HBS %d HBE %d HRE %d\n",
- A, B, C, D, E, F, HT, HDE, HRS, HBS, HBE, HRE);
-#else
- (void)VBS; (void)HBS; (void)A;
-#endif
-#endif
-#ifdef SIS_LINUX_KERNEL
if(writeres) var->xres = xres = E * 8;
var->left_margin = D * 8;
var->right_margin = F * 8;
var->hsync_len = C * 8;
-#endif
/* Vertical */
sr_data = crdata[13];
D = B - F - C;
-#ifdef SIS_XORG_XF86
- current->VDisplay = VDE + 1;
- current->VSyncStart = VRS + 1;
- current->VSyncEnd = ((VRS & ~0x1f) | VRE) + 1;
- if(VRE <= (VRS & 0x1f)) current->VSyncEnd += 32;
- current->VTotal = E + D + C + F;
-#if 0
- current->VDisplay = E;
- current->VSyncStart = E + D;
- current->VSyncEnd = E + D + C;
- current->VTotal = E + D + C + F;
-#endif
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO,
- "V: A %d B %d C %d D %d E %d F %d VT %d VDE %d VRS %d VBS %d VBE %d VRE %d\n",
- A, B, C, D, E, F, VT, VDE, VRS, VBS, VBE, VRE);
-#endif
-#endif
-#ifdef SIS_LINUX_KERNEL
if(writeres) var->yres = yres = E;
var->upper_margin = D;
var->lower_margin = F;
var->vsync_len = C;
-#endif
if((xres == 320) && ((yres == 200) || (yres == 240))) {
/* Terrible hack, but correct CRTC data for
* a negative D. The CRT controller does not
* seem to like correcting HRE to 50)
*/
-#ifdef SIS_XORG_XF86
- current->HDisplay = 320;
- current->HSyncStart = 328;
- current->HSyncEnd = 376;
- current->HTotal = 400;
-#endif
-#ifdef SIS_LINUX_KERNEL
var->left_margin = (400 - 376);
var->right_margin = (328 - 320);
var->hsync_len = (376 - 328);
-#endif
}
#ifndef _INIT_H_
#define _INIT_H_
-#include "osdef.h"
#include "initdef.h"
-#ifdef SIS_XORG_XF86
-#include "sis.h"
-#define SIS_NEED_inSISREG
-#define SIS_NEED_inSISREGW
-#define SIS_NEED_inSISREGL
-#define SIS_NEED_outSISREG
-#define SIS_NEED_outSISREGW
-#define SIS_NEED_outSISREGL
-#include "sis_regs.h"
-#endif
-
-#ifdef SIS_LINUX_KERNEL
#include "vgatypes.h"
#include "vstruct.h"
#ifdef SIS_CP
#include <linux/fb.h>
#include "sis.h"
#include <video/sisfb.h>
-#endif
/* Mode numbers */
static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f};
{ 1280, 854, 8,16} /* 0x22 */
};
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static const struct SiS_StandTable_S SiS_StandTable[]=
{
/* 0x00: MD_0_200 */
};
bool SiSInitPtr(struct SiS_Private *SiS_Pr);
-#ifdef SIS_XORG_XF86
-unsigned short SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay,
- int Depth, bool FSTN, int LCDwith, int LCDheight);
-#endif
unsigned short SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay,
int VDisplay, int Depth, bool FSTN,
unsigned short CustomT, int LCDwith, int LCDheight,
void SiS_DisplayOn(struct SiS_Private *SiS_Pr);
void SiS_DisplayOff(struct SiS_Private *SiS_Pr);
void SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr);
-#ifndef SIS_LINUX_KERNEL
-void SiSSetLVDSetc(struct SiS_Private *SiS_Pr);
-#endif
void SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable);
void SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable);
unsigned short SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex);
bool SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr);
-#ifndef SIS_LINUX_KERNEL
-void SiS_GetVBType(struct SiS_Private *SiS_Pr);
-#endif
bool SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
unsigned short *ModeIdIndex);
unsigned short ModeIdIndex);
unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr,unsigned short ModeNo,
unsigned short ModeIdIndex, unsigned short RRTI);
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1,
unsigned short *idx2);
unsigned short SiS_GetFIFOThresholdB300(unsigned short idx1, unsigned short idx2);
unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index);
#endif
void SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex);
-#ifdef SIS_XORG_XF86
-bool SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo,
- bool dosetpitch);
-bool SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom);
-bool SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom);
-bool SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom);
-#endif
-#ifdef SIS_LINUX_KERNEL
bool SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
-#endif
void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth);
void SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex);
-#ifdef SIS_XORG_XF86
-void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres,
- int yres, DisplayModePtr current);
-#endif
-#ifdef SIS_LINUX_KERNEL
void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres,
int yres, struct fb_var_screeninfo *var, bool writeres);
-#endif
/* From init301.c: */
extern void SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
extern bool SiS_IsVAMode(struct SiS_Private *);
extern bool SiS_IsDualEdge(struct SiS_Private *);
-#ifdef SIS_XORG_XF86
-/* From other modules: */
-extern unsigned short SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode,
- unsigned int VBFlags);
-extern unsigned char SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, unsigned short offset,
- unsigned char value);
-extern unsigned char SiS_GetSetModeID(ScrnInfoPtr pScrn, unsigned char id);
-extern unsigned short SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode,
- unsigned int VBFlags);
-#endif
-
-#ifdef SIS_LINUX_KERNEL
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
extern unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg);
extern void sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg,
unsigned int val);
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
extern void sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg,
unsigned char val);
extern unsigned int sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg);
#endif
-#endif
#endif
#include "init301.h"
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
#include "oem300.h"
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
#include "oem310.h"
#endif
#define SiS_I2CDELAYSHORT 150
static unsigned short SiS_GetBIOSLCDResInfo(struct SiS_Private *SiS_Pr);
-#ifdef SIS_LINUX_KERNEL
static void SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val);
-#endif
/*********************************************/
/* HELPER: Lock/Unlock CRT2 */
SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01);
}
-#ifdef SIS_LINUX_KERNEL
static
-#endif
void
SiS_LockCRT2(struct SiS_Private *SiS_Pr)
{
/* HELPER: Get Pointer to LCD structure */
/*********************************************/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static unsigned char *
GetLCDStructPtr661(struct SiS_Private *SiS_Pr)
{
/* HELPER: GET SOME DATA FROM BIOS ROM */
/*********************************************/
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static bool
SiS_CR36BIOSWord23b(struct SiS_Private *SiS_Pr)
{
SiS_GetReg(SiS_Pr->SiS_P3c4, 0x05);
}
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static void
SiS_GenericDelay(struct SiS_Private *SiS_Pr, unsigned short delay)
{
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
SiS_LongDelay(struct SiS_Private *SiS_Pr, unsigned short delay)
{
}
#endif
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static void
SiS_ShortDelay(struct SiS_Private *SiS_Pr, unsigned short delay)
{
static void
SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime)
{
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned short PanelID, DelayIndex, Delay=0;
#endif
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
if(SiS_Pr->SiS_VBType & VB_SISVB) {
}
SiS_ShortDelay(SiS_Pr, Delay);
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if((SiS_Pr->ChipType >= SIS_661) ||
(SiS_Pr->ChipType <= SIS_315PRO) ||
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
SiS_PanelDelayLoop(struct SiS_Private *SiS_Pr, unsigned short DelayTime, unsigned short DelayLoop)
{
while((!(SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog);
}
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static void
SiS_WaitRetrace2(struct SiS_Private *SiS_Pr, unsigned short reg)
{
SiS_WaitVBRetrace(struct SiS_Private *SiS_Pr)
{
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return;
}
}
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) {
SiS_WaitRetrace1(SiS_Pr);
} else {
/* HELPER: MISC */
/*********************************************/
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static bool
SiS_Is301B(struct SiS_Private *SiS_Pr)
{
bool
SiS_IsDualEdge(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if((SiS_Pr->ChipType != SIS_650) || (SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0)) {
if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableDualEdge) return true;
bool
SiS_IsVAMode(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short flag;
if(SiS_Pr->ChipType >= SIS_315H) {
return false;
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsVAorLCD(struct SiS_Private *SiS_Pr)
{
static bool
SiS_IsDualLink(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if((SiS_CRT2IsLCD(SiS_Pr)) ||
(SiS_IsVAMode(SiS_Pr))) {
return false;
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_TVEnabled(struct SiS_Private *SiS_Pr)
{
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_LCDAEnabled(struct SiS_Private *SiS_Pr)
{
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_WeHaveBacklightCtrl(struct SiS_Private *SiS_Pr)
{
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsNotM650orLater(struct SiS_Private *SiS_Pr)
{
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsYPbPr(struct SiS_Private *SiS_Pr)
{
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsChScart(struct SiS_Private *SiS_Pr)
{
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsTVOrYPbPrOrScart(struct SiS_Private *SiS_Pr)
{
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsLCDOrLCDA(struct SiS_Private *SiS_Pr)
{
/*********************************************/
/* Setup general purpose IO for Chrontel communication */
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
void
SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo)
{
if(!(SiS_Pr->SiS_ChSW)) return;
-#ifdef SIS_LINUX_KERNEL
acpibase = sisfb_read_lpc_pci_dword(SiS_Pr, 0x74);
-#else
- acpibase = pciReadLong(0x00000800, 0x74);
-#endif
acpibase &= 0xFFFF;
if(!acpibase) return;
temp = SiS_GetRegShort((acpibase + 0x3c)); /* ACPI register 0x3c: GP Event 1 I/O mode select */
tempax &= (DriverMode | LoadDACFlag | SetNotSimuMode | SetPALTV);
tempbx |= tempax;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if(SiS_Pr->SiS_VBType & VB_SISLCDA) {
if(ModeNo == 0x03) {
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
if(!(SiS_Pr->SiS_VBType & VB_SISVGA2)) {
tempbx &= ~(SetCRT2ToRAMDAC);
SiS_Pr->SiS_VBInfo = tempbx;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->ChipType == SIS_630) {
SiS_SetChrontelGPIO(SiS_Pr, SiS_Pr->SiS_VBInfo);
}
#endif
-#ifdef SIS_LINUX_KERNEL
#if 0
printk(KERN_DEBUG "sisfb: (init301: VBInfo= 0x%04x, SetFlag=0x%04x)\n",
SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag);
#endif
-#endif
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_PROBED, "(init301: VBInfo=0x%04x, SetFlag=0x%04x)\n",
- SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag);
-#endif
-#endif
}
/*********************************************/
}
SiS_Pr->SiS_VBInfo &= ~SetPALTV;
-
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "(init301: TVMode %x, VBInfo %x)\n", SiS_Pr->SiS_TVMode, SiS_Pr->SiS_VBInfo);
-#endif
-#endif
}
/*********************************************/
static void
SiS_GetLCDInfoBIOS(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned char *ROMAddr;
unsigned short temp;
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Paneldata driver: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n",
- SiS_Pr->PanelHT, SiS_Pr->PanelVT,
- SiS_Pr->PanelHRS, SiS_Pr->PanelHRE,
- SiS_Pr->PanelVRS, SiS_Pr->PanelVRE,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B);
-#endif
-#endif
-
if((ROMAddr = GetLCDStructPtr661(SiS_Pr))) {
if((temp = SISGETROMW(6)) != SiS_Pr->PanelHT) {
SiS_Pr->SiS_NeedRomModeData = true;
SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2C =
SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_B = ROMAddr[20];
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Paneldata BIOS: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n",
- SiS_Pr->PanelHT, SiS_Pr->PanelVT,
- SiS_Pr->PanelHRS, SiS_Pr->PanelHRE,
- SiS_Pr->PanelVRS, SiS_Pr->PanelVRE,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B);
-#endif
-#endif
-
}
#endif
}
{
unsigned short temp,modeflag,resinfo=0,modexres=0,modeyres=0;
bool panelcanscale = false;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
static const unsigned char SiS300SeriesLCDRes[] =
{ 0, 1, 2, 3, 7, 4, 5, 8,
0, 0, 10, 0, 0, 0, 0, 15 };
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned char *myptr = NULL;
#endif
SiS_Pr->SiS_LCDTypeInfo = (temp & 0x0F) - 1;
}
temp &= 0x0f;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->ChipType < SIS_315H) {
/* Very old BIOSes only know 7 sizes (NetVista 2179, 1.01g) */
if(SiS_Pr->SiS_VBType & VB_SIS301) {
#endif
/* Translate to our internal types */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType == SIS_550) {
if (temp == Panel310_1152x768) temp = Panel_320x240_2; /* Verified working */
else if(temp == Panel310_320x240_2) temp = Panel_320x240_2;
SiS_Pr->SiS_LCDResInfo = temp;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
SiS_Pr->SiS_LCDResInfo = Panel_Barco1366;
else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
/* Dual link, Pass 1:1 BIOS default, etc. */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_661) {
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
if(temp & 0x08) SiS_Pr->SiS_LCDInfo |= LCDPass11;
}
}
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
if(SiS_Pr->SiS_CustomT == CUT_PANEL848 || SiS_Pr->SiS_CustomT == CUT_PANEL856) {
SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20; /* neg h/v sync, RGB24(D0 = 0) */
SiS_Pr->SiS_SetFlag |= LCDVESATiming;
}
-#ifdef SIS_LINUX_KERNEL
#if 0
printk(KERN_DEBUG "sisfb: (LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n",
SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo);
#endif
-#endif
-#ifdef SIS_XORG_XF86
- xf86DrvMsgVerb(0, X_PROBED, 4,
- "(init301: LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x SetFlag=0x%04x)\n",
- SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo, SiS_Pr->SiS_SetFlag);
-#endif
}
/*********************************************/
VCLKIndex = SiS_Pr->PanelVCLKIdx315;
}
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
/* Special Timing: Barco iQ Pro R series */
if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) VCLKIndex = 0x44;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "VCLKIndex %d (0x%x)\n", VCLKIndex, VCLKIndex);
-#endif
-#endif
-
return VCLKIndex;
}
{
unsigned short i, j, modeflag, tempah=0;
short tempcl;
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
unsigned short tempbl;
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned short tempah2, tempbl2;
#endif
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* ---- 300 series ---- */
+#ifdef CONFIG_FB_SIS_300 /* ---- 300 series ---- */
/* For 301BDH: (with LCD via LVDS) */
if(SiS_Pr->SiS_VBType & VB_NoLCD) {
if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0xA0;
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* ------- 315/330 series ------ */
+#ifdef CONFIG_FB_SIS_315 /* ------- 315/330 series ------ */
if(ModeNo > 0x13) {
tempcl -= ModeVGA;
if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0x50;
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
if(SiS_Pr->ChipType < SIS_315H) {
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah);
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah);
} else if(SiS_Pr->SiS_VBType & VB_SISVB) {
if(SiS_Pr->ChipType >= SIS_315H) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
/* LVDS can only be slave in 8bpp modes */
tempah = 0x80;
if((modeflag & CRT2Mode) && (SiS_Pr->SiS_ModeType > ModeVGA)) {
} else {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
tempah = 0;
if( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) && (SiS_Pr->SiS_ModeType > ModeVGA) ) {
tempah |= 0x02;
if(SiS_Pr->ChipType >= SIS_315H) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
/* unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); */
/* The following is nearly unpreditable and varies from machine
SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah);
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
} else if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f);
if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) ||
} else { /* LVDS */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
}
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
case Panel_1280x1024: tempbx = 24; break;
case Panel_1400x1050: tempbx = 26; break;
case Panel_1600x1200: tempbx = 28; break;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
case Panel_Barco1366: tempbx = 80; break;
#endif
}
if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempbx = 30;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
tempbx = 82;
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_CalcPanelLinkTiming(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
SiS_CalcLCDACRT1Timing(SiS_Pr, ModeNo, ModeIdIndex);
#endif
case 16: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1; break;
case 18: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1; break;
case 20: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
case 80: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1; break;
case 81: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2; break;
case 82: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1; break;
(SiS_Pr->SiS_SetFlag & SetDOSMode) ) {
SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes;
SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
if(ResIndex < 0x08) {
SiS_Pr->SiS_HDE = 1280;
unsigned short resinfo, CRT2Index, ResIndex;
const struct SiS_LCDData *LCDPtr = NULL;
const struct SiS_TVData *TVPtr = NULL;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
short resinfo661;
#endif
} else {
modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
resinfo661 = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].ROMMODEIDX661;
if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&
(SiS_Pr->SiS_SetFlag & LCDVESATiming) &&
} else if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) && (romptr) && (ROMAddr) ) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_Pr->SiS_RVBHCMAX = ROMAddr[romptr];
SiS_Pr->SiS_RVBHCFACT = ROMAddr[romptr+1];
SiS_Pr->SiS_VGAHT = ROMAddr[romptr+2] | ((ROMAddr[romptr+3] & 0x0f) << 8);
case Panel_1680x1050 :
case Panel_1680x1050 + 32: LCDPtr = SiS_Pr->SiS_LCD1680x1050Data; break;
case 100 : LCDPtr = SiS_Pr->SiS_NoScaleData; break;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
case 200 : LCDPtr = SiS310_ExtCompaq1280x1024Data; break;
case 201 : LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break;
#endif
default : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex);
-#endif
-#endif
-
SiS_Pr->SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX;
SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT;
SiS_Pr->SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT;
{
const struct SiS_LVDSDes *PanelDesPtr = NULL;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
if(SiS_Pr->ChipType < SIS_315H) {
if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
/* non-pass 1:1 only, see above */
if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) {
} else {
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
switch(SiS_Pr->SiS_LCDResInfo) {
case Panel_800x600:
if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) {
}
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
switch(SiS_Pr->SiS_LCDResInfo) {
case Panel_1024x768:
case Panel_1280x1024:
if(SiS_Pr->ChipType < SIS_315H) {
if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320;
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) SiS_Pr->SiS_LCDHDES = 480;
if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 804;
if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 704;
/* DISABLE VIDEO BRIDGE */
/*********************************************/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static int
SiS_HandlePWD(struct SiS_Private *SiS_Pr)
{
ret = 1;
}
SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x27,0x7f,temp);
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, 0, "Setting PWD %x\n", temp);
-#endif
-#endif
}
#endif
return ret;
void
SiS_DisableBridge(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short tempah, pushax=0, modenum;
#endif
unsigned short temp=0;
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* 300 series */
+#ifdef CONFIG_FB_SIS_300 /* 300 series */
if(!(SiS_CR36BIOSWord23b(SiS_Pr))) {
if(SiS_Pr->SiS_VBType & VB_SISLVDS) {
}
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* 315 series */
+#ifdef CONFIG_FB_SIS_315 /* 315 series */
int didpwd = 0;
bool custom1 = (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
} else { /* ============ For 301 ================ */
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(!(SiS_CR36BIOSWord23b(SiS_Pr))) {
SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08);
SiS_PanelDelay(SiS_Pr, 3);
SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp);
} else {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); /* disable CRT2 */
if( (!(SiS_CRT2IsLCD(SiS_Pr))) ||
(!(SiS_CR36BIOSWord23d(SiS_Pr))) ) {
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* 300 series */
+#ifdef CONFIG_FB_SIS_300 /* 300 series */
if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
SiS_SetCH700x(SiS_Pr,0x0E,0x09);
SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04);
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* 315 series */
+#ifdef CONFIG_FB_SIS_315 /* 315 series */
if(!(SiS_IsNotM650orLater(SiS_Pr))) {
/*if(SiS_Pr->ChipType < SIS_340) { */ /* XGI needs this */
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
} /* 315 series */
* from outside the context of a mode switch!
* MUST call getVBType before calling this
*/
-#ifdef SIS_LINUX_KERNEL
static
-#endif
void
SiS_EnableBridge(struct SiS_Private *SiS_Pr)
{
unsigned short temp=0, tempah;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short temp1, pushax=0;
bool delaylong = false;
#endif
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* 300 series */
+#ifdef CONFIG_FB_SIS_300 /* 300 series */
if(SiS_CRT2IsLCD(SiS_Pr)) {
if(SiS_Pr->SiS_VBType & VB_SISLVDS) {
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* 315 series */
+#ifdef CONFIG_FB_SIS_315 /* 315 series */
#ifdef SET_EMI
unsigned char r30=0, r31=0, r32=0, r33=0, cr36=0;
SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* 300 series */
+#ifdef CONFIG_FB_SIS_300 /* 300 series */
if(SiS_CRT2IsLCD(SiS_Pr)) {
if(SiS_Pr->ChipType == SIS_730) {
}
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* 315 series */
+#ifdef CONFIG_FB_SIS_315 /* 315 series */
if(!(SiS_IsNotM650orLater(SiS_Pr))) {
/*if(SiS_Pr->ChipType < SIS_340) {*/ /* XGI needs this */
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
} /* 310 series */
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* ---- 300 series --- */
+#ifdef CONFIG_FB_SIS_300 /* ---- 300 series --- */
if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { /* 630 - 301B(-DH) */
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* ------- 315 series ------ */
+#ifdef CONFIG_FB_SIS_315 /* ------- 315 series ------ */
if(SiS_Pr->SiS_VBType & VB_SISLVDS) { /* 315 - LVDS */
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
}
}
/* Set CRT2 FIFO on 300/540/630/730 */
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static void
SiS_SetCRT2FIFO_300(struct SiS_Private *SiS_Pr,unsigned short ModeNo)
{
} else {
-#ifdef SIS_LINUX_KERNEL
pci50 = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50);
pciA0 = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xa0);
-#else
- pci50 = pciReadLong(0x00000000, 0x50);
- pciA0 = pciReadLong(0x00000000, 0xA0);
-#endif
if(SiS_Pr->ChipType == SIS_730) {
#endif
/* Set CRT2 FIFO on 315/330 series */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
SiS_SetCRT2FIFO_310(struct SiS_Private *SiS_Pr)
{
temp = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02));
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp); /* ? */
-
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "%d %d %d %d %d %d %d %d (%d %d %d %d)\n",
- SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal,
- SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal,
- SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd);
-
- xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
- SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1],
- SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3],
- SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5],
- SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]);
- xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
- SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9],
- SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11],
- SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13],
- SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]);
- xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]);
-#endif
-#endif
}
/* Setup panel link
unsigned short push2, tempax, tempbx, tempcx, temp;
unsigned int tempeax = 0, tempebx, tempecx, tempvcfact = 0;
bool islvds = false, issis = false, chkdclkfirst = false;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
unsigned short crt2crtc = 0;
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short pushcx;
#endif
if(ModeNo <= 0x13) {
modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
#endif
} else if(SiS_Pr->UseCustomMode) {
} else {
modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
#endif
}
}
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
if(IS_SIS330) {
SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* 300 series */
+#ifdef CONFIG_FB_SIS_300 /* 300 series */
tempeax = SiS_Pr->SiS_VGAVDE << 6;
temp = (tempeax % (unsigned int)SiS_Pr->SiS_VDE);
tempeax = tempeax / (unsigned int)SiS_Pr->SiS_VDE;
temp = (unsigned short)(tempeax & 0x00FF);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp); /* BPLVCFACT */
tempvcfact = temp;
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* 315 series */
+#ifdef CONFIG_FB_SIS_315 /* 315 series */
tempeax = SiS_Pr->SiS_VGAVDE << 18;
tempebx = SiS_Pr->SiS_VDE;
temp = (tempeax % tempebx);
temp = (unsigned short)(tempecx & 0x00FF);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
if((islvds) || (SiS_Pr->SiS_VBInfo & VB_SISLVDS)) {
}
#endif
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_IF_DEF_TRUMPION) {
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned char *trumpdata;
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x25,0x00);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x26,0x00);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x45,0x0a);
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
/* Set Part 1 */
SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex)
{
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
#endif
unsigned short temp=0, tempax=0, tempbx=0, tempcx=0, bridgeadd=0;
unsigned short pushbx=0, CRT1Index=0, modeflag, resinfo=0;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short tempbl=0;
#endif
(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) {
if(SiS_Pr->ChipType < SIS_315H ) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo);
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_SetCRT2FIFO_310(SiS_Pr);
#endif
}
if(SiS_Pr->ChipType < SIS_315H ) {
-#ifdef SIS300 /* ------------- 300 series --------------*/
+#ifdef CONFIG_FB_SIS_300 /* ------------- 300 series --------------*/
temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */
bridgeadd = 12;
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* ------------------- 315/330 series --------------- */
+#ifdef CONFIG_FB_SIS_315 /* ------------------- 315/330 series --------------- */
tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HT 0x08,0x09 */
if(modeflag & HalfDCLK) {
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
} /* 315/330 series */
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* ---------- 300 series -------------- */
+#ifdef CONFIG_FB_SIS_300 /* ---------- 300 series -------------- */
if(SiS_Pr->SiS_VBType & VB_SISVB) {
temp = 0x20;
SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* --------------- 315/330 series ---------------*/
+#ifdef CONFIG_FB_SIS_315 /* --------------- 315/330 series ---------------*/
if(SiS_Pr->ChipType < SIS_661) {
if(modeflag & HalfDCLK) tempax |= 0x40;
SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax);
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
/* SET PART 2 REGISTER GROUP */
/*********************************************/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static unsigned char *
SiS_GetGroup2CLVXPtr(struct SiS_Private *SiS_Pr, int tabletype)
{
}
#endif
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static void
SiS_Group2LCDSpecial(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short crt2crtc)
{
unsigned int longtemp, PhaseIndex;
bool newtvphase;
const unsigned char *TimingPoint;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short resindex, CRT2Index;
const struct SiS_Part2PortTbl *CRT2Part2Ptr = NULL;
SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB);
SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
&CRT2Index, &resindex)) {
switch(CRT2Index) {
/* Non-expanding: lcdvdes = tempcx = VT-1; lcdvdee = tempbx = VDE-1 */
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdvdes 0x%x lcdvdee 0x%x\n", tempcx, tempbx);
-#endif
-#endif
-
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempcx); /* lcdvdes */
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,tempbx); /* lcdvdee */
tempbx = SiS_Pr->CVSyncStart;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdvrs 0x%x\n", tempbx);
-#endif
-#endif
-
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx); /* lcdvrs */
temp = (tempbx >> 4) & 0xF0;
temp |= (SiS_Pr->CVSyncEnd & 0x0f);
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdvre[3:0] 0x%x\n", (temp & 0x0f));
-#endif
-#endif
-
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp);
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
SiS_Group2LCDSpecial(SiS_Pr, ModeNo, crt2crtc);
#endif
tempax >>= 1;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdhdee 0x%x\n", tempbx);
-#endif
-#endif
-
tempbx += bridgeoffset;
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,tempbx); /* lcdhdee */
tempbx += bridgeoffset;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdhrs 0x%x\n", tempbx);
-#endif
-#endif
-
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,tempbx); /* lcdhrs */
SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,((tempbx >> 4) & 0xf0));
tempbx += bridgeoffset;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdhre 0x%x\n", tempbx);
-#endif
-#endif
-
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempbx); /* lcdhre */
SiS_SetGroup2_Tail(SiS_Pr, ModeNo);
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
SiS_Set300Part2Regs(SiS_Pr, ModeIdIndex, RefreshRateTableIndex, ModeNo);
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
} /* CRT2-LCD from table */
#endif
}
/* SET PART 4 REGISTER GROUP */
/*********************************************/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
#if 0
static void
SiS_ShiftXPos(struct SiS_Private *SiS_Pr, int shift)
if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
/* Chrontel 7005 - I assume that it does not come with a 315 series chip */
/* Chrontel 7019 - assumed that it does not come with a 300 series chip */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short temp;
}
-#ifdef SIS315H /* ----------- 315 series only ---------- */
+#ifdef CONFIG_FB_SIS_315 /* ----------- 315 series only ---------- */
void
SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr)
bool
SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
#endif
unsigned short ModeIdIndex, RefreshRateTableIndex;
SiS_GetLVDSDesData(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "(init301: LCDHDES 0x%03x LCDVDES 0x%03x)\n", SiS_Pr->SiS_LCDHDES, SiS_Pr->SiS_LCDVDES);
- xf86DrvMsg(0, X_INFO, "(init301: HDE 0x%03x VDE 0x%03x)\n", SiS_Pr->SiS_HDE, SiS_Pr->SiS_VDE);
- xf86DrvMsg(0, X_INFO, "(init301: VGAHDE 0x%03x VGAVDE 0x%03x)\n", SiS_Pr->SiS_VGAHDE, SiS_Pr->SiS_VGAVDE);
- xf86DrvMsg(0, X_INFO, "(init301: HT 0x%03x VT 0x%03x)\n", SiS_Pr->SiS_HT, SiS_Pr->SiS_VT);
- xf86DrvMsg(0, X_INFO, "(init301: VGAHT 0x%03x VGAVT 0x%03x)\n", SiS_Pr->SiS_VGAHT, SiS_Pr->SiS_VGAVT);
-#endif
-#endif
-
if(SiS_Pr->SiS_SetFlag & LowModeTests) {
SiS_SetGroup1(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
}
if(SiS_Pr->SiS_SetFlag & LowModeTests) {
SiS_SetGroup2(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_SetGroup2_C_ELV(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
#endif
SiS_SetGroup3(SiS_Pr, ModeNo, ModeIdIndex);
SiS_SetGroup4(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_SetGroup4_C_ELV(SiS_Pr, ModeNo, ModeIdIndex);
#endif
SiS_SetGroup5(SiS_Pr, ModeNo, ModeIdIndex);
if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_SetCH701xForLCD(SiS_Pr);
#endif
}
}
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->ChipType < SIS_315H) {
if(SiS_Pr->SiS_SetFlag & LowModeTests) {
if(SiS_Pr->SiS_UseOEM) {
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if(SiS_Pr->SiS_SetFlag & LowModeTests) {
if(SiS_Pr->ChipType < SIS_661) {
}
}
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static unsigned char *
SiS_SetTrumpBlockLoop(struct SiS_Private *SiS_Pr, unsigned char *dataptr)
{
dataptr = SiS_SetTrumpBlockLoop(SiS_Pr, dataptr);
if(!dataptr) return false;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Trumpion block success\n");
-#endif
-#endif
return true;
}
#endif
SiS_SetChReg(SiS_Pr, reg, val, 0);
}
-#ifdef SIS_LINUX_KERNEL
static
-#endif
void
SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val)
{
/* Read from Chrontel 70xx */
/* Parameter is [Register no (S7-S0)] */
-#ifdef SIS_LINUX_KERNEL
static
-#endif
unsigned short
SiS_GetCH70xx(struct SiS_Private *SiS_Pr, unsigned short tempbx)
{
}
/* Our own DDC functions */
-#ifndef SIS_XORG_XF86
static
-#endif
unsigned short
SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine,
unsigned short adaptnum, unsigned short DDCdatatype, bool checkcr32,
SiS_SetupDDCN(SiS_Pr);
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "DDC Port %x Index %x Shift %d\n",
- SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index, temp);
-#endif
-#endif
return 0;
}
SiS_SetSwitchDDC2(SiS_Pr);
if(SiS_PrepareDDC(SiS_Pr)) {
SiS_SetStop(SiS_Pr);
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Probe: Prepare failed\n");
-#endif
-#endif
return 0xFFFF;
}
mask = 0xf0;
} else {
failed = true;
ret = 0xFFFF;
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Probe: Read 1 failed\n");
-#endif
-#endif
}
}
if(!failed) {
if(temp == value) ret = 0;
else {
ret = 0xFFFF;
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Probe: Read 2 failed\n");
-#endif
-#endif
if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) {
if(temp == 0x30) ret = 0;
}
return ret;
}
-#ifndef SIS_XORG_XF86
static
-#endif
unsigned short
SiS_ProbeDDC(struct SiS_Private *SiS_Pr)
{
return flag;
}
-#ifndef SIS_XORG_XF86
static
-#endif
unsigned short
SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype, unsigned char *buffer)
{
temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);
} while((!(temp & SiS_Pr->SiS_DDC_Clk)) && --watchdog);
if (!watchdog) {
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "SetClkHigh failed\n");
-#endif
-#endif
return 0xFFFF;
}
SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT);
/* =============== SiS 315/330 O.E.M. ================= */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static unsigned short
GetRAMDACromptr(struct SiS_Private *SiS_Pr)
/* ================= SiS 300 O.E.M. ================== */
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static void
SetOEMLCDData2(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex,
#ifndef _INIT301_H_
#define _INIT301_H_
-#include "osdef.h"
#include "initdef.h"
-#ifdef SIS_XORG_XF86
-#include "sis.h"
-#include "sis_regs.h"
-#endif
-
-#ifdef SIS_LINUX_KERNEL
#include "vgatypes.h"
#include "vstruct.h"
#ifdef SIS_CP
#include <linux/fb.h>
#include "sis.h"
#include <video/sisfb.h>
-#endif
static const unsigned char SiS_YPbPrTable[3][64] = {
{
0xFF,0xFF,
};
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
/* 661 et al LCD data structure (2.03.00) */
static const unsigned char SiS_LCDStruct661[] = {
/* 1024x768 */
};
#endif
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static unsigned char SiS300_TrumpionData[14][80] = {
{ 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02,
0x20,0x03,0x0B,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x10,0x00,0x00,0x04,0x23,
#endif
void SiS_UnLockCRT2(struct SiS_Private *SiS_Pr);
-#ifndef SIS_LINUX_KERNEL
-void SiS_LockCRT2(struct SiS_Private *SiS_Pr);
-#endif
void SiS_EnableCRT2(struct SiS_Private *SiS_Pr);
unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex);
void SiS_WaitRetrace1(struct SiS_Private *SiS_Pr);
unsigned short RefreshRateTableIndex);
unsigned short SiS_GetResInfo(struct SiS_Private *SiS_Pr,unsigned short ModeNo,unsigned short ModeIdIndex);
void SiS_DisableBridge(struct SiS_Private *SiS_Pr);
-#ifndef SIS_LINUX_KERNEL
-void SiS_EnableBridge(struct SiS_Private *SiS_Pr);
-#endif
bool SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
void SiS_SiS30xBLOn(struct SiS_Private *SiS_Pr);
void SiS_SiS30xBLOff(struct SiS_Private *SiS_Pr);
unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short tempax);
void SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val);
unsigned short SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short tempax);
-#ifndef SIS_LINUX_KERNEL
-void SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val);
-unsigned short SiS_GetCH70xx(struct SiS_Private *SiS_Pr, unsigned short tempax);
-#endif
void SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg,
unsigned char orval,unsigned short andval);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void SiS_Chrontel701xOn(struct SiS_Private *SiS_Pr);
static void SiS_Chrontel701xOff(struct SiS_Private *SiS_Pr);
static void SiS_ChrontelInitTVVSync(struct SiS_Private *SiS_Pr);
void SiS_Chrontel701xBLOff(struct SiS_Private *SiS_Pr);
#endif /* 315 */
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static bool SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr);
void SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo);
#endif
unsigned short adaptnum, unsigned short DDCdatatype,
unsigned char *buffer, unsigned int VBFlags2);
-#ifdef SIS_XORG_XF86
-unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags,
- int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype,
- bool checkcr32, unsigned int VBFlags2);
-unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr);
-unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype,
- unsigned char *buffer);
-#else
static unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags,
int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype,
bool checkcr32, unsigned int VBFlags2);
static unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr);
static unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype,
unsigned char *buffer);
-#endif
static void SiS_SetSwitchDDC2(struct SiS_Private *SiS_Pr);
static unsigned short SiS_SetStart(struct SiS_Private *SiS_Pr);
static unsigned short SiS_SetStop(struct SiS_Private *SiS_Pr);
static void SiS_SendACK(struct SiS_Private *SiS_Pr, unsigned short yesno);
static unsigned short SiS_DoProbeDDC(struct SiS_Private *SiS_Pr);
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static void SiS_OEM300Setting(struct SiS_Private *SiS_Pr,
unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefTabindex);
static void SetOEMLCDData2(struct SiS_Private *SiS_Pr,
unsigned short ModeNo, unsigned short ModeIdIndex,unsigned short RefTableIndex);
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void SiS_OEM310Setting(struct SiS_Private *SiS_Pr,
unsigned short ModeNo,unsigned short ModeIdIndex, unsigned short RRTI);
static void SiS_OEM661Setting(struct SiS_Private *SiS_Pr,
extern void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth);
extern unsigned short SiS_GetRefCRTVCLK(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide);
extern unsigned short SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide);
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
extern void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *tempbx,
unsigned short *tempcl);
extern unsigned short SiS_GetFIFOThresholdB300(unsigned short tempbx, unsigned short tempcl);
extern unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index);
-#ifdef SIS_LINUX_KERNEL
extern unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg);
extern unsigned int sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg);
#endif
-#endif
#endif
* Author: Thomas Winischhofer <thomas@winischhofer.net>
*/
-#include "osdef.h"
#include "initdef.h"
#include "vgatypes.h"
#include "vstruct.h"
if(rateindex > 0) rateindex--;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
switch(ModeNo) {
case 0x5a: ModeNo = 0x50; break;
case 0x5b: ModeNo = 0x56;
if(rateindex > 0) rateindex--;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
switch(ModeNo) {
case 0x5a: ModeNo = 0x50; break;
case 0x5b: ModeNo = 0x56;
if(rateindex > 0) rateindex--;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
switch(ModeNo) {
case 0x5a: ModeNo = 0x50; break;
case 0x5b: ModeNo = 0x56;
+++ /dev/null
-/* $XFree86$ */
-/* $XdotOrg$ */
-/*
- * OS depending defines
- *
- * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
- *
- * If distributed as part of the Linux kernel, the following license terms
- * apply:
- *
- * * 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 named License,
- * * or 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
- *
- * Otherwise, the following license terms apply:
- *
- * * Redistribution and use in source and binary forms, with or without
- * * modification, are permitted provided that the following conditions
- * * are met:
- * * 1) Redistributions of source code must retain the above copyright
- * * notice, this list of conditions and the following disclaimer.
- * * 2) Redistributions in binary form must reproduce the above copyright
- * * notice, this list of conditions and the following disclaimer in the
- * * documentation and/or other materials provided with the distribution.
- * * 3) The name of the author may not be used to endorse or promote products
- * * derived from this software without specific prior written permission.
- * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
- * Silicon Integrated Systems, Inc. (used by permission)
- *
- */
-
-#ifndef _SIS_OSDEF_H_
-#define _SIS_OSDEF_H_
-
-/* The choices are: */
-#define SIS_LINUX_KERNEL /* Linux kernel framebuffer */
-#undef SIS_XORG_XF86 /* XFree86/X.org */
-
-#ifdef OutPortByte
-#undef OutPortByte
-#endif
-
-#ifdef OutPortWord
-#undef OutPortWord
-#endif
-
-#ifdef OutPortLong
-#undef OutPortLong
-#endif
-
-#ifdef InPortByte
-#undef InPortByte
-#endif
-
-#ifdef InPortWord
-#undef InPortWord
-#endif
-
-#ifdef InPortLong
-#undef InPortLong
-#endif
-
-/**********************************************************************/
-/* LINUX KERNEL */
-/**********************************************************************/
-
-#ifdef SIS_LINUX_KERNEL
-
-#ifdef CONFIG_FB_SIS_300
-#define SIS300
-#endif
-
-#ifdef CONFIG_FB_SIS_315
-#define SIS315H
-#endif
-
-#if !defined(SIS300) && !defined(SIS315H)
-#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
-#warning sisfb will not work!
-#endif
-
-#define OutPortByte(p,v) outb((u8)(v),(SISIOADDRESS)(p))
-#define OutPortWord(p,v) outw((u16)(v),(SISIOADDRESS)(p))
-#define OutPortLong(p,v) outl((u32)(v),(SISIOADDRESS)(p))
-#define InPortByte(p) inb((SISIOADDRESS)(p))
-#define InPortWord(p) inw((SISIOADDRESS)(p))
-#define InPortLong(p) inl((SISIOADDRESS)(p))
-#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset_io(MemoryAddress, value, MemorySize)
-
-#endif /* LINUX_KERNEL */
-
-/**********************************************************************/
-/* XFree86/X.org */
-/**********************************************************************/
-
-#ifdef SIS_XORG_XF86
-
-#define SIS300
-#define SIS315H
-
-#define OutPortByte(p,v) outSISREG((IOADDRESS)(p),(CARD8)(v))
-#define OutPortWord(p,v) outSISREGW((IOADDRESS)(p),(CARD16)(v))
-#define OutPortLong(p,v) outSISREGL((IOADDRESS)(p),(CARD32)(v))
-#define InPortByte(p) inSISREG((IOADDRESS)(p))
-#define InPortWord(p) inSISREGW((IOADDRESS)(p))
-#define InPortLong(p) inSISREGL((IOADDRESS)(p))
-#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
-
-#endif /* XF86 */
-
-#endif /* _OSDEF_H_ */
#ifndef _SIS_H_
#define _SIS_H_
-#include "osdef.h"
#include <video/sisfb.h>
#include "vgatypes.h"
#include "sis.h"
#include "sis_main.h"
+#if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
+#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
+#warning sisfb will not work!
+#endif
+
static void sisfb_handle_command(struct sis_video_info *ivideo,
struct sisfb_cmd *sisfb_command);
if(sisfb_check_rom(rom_base, ivideo)) {
if((myrombase = vmalloc(65536))) {
-
- /* Work around bug in pci/rom.c: Folks forgot to check
- * whether the size retrieved from the BIOS image eventually
- * is larger than the mapped size
- */
- if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
- romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
-
memcpy_fromio(myrombase, rom_base,
(romsize > 65536) ? 65536 : romsize);
}
}
-#else
-
- pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
- (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
-
- rom_base = ioremap(ivideo->video_base, 65536);
- if(rom_base) {
- if(sisfb_check_rom(rom_base, ivideo)) {
- if((myrombase = vmalloc(65536)))
- memcpy_fromio(myrombase, rom_base, 65536);
- }
- iounmap(rom_base);
- }
-
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
-
#endif
return myrombase;
#define SISIOMEMTYPE
-#ifdef SIS_LINUX_KERNEL
typedef unsigned long SISIOADDRESS;
#include <linux/types.h> /* Need __iomem */
#undef SISIOMEMTYPE
#define SISIOMEMTYPE __iomem
-#endif
-
-#ifdef SIS_XORG_XF86
-#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0)
-typedef unsigned long IOADDRESS;
-typedef unsigned long SISIOADDRESS;
-#else
-typedef IOADDRESS SISIOADDRESS;
-#endif
-#endif
typedef enum _SIS_CHIP_TYPE {
SIS_VGALegacy = 0,
{
unsigned char ChipType;
unsigned char ChipRevision;
-#ifdef SIS_XORG_XF86
- PCITAG PciTag;
-#endif
-#ifdef SIS_LINUX_KERNEL
void *ivideo;
-#endif
unsigned char *VirtualRomBase;
bool UseROM;
-#ifdef SIS_LINUX_KERNEL
unsigned char SISIOMEMTYPE *VideoMemoryAddress;
unsigned int VideoMemorySize;
-#endif
SISIOADDRESS IOAddress;
SISIOADDRESS IOAddress2; /* For dual chip XGI volari */
-#ifdef SIS_LINUX_KERNEL
SISIOADDRESS RelIO;
-#endif
SISIOADDRESS SiS_P3c4;
SISIOADDRESS SiS_P3d4;
SISIOADDRESS SiS_P3c0;
unsigned short SiS_IF_DEF_FSTN;
unsigned short SiS_SysFlags;
unsigned char SiS_VGAINFO;
-#ifdef SIS_XORG_XF86
- unsigned short SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4;
-#endif
bool SiS_UseROM;
bool SiS_ROMNew;
bool SiS_XGIROM;
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
- return sprintf(buf, "%hu", dev->id.device);
+ return sprintf(buf, "0x%04x\n", dev->id.device);
}
static ssize_t vendor_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
- return sprintf(buf, "%hu", dev->id.vendor);
+ return sprintf(buf, "0x%04x\n", dev->id.vendor);
}
static ssize_t status_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
- return sprintf(buf, "0x%08x", dev->config->get_status(dev));
+ return sprintf(buf, "0x%08x\n", dev->config->get_status(dev));
}
static ssize_t modalias_show(struct device *_d,
struct device_attribute *attr, char *buf)
pr_debug("Added buffer head %i to %p\n", head, vq);
END_USE(vq);
- /* If we're indirect, we can fit many (assuming not OOM). */
- if (vq->indirect)
- return vq->num_free ? vq->vring.num : 0;
return vq->num_free;
}
EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp);
This is the driver for the built-in watchdog timer on the IT8712F
Super I/0 chipset used on many motherboards.
+ If the driver does not work, then make sure that the game port in
+ the BIOS is enabled.
+
To compile this driver as a module, choose M here: the
module will be called it8712f_wdt.
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
}
}
-static int bcm63xx_wdt_notify_sys(struct notifier_block *this,
- unsigned long code, void *unused)
-{
- if (code == SYS_DOWN || code == SYS_HALT)
- bcm63xx_wdt_pause();
- return NOTIFY_DONE;
-}
-
static const struct file_operations bcm63xx_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.fops = &bcm63xx_wdt_fops,
};
-static struct notifier_block bcm63xx_wdt_notifier = {
- .notifier_call = bcm63xx_wdt_notify_sys,
-};
-
-static int bcm63xx_wdt_probe(struct platform_device *pdev)
+static int __devinit bcm63xx_wdt_probe(struct platform_device *pdev)
{
int ret;
struct resource *r;
wdt_time);
}
- ret = register_reboot_notifier(&bcm63xx_wdt_notifier);
- if (ret) {
- dev_err(&pdev->dev, "failed to register reboot_notifier\n");
- goto unregister_timer;
- }
-
ret = misc_register(&bcm63xx_wdt_miscdev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register watchdog device\n");
- goto unregister_reboot_notifier;
+ goto unregister_timer;
}
dev_info(&pdev->dev, " started, timer margin: %d sec\n",
return 0;
-unregister_reboot_notifier:
- unregister_reboot_notifier(&bcm63xx_wdt_notifier);
unregister_timer:
bcm63xx_timer_unregister(TIMER_WDT_ID);
unmap:
return ret;
}
-static int bcm63xx_wdt_remove(struct platform_device *pdev)
+static int __devexit bcm63xx_wdt_remove(struct platform_device *pdev)
{
if (!nowayout)
bcm63xx_wdt_pause();
misc_deregister(&bcm63xx_wdt_miscdev);
-
- iounmap(bcm63xx_wdt_device.regs);
-
- unregister_reboot_notifier(&bcm63xx_wdt_notifier);
bcm63xx_timer_unregister(TIMER_WDT_ID);
-
+ iounmap(bcm63xx_wdt_device.regs);
return 0;
}
+static void bcm63xx_wdt_shutdown(struct platform_device *pdev)
+{
+ bcm63xx_wdt_pause();
+}
+
static struct platform_driver bcm63xx_wdt = {
.probe = bcm63xx_wdt_probe,
- .remove = bcm63xx_wdt_remove,
+ .remove = __devexit_p(bcm63xx_wdt_remove),
+ .shutdown = bcm63xx_wdt_shutdown,
.driver = {
+ .owner = THIS_MODULE,
.name = "bcm63xx-wdt",
}
};
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
+#include <linux/fs.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/io.h>
* document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
* document number 320066-003, 320257-008: EP80597 (IICH)
* document number TBD : Cougar Point (CPT)
+ * document number TBD : Patsburg (PBG)
*/
/*
TCO_CPT29, /* Cougar Point */
TCO_CPT30, /* Cougar Point */
TCO_CPT31, /* Cougar Point */
- TCO_PBG, /* Patsburg */
+ TCO_PBG1, /* Patsburg */
+ TCO_PBG2, /* Patsburg */
};
static struct {
{"Cougar Point", 2},
{"Cougar Point", 2},
{"Patsburg", 2},
+ {"Patsburg", 2},
{NULL, 0}
};
{ ITCO_PCI_DEVICE(0x1c5d, TCO_CPT29)},
{ ITCO_PCI_DEVICE(0x1c5e, TCO_CPT30)},
{ ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)},
- { ITCO_PCI_DEVICE(0x1d40, TCO_PBG)},
+ { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)},
+ { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
obj-$(CONFIG_XEN_BALLOON) += balloon.o
-obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o
+obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
obj-$(CONFIG_XENFS) += xenfs/
obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
obj-$(CONFIG_XEN_DOM0) += pci.o
+
+xen-evtchn-y := evtchn.o
+
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/tlb.h>
+#include <asm/e820.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
}
/* balloon_append: add the given page to the balloon. */
-static void balloon_append(struct page *page)
+static void __balloon_append(struct page *page)
{
/* Lowmem is re-populated first, so highmem pages go at list tail. */
if (PageHighMem(page)) {
list_add(&page->lru, &ballooned_pages);
balloon_stats.balloon_low++;
}
+}
+static void balloon_append(struct page *page)
+{
+ __balloon_append(page);
totalram_pages--;
}
static int increase_reservation(unsigned long nr_pages)
{
- unsigned long pfn, i, flags;
+ unsigned long pfn, i;
struct page *page;
long rc;
struct xen_memory_reservation reservation = {
if (nr_pages > ARRAY_SIZE(frame_list))
nr_pages = ARRAY_SIZE(frame_list);
- spin_lock_irqsave(&xen_reservation_lock, flags);
-
page = balloon_first_page();
for (i = 0; i < nr_pages; i++) {
BUG_ON(page == NULL);
balloon_stats.current_pages += rc;
out:
- spin_unlock_irqrestore(&xen_reservation_lock, flags);
-
return rc < 0 ? rc : rc != nr_pages;
}
static int decrease_reservation(unsigned long nr_pages)
{
- unsigned long pfn, i, flags;
+ unsigned long pfn, i;
struct page *page;
int need_sleep = 0;
int ret;
kmap_flush_unused();
flush_tlb_all();
- spin_lock_irqsave(&xen_reservation_lock, flags);
-
/* No more mappings: invalidate P2M and add to balloon. */
for (i = 0; i < nr_pages; i++) {
pfn = mfn_to_pfn(frame_list[i]);
balloon_stats.current_pages -= nr_pages;
- spin_unlock_irqrestore(&xen_reservation_lock, flags);
-
return need_sleep;
}
static int __init balloon_init(void)
{
- unsigned long pfn;
+ unsigned long pfn, extra_pfn_end;
struct page *page;
if (!xen_pv_domain())
register_balloon(&balloon_sysdev);
- /* Initialise the balloon with excess memory space. */
- for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
+ /*
+ * Initialise the balloon with excess memory space. We need
+ * to make sure we don't add memory which doesn't exist or
+ * logically exist. The E820 map can be trimmed to be smaller
+ * than the amount of physical memory due to the mem= command
+ * line parameter. And if this is a 32-bit non-HIGHMEM kernel
+ * on a system with memory which requires highmem to access,
+ * don't try to use it.
+ */
+ extra_pfn_end = min(min(max_pfn, e820_end_of_ram_pfn()),
+ (unsigned long)PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size));
+ for (pfn = PFN_UP(xen_extra_mem_start);
+ pfn < extra_pfn_end;
+ pfn++) {
page = pfn_to_page(pfn);
- if (!PageReserved(page))
- balloon_append(page);
+ /* totalram_pages doesn't include the boot-time
+ balloon extension, so don't subtract from it. */
+ __balloon_append(page);
}
target_watch.callback = watch_target;
static struct irq_info *irq_info;
static int *pirq_to_irq;
-static int nr_pirqs;
static int *evtchn_to_irq;
struct cpu_evtchn_s {
cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu));
#endif
- __clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
- __set_bit(chn, cpu_evtchn_mask(cpu));
+ clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
+ set_bit(chn, cpu_evtchn_mask(cpu));
irq_info[irq].cpu = cpu;
}
static void init_evtchn_cpu_bindings(void)
{
+ int i;
#ifdef CONFIG_SMP
struct irq_desc *desc;
- int i;
/* By default all event channels notify CPU#0. */
for_each_irq_desc(i, desc) {
}
#endif
- memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s));
+ for_each_possible_cpu(i)
+ memset(cpu_evtchn_mask(i),
+ (i == 0) ? ~0 : 0, sizeof(struct cpu_evtchn_s));
+
}
static inline void clear_evtchn(int port)
return ret;
}
-/* callers of this function should make sure that PHYSDEVOP_get_nr_pirqs
- * succeeded otherwise nr_pirqs won't hold the right value */
-static int find_unbound_pirq(void)
+static int find_unbound_pirq(int type)
{
- int i;
- for (i = nr_pirqs-1; i >= 0; i--) {
+ int rc, i;
+ struct physdev_get_free_pirq op_get_free_pirq;
+ op_get_free_pirq.type = type;
+
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
+ if (!rc)
+ return op_get_free_pirq.pirq;
+
+ for (i = 0; i < nr_irqs; i++) {
if (pirq_to_irq[i] < 0)
return i;
}
if (irq == start)
goto no_irqs;
- res = irq_alloc_desc_at(irq, 0);
+ res = irq_alloc_desc_at(irq, -1);
if (WARN_ON(res != irq))
return -1;
spin_lock(&irq_mapping_update_lock);
- if ((pirq > nr_pirqs) || (gsi > nr_irqs)) {
+ if ((pirq > nr_irqs) || (gsi > nr_irqs)) {
printk(KERN_WARNING "xen_map_pirq_gsi: %s %s is incorrect!\n",
- pirq > nr_pirqs ? "nr_pirqs" :"",
- gsi > nr_irqs ? "nr_irqs" : "");
+ pirq > nr_irqs ? "pirq" :"",
+ gsi > nr_irqs ? "gsi" : "");
goto out;
}
if (identity_mapped_irq(gsi) || (!xen_initial_domain() &&
xen_pv_domain())) {
irq = gsi;
- irq_alloc_desc_at(irq, 0);
+ irq_alloc_desc_at(irq, -1);
} else
irq = find_unbound_irq();
#include <linux/msi.h>
#include "../pci/msi.h"
-void xen_allocate_pirq_msi(char *name, int *irq, int *pirq)
+void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc)
{
spin_lock(&irq_mapping_update_lock);
- *irq = find_unbound_irq();
- if (*irq == -1)
- goto out;
+ if (alloc & XEN_ALLOC_IRQ) {
+ *irq = find_unbound_irq();
+ if (*irq == -1)
+ goto out;
+ }
- *pirq = find_unbound_pirq();
- if (*pirq == -1)
- goto out;
+ if (alloc & XEN_ALLOC_PIRQ) {
+ *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI);
+ if (*pirq == -1)
+ goto out;
+ }
set_irq_chip_and_handler_name(*irq, &xen_pirq_chip,
handle_level_irq, name);
goto out;
if (xen_initial_domain()) {
- unmap_irq.pirq = info->u.pirq.gsi;
+ unmap_irq.pirq = info->u.pirq.pirq;
unmap_irq.domid = DOMID_SELF;
rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
if (rc) {
printk(KERN_WARNING "unmap irq failed %d\n", rc);
goto out;
}
+ pirq_to_irq[info->u.pirq.pirq] = -1;
}
irq_info[irq] = mk_unbound_info();
return gsi_from_irq(irq);
}
+int xen_irq_from_pirq(unsigned pirq)
+{
+ return pirq_to_irq[pirq];
+}
+
int bind_evtchn_to_irq(unsigned int evtchn)
{
int irq;
return ret;
}
+static void restore_cpu_pirqs(void)
+{
+ int pirq, rc, irq, gsi;
+ struct physdev_map_pirq map_irq;
+
+ for (pirq = 0; pirq < nr_irqs; pirq++) {
+ irq = pirq_to_irq[pirq];
+ if (irq == -1)
+ continue;
+
+ /* save/restore of PT devices doesn't work, so at this point the
+ * only devices present are GSI based emulated devices */
+ gsi = gsi_from_irq(irq);
+ if (!gsi)
+ continue;
+
+ map_irq.domid = DOMID_SELF;
+ map_irq.type = MAP_PIRQ_TYPE_GSI;
+ map_irq.index = gsi;
+ map_irq.pirq = pirq;
+
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+ if (rc) {
+ printk(KERN_WARNING "xen map irq failed gsi=%d irq=%d pirq=%d rc=%d\n",
+ gsi, irq, pirq, rc);
+ irq_info[irq] = mk_unbound_info();
+ pirq_to_irq[pirq] = -1;
+ continue;
+ }
+
+ printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
+
+ startup_pirq(irq);
+ }
+}
+
static void restore_cpu_virqs(unsigned int cpu)
{
struct evtchn_bind_virq bind_virq;
unmask_evtchn(evtchn);
}
+
+ restore_cpu_pirqs();
}
static struct irq_chip xen_dynamic_chip __read_mostly = {
void __init xen_init_IRQ(void)
{
- int i, rc;
- struct physdev_nr_pirqs op_nr_pirqs;
+ int i;
cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s),
GFP_KERNEL);
irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL);
- rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_nr_pirqs, &op_nr_pirqs);
- if (rc < 0) {
- nr_pirqs = nr_irqs;
- if (rc != -ENOSYS)
- printk(KERN_WARNING "PHYSDEVOP_get_nr_pirqs returned rc=%d\n", rc);
- } else {
- if (xen_pv_domain() && !xen_initial_domain())
- nr_pirqs = max((int)op_nr_pirqs.nr_pirqs, nr_irqs);
- else
- nr_pirqs = op_nr_pirqs.nr_pirqs;
- }
- pirq_to_irq = kcalloc(nr_pirqs, sizeof(*pirq_to_irq), GFP_KERNEL);
- for (i = 0; i < nr_pirqs; i++)
+ /* We are using nr_irqs as the maximum number of pirq available but
+ * that number is actually chosen by Xen and we don't know exactly
+ * what it is. Be careful choosing high pirq numbers. */
+ pirq_to_irq = kcalloc(nr_irqs, sizeof(*pirq_to_irq), GFP_KERNEL);
+ for (i = 0; i < nr_irqs; i++)
pirq_to_irq[i] = -1;
evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq),
const char *name;
};
-/* Who's bound to each port? */
-static struct per_user_data *port_user[NR_EVENT_CHANNELS];
+/*
+ * Who's bound to each port? This is logically an array of struct
+ * per_user_data *, but we encode the current enabled-state in bit 0.
+ */
+static unsigned long *port_user;
static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */
-irqreturn_t evtchn_interrupt(int irq, void *data)
+static inline struct per_user_data *get_port_user(unsigned port)
+{
+ return (struct per_user_data *)(port_user[port] & ~1);
+}
+
+static inline void set_port_user(unsigned port, struct per_user_data *u)
+{
+ port_user[port] = (unsigned long)u;
+}
+
+static inline bool get_port_enabled(unsigned port)
+{
+ return port_user[port] & 1;
+}
+
+static inline void set_port_enabled(unsigned port, bool enabled)
+{
+ if (enabled)
+ port_user[port] |= 1;
+ else
+ port_user[port] &= ~1;
+}
+
+static irqreturn_t evtchn_interrupt(int irq, void *data)
{
unsigned int port = (unsigned long)data;
struct per_user_data *u;
spin_lock(&port_user_lock);
- u = port_user[port];
+ u = get_port_user(port);
+
+ WARN(!get_port_enabled(port),
+ "Interrupt for port %d, but apparently not enabled; per-user %p\n",
+ port, u);
disable_irq_nosync(irq);
+ set_port_enabled(port, false);
if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
kill_fasync(&u->evtchn_async_queue,
SIGIO, POLL_IN);
}
- } else {
+ } else
u->ring_overflow = 1;
- }
spin_unlock(&port_user_lock);
goto out;
spin_lock_irq(&port_user_lock);
- for (i = 0; i < (count/sizeof(evtchn_port_t)); i++)
- if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u))
- enable_irq(irq_from_evtchn(kbuf[i]));
+
+ for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) {
+ unsigned port = kbuf[i];
+
+ if (port < NR_EVENT_CHANNELS &&
+ get_port_user(port) == u &&
+ !get_port_enabled(port)) {
+ set_port_enabled(port, true);
+ enable_irq(irq_from_evtchn(port));
+ }
+ }
+
spin_unlock_irq(&port_user_lock);
rc = count;
* interrupt handler yet, and our caller has already
* serialized bind operations.)
*/
- BUG_ON(port_user[port] != NULL);
- port_user[port] = u;
+ BUG_ON(get_port_user(port) != NULL);
+ set_port_user(port, u);
+ set_port_enabled(port, true); /* start enabled */
rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
u->name, (void *)(unsigned long)port);
unbind_from_irqhandler(irq, (void *)(unsigned long)port);
- /* make sure we unbind the irq handler before clearing the port */
- barrier();
-
- port_user[port] = NULL;
+ set_port_user(port, NULL);
}
static long evtchn_ioctl(struct file *file,
spin_lock_irq(&port_user_lock);
rc = -ENOTCONN;
- if (port_user[unbind.port] != u) {
+ if (get_port_user(unbind.port) != u) {
spin_unlock_irq(&port_user_lock);
break;
}
- evtchn_unbind_from_user(u, unbind.port);
+ disable_irq(irq_from_evtchn(unbind.port));
spin_unlock_irq(&port_user_lock);
+ evtchn_unbind_from_user(u, unbind.port);
+
rc = 0;
break;
}
if (notify.port >= NR_EVENT_CHANNELS) {
rc = -EINVAL;
- } else if (port_user[notify.port] != u) {
+ } else if (get_port_user(notify.port) != u) {
rc = -ENOTCONN;
} else {
notify_remote_via_evtchn(notify.port);
filp->private_data = u;
- return 0;
+ return nonseekable_open(inode, filp);;
}
static int evtchn_release(struct inode *inode, struct file *filp)
free_page((unsigned long)u->ring);
for (i = 0; i < NR_EVENT_CHANNELS; i++) {
- if (port_user[i] != u)
+ if (get_port_user(i) != u)
continue;
- evtchn_unbind_from_user(port_user[i], i);
+ disable_irq(irq_from_evtchn(i));
}
spin_unlock_irq(&port_user_lock);
+ for (i = 0; i < NR_EVENT_CHANNELS; i++) {
+ if (get_port_user(i) != u)
+ continue;
+
+ evtchn_unbind_from_user(get_port_user(i), i);
+ }
+
kfree(u->name);
kfree(u);
.fasync = evtchn_fasync,
.open = evtchn_open,
.release = evtchn_release,
- .llseek = noop_llseek,
+ .llseek = no_llseek,
};
static struct miscdevice evtchn_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
- .name = "evtchn",
+ .name = "xen/evtchn",
.fops = &evtchn_fops,
};
static int __init evtchn_init(void)
if (!xen_domain())
return -ENODEV;
+ port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL);
+ if (port_user == NULL)
+ return -ENOMEM;
+
spin_lock_init(&port_user_lock);
- memset(port_user, 0, sizeof(port_user));
/* Create '/dev/misc/evtchn'. */
err = misc_register(&evtchn_miscdev);
static void __exit evtchn_cleanup(void)
{
+ kfree(port_user);
+ port_user = NULL;
+
misc_deregister(&evtchn_miscdev);
}
if (!*cancelled) {
xen_irq_resume();
+ xen_console_resume();
xen_timer_resume();
}
#include <linux/mman.h>
#include <linux/uaccess.h>
#include <linux/swap.h>
-#include <linux/smp_lock.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/seq_file.h>
xen_pfn_t *mfnp = data;
struct mmap_batch_state *st = state;
- put_user(*mfnp, st->user++);
-
- return 0;
+ return put_user(*mfnp, st->user++);
}
static struct vm_operations_struct privcmd_vm_ops;
up_write(&mm->mmap_sem);
if (state.err > 0) {
- ret = 0;
-
state.user = m.arr;
- traverse_pages(m.num, sizeof(xen_pfn_t),
+ ret = traverse_pages(m.num, sizeof(xen_pfn_t),
&pagelist,
mmap_return_errors, &state);
}
if (xen_feature(XENFEAT_auto_translated_physmap))
return -ENOSYS;
- /* DONTCOPY is essential for Xen as copy_page_range is broken. */
- vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
+ /* DONTCOPY is essential for Xen because copy_page_range doesn't know
+ * how to recreate these mappings */
+ vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP;
vma->vm_ops = &privcmd_vm_ops;
vma->vm_private_data = NULL;
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/magic.h>
-#include <linux/mm.h>
-#include <linux/backing-dev.h>
#include <xen/xen.h>
MODULE_DESCRIPTION("Xen filesystem");
MODULE_LICENSE("GPL");
-static int xenfs_set_page_dirty(struct page *page)
-{
- return !TestSetPageDirty(page);
-}
-
-static const struct address_space_operations xenfs_aops = {
- .set_page_dirty = xenfs_set_page_dirty,
-};
-
-static struct backing_dev_info xenfs_backing_dev_info = {
- .ra_pages = 0, /* No readahead */
- .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
-};
-
static struct inode *xenfs_make_inode(struct super_block *sb, int mode)
{
struct inode *ret = new_inode(sb);
if (ret) {
ret->i_mode = mode;
- ret->i_mapping->a_ops = &xenfs_aops;
- ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info;
ret->i_uid = ret->i_gid = 0;
ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
return rc;
}
-static int xenfs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static struct dentry *xenfs_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data)
{
return mount_single(fs_type, flags, data, xenfs_fill_super);
}
static int __init xenfs_init(void)
{
- int err;
- if (!xen_domain()) {
- printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n");
- return 0;
- }
-
- err = register_filesystem(&xenfs_type);
- if (err) {
- printk(KERN_ERR "xenfs: Unable to register filesystem!\n");
- goto out;
- }
-
- err = bdi_init(&xenfs_backing_dev_info);
- if (err)
- unregister_filesystem(&xenfs_type);
-
- out:
+ if (xen_domain())
+ return register_filesystem(&xenfs_type);
- return err;
+ printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n");
+ return 0;
}
static void __exit xenfs_exit(void)
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/amigahw.h>
#include <asm/setup.h>
}
}
-static DEFINE_MUTEX(autofs4_ioctl_mutex);
-
static long autofs4_root_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
- long ret;
struct inode *inode = filp->f_dentry->d_inode;
-
- mutex_lock(&autofs4_ioctl_mutex);
- ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, arg);
- mutex_unlock(&autofs4_ioctl_mutex);
-
- return ret;
+ return autofs4_root_ioctl_unlocked(inode, filp, cmd, arg);
}
#ifdef CONFIG_COMPAT
struct inode *inode = filp->f_path.dentry->d_inode;
int ret;
- mutex_lock(&autofs4_ioctl_mutex);
if (cmd == AUTOFS_IOC_READY || cmd == AUTOFS_IOC_FAIL)
ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, arg);
else
ret = autofs4_root_ioctl_unlocked(inode, filp, cmd,
(unsigned long)compat_ptr(arg));
- mutex_unlock(&autofs4_ioctl_mutex);
return ret;
}
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/major.h>
-#include <linux/smp_lock.h>
#include <linux/device_cgroup.h>
#include <linux/highmem.h>
#include <linux/blkdev.h>
static struct bio *compressed_bio_alloc(struct block_device *bdev,
u64 first_byte, gfp_t gfp_flags)
{
- struct bio *bio;
int nr_vecs;
nr_vecs = bio_get_nr_vecs(bdev);
- bio = bio_alloc(gfp_flags, nr_vecs);
-
- if (bio == NULL && (current->flags & PF_MEMALLOC)) {
- while (!bio && (nr_vecs /= 2))
- bio = bio_alloc(gfp_flags, nr_vecs);
- }
-
- if (bio) {
- bio->bi_size = 0;
- bio->bi_bdev = bdev;
- bio->bi_sector = first_byte >> 9;
- }
- return bio;
+ return btrfs_bio_alloc(bdev, first_byte >> 9, nr_vecs, gfp_flags);
}
static int check_compressed_csum(struct inode *inode,
int extents_thresh;
int free_extents;
int total_bitmaps;
- int ro:1;
- int dirty:1;
- int iref:1;
+ unsigned int ro:1;
+ unsigned int dirty:1;
+ unsigned int iref:1;
int disk_cache_state;
#include <linux/freezer.h>
#include <linux/crc32c.h>
#include <linux/slab.h>
+#include <linux/migrate.h>
#include "compat.h"
#include "ctree.h"
#include "disk-io.h"
ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE,
btrfs_header_generation(eb));
BUG_ON(ret);
+ WARN_ON(!btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN));
+
found_start = btrfs_header_bytenr(eb);
if (found_start != start) {
WARN_ON(1);
__btree_submit_bio_done);
}
+#ifdef CONFIG_MIGRATION
+static int btree_migratepage(struct address_space *mapping,
+ struct page *newpage, struct page *page)
+{
+ /*
+ * we can't safely write a btree page from here,
+ * we haven't done the locking hook
+ */
+ if (PageDirty(page))
+ return -EAGAIN;
+ /*
+ * Buffers may be managed in a filesystem specific way.
+ * We must have no buffers or drop them.
+ */
+ if (page_has_private(page) &&
+ !try_to_release_page(page, GFP_KERNEL))
+ return -EAGAIN;
+ return migrate_page(mapping, newpage, page);
+}
+#endif
+
static int btree_writepage(struct page *page, struct writeback_control *wbc)
{
struct extent_io_tree *tree;
}
redirty_page_for_writepage(wbc, page);
- eb = btrfs_find_tree_block(root, page_offset(page),
- PAGE_CACHE_SIZE);
+ eb = btrfs_find_tree_block(root, page_offset(page), PAGE_CACHE_SIZE);
WARN_ON(!eb);
was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
.releasepage = btree_releasepage,
.invalidatepage = btree_invalidatepage,
.sync_page = block_sync_page,
+#ifdef CONFIG_MIGRATION
+ .migratepage = btree_migratepage,
+#endif
};
int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation);
- BUG_ON(!root->node);
+ if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) {
+ free_extent_buffer(root->node);
+ return -EIO;
+ }
root->commit_root = btrfs_root_node(root);
return 0;
}
GFP_NOFS);
struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root),
GFP_NOFS);
- struct btrfs_root *tree_root = kzalloc(sizeof(struct btrfs_root),
- GFP_NOFS);
- struct btrfs_fs_info *fs_info = kzalloc(sizeof(*fs_info),
- GFP_NOFS);
+ struct btrfs_root *tree_root = btrfs_sb(sb);
+ struct btrfs_fs_info *fs_info = tree_root->fs_info;
struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
GFP_NOFS);
struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
return ERR_PTR(ret);
}
+static int btrfs_get_name(struct dentry *parent, char *name,
+ struct dentry *child)
+{
+ struct inode *inode = child->d_inode;
+ struct inode *dir = parent->d_inode;
+ struct btrfs_path *path;
+ struct btrfs_root *root = BTRFS_I(dir)->root;
+ struct btrfs_inode_ref *iref;
+ struct btrfs_root_ref *rref;
+ struct extent_buffer *leaf;
+ unsigned long name_ptr;
+ struct btrfs_key key;
+ int name_len;
+ int ret;
+
+ if (!dir || !inode)
+ return -EINVAL;
+
+ if (!S_ISDIR(dir->i_mode))
+ return -EINVAL;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+ path->leave_spinning = 1;
+
+ if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
+ key.objectid = BTRFS_I(inode)->root->root_key.objectid;
+ key.type = BTRFS_ROOT_BACKREF_KEY;
+ key.offset = (u64)-1;
+ root = root->fs_info->tree_root;
+ } else {
+ key.objectid = inode->i_ino;
+ key.offset = dir->i_ino;
+ key.type = BTRFS_INODE_REF_KEY;
+ }
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0) {
+ btrfs_free_path(path);
+ return ret;
+ } else if (ret > 0) {
+ if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
+ path->slots[0]--;
+ } else {
+ btrfs_free_path(path);
+ return -ENOENT;
+ }
+ }
+ leaf = path->nodes[0];
+
+ if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
+ rref = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_root_ref);
+ name_ptr = (unsigned long)(rref + 1);
+ name_len = btrfs_root_ref_name_len(leaf, rref);
+ } else {
+ iref = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_inode_ref);
+ name_ptr = (unsigned long)(iref + 1);
+ name_len = btrfs_inode_ref_name_len(leaf, iref);
+ }
+
+ read_extent_buffer(leaf, name, name_ptr, name_len);
+ btrfs_free_path(path);
+
+ /*
+ * have to add the null termination to make sure that reconnect_path
+ * gets the right len for strlen
+ */
+ name[name_len] = '\0';
+
+ return 0;
+}
+
const struct export_operations btrfs_export_ops = {
.encode_fh = btrfs_encode_fh,
.fh_to_dentry = btrfs_fh_to_dentry,
.fh_to_parent = btrfs_fh_to_parent,
.get_parent = btrfs_get_parent,
+ .get_name = btrfs_get_name,
};
static int cache_block_group(struct btrfs_block_group_cache *cache,
struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
int load_cache_only)
{
struct btrfs_fs_info *fs_info = cache->fs_info;
/*
* We can't do the read from on-disk cache during a commit since we need
- * to have the normal tree locking.
+ * to have the normal tree locking. Also if we are currently trying to
+ * allocate blocks for the tree root we can't do the fast caching since
+ * we likely hold important locks.
*/
- if (!trans->transaction->in_commit) {
+ if (!trans->transaction->in_commit &&
+ (root && root != root->fs_info->tree_root)) {
spin_lock(&cache->lock);
if (cache->cached != BTRFS_CACHE_NO) {
spin_unlock(&cache->lock);
struct btrfs_root *root = block_group->fs_info->tree_root;
struct inode *inode = NULL;
u64 alloc_hint = 0;
+ int dcs = BTRFS_DC_ERROR;
int num_pages = 0;
int retries = 0;
int ret = 0;
spin_lock(&block_group->lock);
if (block_group->cached != BTRFS_CACHE_FINISHED) {
+ /* We're not cached, don't bother trying to write stuff out */
+ dcs = BTRFS_DC_WRITTEN;
spin_unlock(&block_group->lock);
goto out_put;
}
ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages,
num_pages, num_pages,
&alloc_hint);
+ if (!ret)
+ dcs = BTRFS_DC_SETUP;
btrfs_free_reserved_data_space(inode, num_pages);
out_put:
iput(inode);
btrfs_release_path(root, path);
out:
spin_lock(&block_group->lock);
- if (ret)
- block_group->disk_cache_state = BTRFS_DC_ERROR;
- else
- block_group->disk_cache_state = BTRFS_DC_SETUP;
+ block_group->disk_cache_state = dcs;
spin_unlock(&block_group->lock);
return ret;
u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
{
- u64 num_devices = root->fs_info->fs_devices->rw_devices;
+ /*
+ * we add in the count of missing devices because we want
+ * to make sure that any RAID levels on a degraded FS
+ * continue to be honored.
+ */
+ u64 num_devices = root->fs_info->fs_devices->rw_devices +
+ root->fs_info->fs_devices->missing_devices;
if (num_devices == 1)
flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0);
* our reservation.
*/
if (unused <= space_info->total_bytes) {
- unused -= space_info->total_bytes;
+ unused = space_info->total_bytes - unused;
if (unused >= num_bytes) {
if (!reserved)
space_info->bytes_reserved += orig_bytes;
* space back to the block group, otherwise we will leak space.
*/
if (!alloc && cache->cached == BTRFS_CACHE_NO)
- cache_block_group(cache, trans, 1);
+ cache_block_group(cache, trans, NULL, 1);
byte_in_group = bytenr - cache->key.objectid;
WARN_ON(byte_in_group > cache->key.offset);
btrfs_get_block_group(block_group);
search_start = block_group->key.objectid;
+ /*
+ * this can happen if we end up cycling through all the
+ * raid types, but we want to make sure we only allocate
+ * for the proper type.
+ */
+ if (!block_group_bits(block_group, data)) {
+ u64 extra = BTRFS_BLOCK_GROUP_DUP |
+ BTRFS_BLOCK_GROUP_RAID1 |
+ BTRFS_BLOCK_GROUP_RAID10;
+
+ /*
+ * if they asked for extra copies and this block group
+ * doesn't provide them, bail. This does allow us to
+ * fill raid0 from raid1.
+ */
+ if ((data & extra) && !(block_group->flags & extra))
+ goto loop;
+ }
+
have_block_group:
if (unlikely(block_group->cached == BTRFS_CACHE_NO)) {
u64 free_percent;
- ret = cache_block_group(block_group, trans, 1);
+ ret = cache_block_group(block_group, trans,
+ orig_root, 1);
if (block_group->cached == BTRFS_CACHE_FINISHED)
goto have_block_group;
if (loop > LOOP_CACHING_NOWAIT ||
(loop > LOOP_FIND_IDEAL &&
atomic_read(&space_info->caching_threads) < 2)) {
- ret = cache_block_group(block_group, trans, 0);
+ ret = cache_block_group(block_group, trans,
+ orig_root, 0);
BUG_ON(ret);
}
found_uncached_bg = true;
u64 num_bytes = ins->offset;
block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid);
- cache_block_group(block_group, trans, 0);
+ cache_block_group(block_group, trans, NULL, 0);
caching_ctl = get_caching_control(block_group);
if (!caching_ctl) {
NULL, NULL);
BUG_ON(ret < 0);
if (ret > 0) {
- ret = btrfs_del_orphan_item(trans, tree_root,
- root->root_key.objectid);
- BUG_ON(ret);
+ /* if we fail to delete the orphan item this time
+ * around, it'll get picked up the next time.
+ *
+ * The most common failure here is just -ENOENT.
+ */
+ btrfs_del_orphan_item(trans, tree_root,
+ root->root_key.objectid);
}
}
u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
- num_devices = root->fs_info->fs_devices->rw_devices;
+ /*
+ * we add in the count of missing devices because we want
+ * to make sure that any RAID levels on a degraded FS
+ * continue to be honored.
+ */
+ num_devices = root->fs_info->fs_devices->rw_devices +
+ root->fs_info->fs_devices->missing_devices;
+
if (num_devices == 1) {
stripped |= BTRFS_BLOCK_GROUP_DUP;
stripped = flags & ~stripped;
break;
if (ret != 0)
goto error;
-
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
cache = kzalloc(sizeof(*cache), GFP_NOFS);
bio_put(bio);
}
-static struct bio *
-extent_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
- gfp_t gfp_flags)
+struct bio *
+btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
+ gfp_t gfp_flags)
{
struct bio *bio;
else
nr = bio_get_nr_vecs(bdev);
- bio = extent_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH);
+ bio = btrfs_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH);
bio_add_page(bio, page, page_size, offset);
bio->bi_end_io = end_io_func;
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len, get_extent_t *get_extent)
{
- int ret;
+ int ret = 0;
u64 off = start;
u64 max = start + len;
u32 flags = 0;
+ u32 found_type;
+ u64 last;
u64 disko = 0;
+ struct btrfs_key found_key;
struct extent_map *em = NULL;
struct extent_state *cached_state = NULL;
+ struct btrfs_path *path;
+ struct btrfs_file_extent_item *item;
int end = 0;
u64 em_start = 0, em_len = 0;
unsigned long emflags;
- ret = 0;
+ int hole = 0;
if (len == 0)
return -EINVAL;
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+ path->leave_spinning = 1;
+
+ ret = btrfs_lookup_file_extent(NULL, BTRFS_I(inode)->root,
+ path, inode->i_ino, -1, 0);
+ if (ret < 0) {
+ btrfs_free_path(path);
+ return ret;
+ }
+ WARN_ON(!ret);
+ path->slots[0]--;
+ item = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_file_extent_item);
+ btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
+ found_type = btrfs_key_type(&found_key);
+
+ /* No extents, just return */
+ if (found_key.objectid != inode->i_ino ||
+ found_type != BTRFS_EXTENT_DATA_KEY) {
+ btrfs_free_path(path);
+ return 0;
+ }
+ last = found_key.offset;
+ btrfs_free_path(path);
+
lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
&cached_state, GFP_NOFS);
em = get_extent(inode, NULL, 0, off, max - off, 0);
ret = PTR_ERR(em);
goto out;
}
+
while (!end) {
+ hole = 0;
off = em->start + em->len;
if (off >= max)
end = 1;
+ if (em->block_start == EXTENT_MAP_HOLE) {
+ hole = 1;
+ goto next;
+ }
+
em_start = em->start;
em_len = em->len;
if (em->block_start == EXTENT_MAP_LAST_BYTE) {
end = 1;
flags |= FIEMAP_EXTENT_LAST;
- } else if (em->block_start == EXTENT_MAP_HOLE) {
- flags |= FIEMAP_EXTENT_UNWRITTEN;
} else if (em->block_start == EXTENT_MAP_INLINE) {
flags |= (FIEMAP_EXTENT_DATA_INLINE |
FIEMAP_EXTENT_NOT_ALIGNED);
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
flags |= FIEMAP_EXTENT_ENCODED;
+next:
emflags = em->flags;
free_extent_map(em);
em = NULL;
-
if (!end) {
em = get_extent(inode, NULL, 0, off, max - off, 0);
if (!em)
}
emflags = em->flags;
}
+
if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) {
flags |= FIEMAP_EXTENT_LAST;
end = 1;
}
- ret = fiemap_fill_next_extent(fieinfo, em_start, disko,
- em_len, flags);
- if (ret)
- goto out_free;
+ if (em_start == last) {
+ flags |= FIEMAP_EXTENT_LAST;
+ end = 1;
+ }
+
+ if (!hole) {
+ ret = fiemap_fill_next_extent(fieinfo, em_start, disko,
+ em_len, flags);
+ if (ret)
+ goto out_free;
+ }
}
out_free:
free_extent_map(em);
spin_lock(&tree->buffer_lock);
eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
- if (!eb)
- goto out;
+ if (!eb) {
+ spin_unlock(&tree->buffer_lock);
+ return ret;
+ }
if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
ret = 0;
struct extent_io_tree *tree,
u64 start, u64 end, struct page *locked_page,
unsigned long op);
+struct bio *
+btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
+ gfp_t gfp_flags);
#endif
struct page **prepared_pages,
struct iov_iter *i)
{
- size_t copied;
+ size_t copied = 0;
int pg = 0;
int offset = pos & (PAGE_CACHE_SIZE - 1);
+ int total_copied = 0;
while (write_bytes > 0) {
size_t count = min_t(size_t,
PAGE_CACHE_SIZE - offset, write_bytes);
struct page *page = prepared_pages[pg];
-again:
- if (unlikely(iov_iter_fault_in_readable(i, count)))
- return -EFAULT;
-
- /* Copy data from userspace to the current page */
- copied = iov_iter_copy_from_user(page, i, offset, count);
+ /*
+ * Copy data from userspace to the current page
+ *
+ * Disable pagefault to avoid recursive lock since
+ * the pages are already locked
+ */
+ pagefault_disable();
+ copied = iov_iter_copy_from_user_atomic(page, i, offset, count);
+ pagefault_enable();
/* Flush processor's dcache for this page */
flush_dcache_page(page);
iov_iter_advance(i, copied);
write_bytes -= copied;
+ total_copied += copied;
+ /* Return to btrfs_file_aio_write to fault page */
if (unlikely(copied == 0)) {
- count = min_t(size_t, PAGE_CACHE_SIZE - offset,
- iov_iter_single_seg_count(i));
- goto again;
+ break;
}
if (unlikely(copied < PAGE_CACHE_SIZE - offset)) {
offset = 0;
}
}
- return 0;
+ return total_copied;
}
/*
unsigned long last_index;
int will_write;
int buffered = 0;
+ int copied = 0;
+ int dirty_pages = 0;
will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) ||
(file->f_flags & O_DIRECT));
WARN_ON(num_pages > nrptrs);
memset(pages, 0, sizeof(struct page *) * nrptrs);
- ret = btrfs_delalloc_reserve_space(inode, write_bytes);
+ /*
+ * Fault pages before locking them in prepare_pages
+ * to avoid recursive lock
+ */
+ if (unlikely(iov_iter_fault_in_readable(&i, write_bytes))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = btrfs_delalloc_reserve_space(inode,
+ num_pages << PAGE_CACHE_SHIFT);
if (ret)
goto out;
pos, first_index, last_index,
write_bytes);
if (ret) {
- btrfs_delalloc_release_space(inode, write_bytes);
+ btrfs_delalloc_release_space(inode,
+ num_pages << PAGE_CACHE_SHIFT);
goto out;
}
- ret = btrfs_copy_from_user(pos, num_pages,
+ copied = btrfs_copy_from_user(pos, num_pages,
write_bytes, pages, &i);
- if (ret == 0) {
+ dirty_pages = (copied + PAGE_CACHE_SIZE - 1) >>
+ PAGE_CACHE_SHIFT;
+
+ if (num_pages > dirty_pages) {
+ if (copied > 0)
+ atomic_inc(
+ &BTRFS_I(inode)->outstanding_extents);
+ btrfs_delalloc_release_space(inode,
+ (num_pages - dirty_pages) <<
+ PAGE_CACHE_SHIFT);
+ }
+
+ if (copied > 0) {
dirty_and_release_pages(NULL, root, file, pages,
- num_pages, pos, write_bytes);
+ dirty_pages, pos, copied);
}
btrfs_drop_pages(pages, num_pages);
- if (ret) {
- btrfs_delalloc_release_space(inode, write_bytes);
- goto out;
- }
- if (will_write) {
- filemap_fdatawrite_range(inode->i_mapping, pos,
- pos + write_bytes - 1);
- } else {
- balance_dirty_pages_ratelimited_nr(inode->i_mapping,
- num_pages);
- if (num_pages <
- (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
- btrfs_btree_balance_dirty(root, 1);
- btrfs_throttle(root);
+ if (copied > 0) {
+ if (will_write) {
+ filemap_fdatawrite_range(inode->i_mapping, pos,
+ pos + copied - 1);
+ } else {
+ balance_dirty_pages_ratelimited_nr(
+ inode->i_mapping,
+ dirty_pages);
+ if (dirty_pages <
+ (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
+ btrfs_btree_balance_dirty(root, 1);
+ btrfs_throttle(root);
+ }
}
- pos += write_bytes;
- num_written += write_bytes;
+ pos += copied;
+ num_written += copied;
cond_resched();
}
if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
trans = btrfs_start_transaction(root, 0);
+ if (IS_ERR(trans)) {
+ num_written = PTR_ERR(trans);
+ goto done;
+ }
+ mutex_lock(&inode->i_mutex);
ret = btrfs_log_dentry_safe(trans, root,
file->f_dentry);
+ mutex_unlock(&inode->i_mutex);
if (ret == 0) {
ret = btrfs_sync_log(trans, root);
if (ret == 0)
(start_pos + num_written - 1) >> PAGE_CACHE_SHIFT);
}
}
+done:
current->backing_dev_info = NULL;
return num_written ? num_written : err;
}
(unsigned long long)BTRFS_I(inode)->generation,
(unsigned long long)generation,
(unsigned long long)block_group->key.objectid);
- goto out;
+ goto free_cache;
}
if (!num_entries)
return 0;
}
+ node = rb_first(&block_group->free_space_offset);
+ if (!node) {
+ iput(inode);
+ return 0;
+ }
+
last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT;
filemap_write_and_wait(inode->i_mapping);
btrfs_wait_ordered_range(inode, inode->i_size &
*/
first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64);
- node = rb_first(&block_group->free_space_offset);
- if (!node)
- goto out_free;
-
/*
* Lock all pages first so we can lock the extent safely.
*
add_async_extent(async_cow, start, num_bytes,
total_compressed, pages, nr_pages_ret);
- if (start + num_bytes < end && start + num_bytes < actual_end) {
+ if (start + num_bytes < end) {
start += num_bytes;
pages = NULL;
cond_resched();
BTRFS_I(inode)->index_cnt = 2;
BTRFS_I(inode)->root = root;
BTRFS_I(inode)->generation = trans->transid;
+ inode->i_generation = BTRFS_I(inode)->generation;
btrfs_set_inode_space_info(root, inode);
if (mode & S_IFDIR)
}
static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
- struct dentry *dentry, struct inode *inode,
- int backref, u64 index)
+ struct inode *dir, struct dentry *dentry,
+ struct inode *inode, int backref, u64 index)
{
- int err = btrfs_add_link(trans, dentry->d_parent->d_inode,
- inode, dentry->d_name.name,
- dentry->d_name.len, backref, index);
+ int err = btrfs_add_link(trans, dir, inode,
+ dentry->d_name.name, dentry->d_name.len,
+ backref, index);
if (!err) {
d_instantiate(dentry, inode);
return 0;
btrfs_set_trans_block_group(trans, dir);
inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
- dentry->d_name.len,
- dentry->d_parent->d_inode->i_ino, objectid,
+ dentry->d_name.len, dir->i_ino, objectid,
BTRFS_I(dir)->block_group, mode, &index);
err = PTR_ERR(inode);
if (IS_ERR(inode))
}
btrfs_set_trans_block_group(trans, inode);
- err = btrfs_add_nondir(trans, dentry, inode, 0, index);
+ err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
if (err)
drop_inode = 1;
else {
btrfs_set_trans_block_group(trans, dir);
inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
- dentry->d_name.len,
- dentry->d_parent->d_inode->i_ino,
- objectid, BTRFS_I(dir)->block_group, mode,
- &index);
+ dentry->d_name.len, dir->i_ino, objectid,
+ BTRFS_I(dir)->block_group, mode, &index);
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_unlock;
}
btrfs_set_trans_block_group(trans, inode);
- err = btrfs_add_nondir(trans, dentry, inode, 0, index);
+ err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
if (err)
drop_inode = 1;
else {
return -EPERM;
btrfs_inc_nlink(inode);
+ inode->i_ctime = CURRENT_TIME;
err = btrfs_set_inode_index(dir, &index);
if (err)
btrfs_set_trans_block_group(trans, dir);
ihold(inode);
- err = btrfs_add_nondir(trans, dentry, inode, 1, index);
+ err = btrfs_add_nondir(trans, dir, dentry, inode, 1, index);
if (err) {
drop_inode = 1;
} else {
+ struct dentry *parent = dget_parent(dentry);
btrfs_update_inode_block_group(trans, dir);
err = btrfs_update_inode(trans, root, inode);
BUG_ON(err);
- btrfs_log_new_name(trans, inode, NULL, dentry->d_parent);
+ btrfs_log_new_name(trans, inode, NULL, parent);
+ dput(parent);
}
nr = trans->blocks_used;
btrfs_set_trans_block_group(trans, dir);
inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
- dentry->d_name.len,
- dentry->d_parent->d_inode->i_ino, objectid,
+ dentry->d_name.len, dir->i_ino, objectid,
BTRFS_I(dir)->block_group, S_IFDIR | mode,
&index);
if (IS_ERR(inode)) {
if (err)
goto out_fail;
- err = btrfs_add_link(trans, dentry->d_parent->d_inode,
- inode, dentry->d_name.name,
- dentry->d_name.len, 0, index);
+ err = btrfs_add_link(trans, dir, inode, dentry->d_name.name,
+ dentry->d_name.len, 0, index);
if (err)
goto out_fail;
u64 bytes;
u32 *csums;
void *private;
+
+ /* number of bios pending for this dio */
+ atomic_t pending_bios;
+
+ /* IO errors */
+ int errors;
+
+ struct bio *orig_bio;
};
static void btrfs_endio_direct_read(struct bio *bio, int err)
{
+ struct btrfs_dio_private *dip = bio->bi_private;
struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1;
struct bio_vec *bvec = bio->bi_io_vec;
- struct btrfs_dio_private *dip = bio->bi_private;
struct inode *inode = dip->inode;
struct btrfs_root *root = BTRFS_I(inode)->root;
u64 start;
struct btrfs_trans_handle *trans;
struct btrfs_ordered_extent *ordered = NULL;
struct extent_state *cached_state = NULL;
+ u64 ordered_offset = dip->logical_offset;
+ u64 ordered_bytes = dip->bytes;
int ret;
if (err)
goto out_done;
-
- ret = btrfs_dec_test_ordered_pending(inode, &ordered,
- dip->logical_offset, dip->bytes);
+again:
+ ret = btrfs_dec_test_first_ordered_pending(inode, &ordered,
+ &ordered_offset,
+ ordered_bytes);
if (!ret)
- goto out_done;
+ goto out_test;
BUG_ON(!ordered);
out:
btrfs_delalloc_release_metadata(inode, ordered->len);
btrfs_end_transaction(trans, root);
+ ordered_offset = ordered->file_offset + ordered->len;
btrfs_put_ordered_extent(ordered);
btrfs_put_ordered_extent(ordered);
+
+out_test:
+ /*
+ * our bio might span multiple ordered extents. If we haven't
+ * completed the accounting for the whole dio, go back and try again
+ */
+ if (ordered_offset < dip->logical_offset + dip->bytes) {
+ ordered_bytes = dip->logical_offset + dip->bytes -
+ ordered_offset;
+ goto again;
+ }
out_done:
bio->bi_private = dip->private;
return 0;
}
+static void btrfs_end_dio_bio(struct bio *bio, int err)
+{
+ struct btrfs_dio_private *dip = bio->bi_private;
+
+ if (err) {
+ printk(KERN_ERR "btrfs direct IO failed ino %lu rw %lu "
+ "sector %#Lx len %u err no %d\n",
+ dip->inode->i_ino, bio->bi_rw,
+ (unsigned long long)bio->bi_sector, bio->bi_size, err);
+ dip->errors = 1;
+
+ /*
+ * before atomic variable goto zero, we must make sure
+ * dip->errors is perceived to be set.
+ */
+ smp_mb__before_atomic_dec();
+ }
+
+ /* if there are more bios still pending for this dio, just exit */
+ if (!atomic_dec_and_test(&dip->pending_bios))
+ goto out;
+
+ if (dip->errors)
+ bio_io_error(dip->orig_bio);
+ else {
+ set_bit(BIO_UPTODATE, &dip->orig_bio->bi_flags);
+ bio_endio(dip->orig_bio, 0);
+ }
+out:
+ bio_put(bio);
+}
+
+static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev,
+ u64 first_sector, gfp_t gfp_flags)
+{
+ int nr_vecs = bio_get_nr_vecs(bdev);
+ return btrfs_bio_alloc(bdev, first_sector, nr_vecs, gfp_flags);
+}
+
+static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
+ int rw, u64 file_offset, int skip_sum,
+ u32 *csums)
+{
+ int write = rw & REQ_WRITE;
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+ int ret;
+
+ bio_get(bio);
+ ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
+ if (ret)
+ goto err;
+
+ if (write && !skip_sum) {
+ ret = btrfs_wq_submit_bio(root->fs_info,
+ inode, rw, bio, 0, 0,
+ file_offset,
+ __btrfs_submit_bio_start_direct_io,
+ __btrfs_submit_bio_done);
+ goto err;
+ } else if (!skip_sum)
+ btrfs_lookup_bio_sums_dio(root, inode, bio,
+ file_offset, csums);
+
+ ret = btrfs_map_bio(root, rw, bio, 0, 1);
+err:
+ bio_put(bio);
+ return ret;
+}
+
+static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
+ int skip_sum)
+{
+ struct inode *inode = dip->inode;
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+ struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
+ struct bio *bio;
+ struct bio *orig_bio = dip->orig_bio;
+ struct bio_vec *bvec = orig_bio->bi_io_vec;
+ u64 start_sector = orig_bio->bi_sector;
+ u64 file_offset = dip->logical_offset;
+ u64 submit_len = 0;
+ u64 map_length;
+ int nr_pages = 0;
+ u32 *csums = dip->csums;
+ int ret = 0;
+
+ bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
+ if (!bio)
+ return -ENOMEM;
+ bio->bi_private = dip;
+ bio->bi_end_io = btrfs_end_dio_bio;
+ atomic_inc(&dip->pending_bios);
+
+ map_length = orig_bio->bi_size;
+ ret = btrfs_map_block(map_tree, READ, start_sector << 9,
+ &map_length, NULL, 0);
+ if (ret) {
+ bio_put(bio);
+ return -EIO;
+ }
+
+ while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
+ if (unlikely(map_length < submit_len + bvec->bv_len ||
+ bio_add_page(bio, bvec->bv_page, bvec->bv_len,
+ bvec->bv_offset) < bvec->bv_len)) {
+ /*
+ * inc the count before we submit the bio so
+ * we know the end IO handler won't happen before
+ * we inc the count. Otherwise, the dip might get freed
+ * before we're done setting it up
+ */
+ atomic_inc(&dip->pending_bios);
+ ret = __btrfs_submit_dio_bio(bio, inode, rw,
+ file_offset, skip_sum,
+ csums);
+ if (ret) {
+ bio_put(bio);
+ atomic_dec(&dip->pending_bios);
+ goto out_err;
+ }
+
+ if (!skip_sum)
+ csums = csums + nr_pages;
+ start_sector += submit_len >> 9;
+ file_offset += submit_len;
+
+ submit_len = 0;
+ nr_pages = 0;
+
+ bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev,
+ start_sector, GFP_NOFS);
+ if (!bio)
+ goto out_err;
+ bio->bi_private = dip;
+ bio->bi_end_io = btrfs_end_dio_bio;
+
+ map_length = orig_bio->bi_size;
+ ret = btrfs_map_block(map_tree, READ, start_sector << 9,
+ &map_length, NULL, 0);
+ if (ret) {
+ bio_put(bio);
+ goto out_err;
+ }
+ } else {
+ submit_len += bvec->bv_len;
+ nr_pages ++;
+ bvec++;
+ }
+ }
+
+ ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum,
+ csums);
+ if (!ret)
+ return 0;
+
+ bio_put(bio);
+out_err:
+ dip->errors = 1;
+ /*
+ * before atomic variable goto zero, we must
+ * make sure dip->errors is perceived to be set.
+ */
+ smp_mb__before_atomic_dec();
+ if (atomic_dec_and_test(&dip->pending_bios))
+ bio_io_error(dip->orig_bio);
+
+ /* bio_end_io() will handle error, so we needn't return it */
+ return 0;
+}
+
static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode,
loff_t file_offset)
{
dip->disk_bytenr = (u64)bio->bi_sector << 9;
bio->bi_private = dip;
+ dip->errors = 0;
+ dip->orig_bio = bio;
+ atomic_set(&dip->pending_bios, 0);
if (write)
bio->bi_end_io = btrfs_endio_direct_write;
else
bio->bi_end_io = btrfs_endio_direct_read;
- ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
- if (ret)
- goto out_err;
-
- if (write && !skip_sum) {
- ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
- inode, rw, bio, 0, 0,
- dip->logical_offset,
- __btrfs_submit_bio_start_direct_io,
- __btrfs_submit_bio_done);
- if (ret)
- goto out_err;
+ ret = btrfs_submit_direct_hook(rw, dip, skip_sum);
+ if (!ret)
return;
- } else if (!skip_sum)
- btrfs_lookup_bio_sums_dio(root, inode, bio,
- dip->logical_offset, dip->csums);
-
- ret = btrfs_map_bio(root, rw, bio, 0, 1);
- if (ret)
- goto out_err;
- return;
-out_err:
- kfree(dip->csums);
- kfree(dip);
free_ordered:
/*
* If this is a write, we need to clean up the reserved space and kill
*/
if (write) {
struct btrfs_ordered_extent *ordered;
- ordered = btrfs_lookup_ordered_extent(inode,
- dip->logical_offset);
+ ordered = btrfs_lookup_ordered_extent(inode, file_offset);
if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) &&
!test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags))
btrfs_free_reserved_extent(root, ordered->start,
BUG_ON(ret);
if (old_inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) {
- btrfs_log_new_name(trans, old_inode, old_dir,
- new_dentry->d_parent);
+ struct dentry *parent = dget_parent(new_dentry);
+ btrfs_log_new_name(trans, old_inode, old_dir, parent);
+ dput(parent);
btrfs_end_log_trans(root);
}
out_fail:
btrfs_set_trans_block_group(trans, dir);
inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
- dentry->d_name.len,
- dentry->d_parent->d_inode->i_ino, objectid,
+ dentry->d_name.len, dir->i_ino, objectid,
BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO,
&index);
err = PTR_ERR(inode);
}
btrfs_set_trans_block_group(trans, inode);
- err = btrfs_add_nondir(trans, dentry, inode, 0, index);
+ err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
if (err)
drop_inode = 1;
else {
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_key ins;
u64 cur_offset = start;
+ u64 i_size;
int ret = 0;
bool own_trans = true;
(actual_len > inode->i_size) &&
(cur_offset > inode->i_size)) {
if (cur_offset > actual_len)
- i_size_write(inode, actual_len);
+ i_size = actual_len;
else
- i_size_write(inode, cur_offset);
- i_size_write(inode, cur_offset);
- btrfs_ordered_update_i_size(inode, cur_offset, NULL);
+ i_size = cur_offset;
+ i_size_write(inode, i_size);
+ btrfs_ordered_update_i_size(inode, i_size, NULL);
}
ret = btrfs_update_inode(trans, root, inode);
btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start);
mutex_lock(&inode->i_mutex);
+ ret = inode_newsize_ok(inode, alloc_end);
+ if (ret)
+ goto out;
+
if (alloc_start > inode->i_size) {
ret = btrfs_cont_expand(inode, alloc_start);
if (ret)
.readlink = generic_readlink,
.follow_link = page_follow_link_light,
.put_link = page_put_link,
+ .getattr = btrfs_getattr,
.permission = btrfs_permission,
.setxattr = btrfs_setxattr,
.getxattr = btrfs_getxattr,
struct btrfs_inode_item *inode_item;
struct extent_buffer *leaf;
struct btrfs_root *new_root;
- struct inode *dir = dentry->d_parent->d_inode;
+ struct dentry *parent = dget_parent(dentry);
+ struct inode *dir;
int ret;
int err;
u64 objectid;
ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root,
0, &objectid);
- if (ret)
+ if (ret) {
+ dput(parent);
return ret;
+ }
+
+ dir = parent->d_inode;
+
/*
* 1 - inode item
* 2 - refs
* 2 - dir items
*/
trans = btrfs_start_transaction(root, 6);
- if (IS_ERR(trans))
+ if (IS_ERR(trans)) {
+ dput(parent);
return PTR_ERR(trans);
+ }
leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
0, objectid, NULL, 0, 0, 0);
d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
fail:
+ dput(parent);
if (async_transid) {
*async_transid = trans->transid;
err = btrfs_commit_transaction_async(trans, root, 1);
char *name, int namelen, u64 *async_transid)
{
struct inode *inode;
+ struct dentry *parent;
struct btrfs_pending_snapshot *pending_snapshot;
struct btrfs_trans_handle *trans;
int ret;
btrfs_orphan_cleanup(pending_snapshot->snap);
- inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
+ parent = dget_parent(dentry);
+ inode = btrfs_lookup_dentry(parent->d_inode, dentry);
+ dput(parent);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
goto fail;
static noinline int btrfs_ioctl_snap_create(struct file *file,
void __user *arg, int subvol,
- int async)
+ int v2)
{
struct btrfs_ioctl_vol_args *vol_args = NULL;
- struct btrfs_ioctl_async_vol_args *async_vol_args = NULL;
+ struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL;
char *name;
u64 fd;
- u64 transid = 0;
int ret;
- if (async) {
- async_vol_args = memdup_user(arg, sizeof(*async_vol_args));
- if (IS_ERR(async_vol_args))
- return PTR_ERR(async_vol_args);
+ if (v2) {
+ u64 transid = 0;
+ u64 *ptr = NULL;
+
+ vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2));
+ if (IS_ERR(vol_args_v2))
+ return PTR_ERR(vol_args_v2);
+
+ if (vol_args_v2->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ name = vol_args_v2->name;
+ fd = vol_args_v2->fd;
+ vol_args_v2->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
+
+ if (vol_args_v2->flags & BTRFS_SUBVOL_CREATE_ASYNC)
+ ptr = &transid;
+
+ ret = btrfs_ioctl_snap_create_transid(file, name, fd,
+ subvol, ptr);
- name = async_vol_args->name;
- fd = async_vol_args->fd;
- async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0';
+ if (ret == 0 && ptr &&
+ copy_to_user(arg +
+ offsetof(struct btrfs_ioctl_vol_args_v2,
+ transid), ptr, sizeof(*ptr)))
+ ret = -EFAULT;
} else {
vol_args = memdup_user(arg, sizeof(*vol_args));
if (IS_ERR(vol_args))
name = vol_args->name;
fd = vol_args->fd;
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
- }
-
- ret = btrfs_ioctl_snap_create_transid(file, name, fd,
- subvol, &transid);
- if (!ret && async) {
- if (copy_to_user(arg +
- offsetof(struct btrfs_ioctl_async_vol_args,
- transid), &transid, sizeof(transid)))
- return -EFAULT;
+ ret = btrfs_ioctl_snap_create_transid(file, name, fd,
+ subvol, NULL);
}
-
+out:
kfree(vol_args);
- kfree(async_vol_args);
+ kfree(vol_args_v2);
return ret;
}
olen = len = src->i_size - off;
/* if we extend to eof, continue to block boundary */
if (off + len == src->i_size)
- len = ((src->i_size + bs-1) & ~(bs-1))
- - off;
+ len = ALIGN(src->i_size, bs) - off;
/* verify the end result is block aligned */
- if ((off & (bs-1)) ||
- ((off + len) & (bs-1)))
+ if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) ||
+ !IS_ALIGNED(destoff, bs))
goto out_unlock;
/* do any pending delalloc/csum calc on src, one way or
* but shouldn't round up the file size
*/
endoff = new_key.offset + datal;
- if (endoff > off+olen)
- endoff = off+olen;
+ if (endoff > destoff+olen)
+ endoff = destoff+olen;
if (endoff > inode->i_size)
btrfs_i_size_write(inode, endoff);
return btrfs_ioctl_getversion(file, argp);
case BTRFS_IOC_SNAP_CREATE:
return btrfs_ioctl_snap_create(file, argp, 0, 0);
- case BTRFS_IOC_SNAP_CREATE_ASYNC:
+ case BTRFS_IOC_SNAP_CREATE_V2:
return btrfs_ioctl_snap_create(file, argp, 0, 1);
case BTRFS_IOC_SUBVOL_CREATE:
return btrfs_ioctl_snap_create(file, argp, 1, 0);
char name[BTRFS_PATH_NAME_MAX + 1];
};
-#define BTRFS_SNAPSHOT_NAME_MAX 4079
-struct btrfs_ioctl_async_vol_args {
+#define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0)
+
+#define BTRFS_SUBVOL_NAME_MAX 4039
+struct btrfs_ioctl_vol_args_v2 {
__s64 fd;
__u64 transid;
- char name[BTRFS_SNAPSHOT_NAME_MAX + 1];
+ __u64 flags;
+ __u64 unused[4];
+ char name[BTRFS_SUBVOL_NAME_MAX + 1];
};
#define BTRFS_INO_LOOKUP_PATH_MAX 4080
struct btrfs_ioctl_space_args)
#define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64)
#define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
-#define BTRFS_IOC_SNAP_CREATE_ASYNC _IOW(BTRFS_IOCTL_MAGIC, 23, \
- struct btrfs_ioctl_async_vol_args)
+#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
+ struct btrfs_ioctl_vol_args_v2)
#endif
return 0;
}
+/*
+ * this is used to account for finished IO across a given range
+ * of the file. The IO may span ordered extents. If
+ * a given ordered_extent is completely done, 1 is returned, otherwise
+ * 0.
+ *
+ * test_and_set_bit on a flag in the struct btrfs_ordered_extent is used
+ * to make sure this function only returns 1 once for a given ordered extent.
+ *
+ * file_offset is updated to one byte past the range that is recorded as
+ * complete. This allows you to walk forward in the file.
+ */
+int btrfs_dec_test_first_ordered_pending(struct inode *inode,
+ struct btrfs_ordered_extent **cached,
+ u64 *file_offset, u64 io_size)
+{
+ struct btrfs_ordered_inode_tree *tree;
+ struct rb_node *node;
+ struct btrfs_ordered_extent *entry = NULL;
+ int ret;
+ u64 dec_end;
+ u64 dec_start;
+ u64 to_dec;
+
+ tree = &BTRFS_I(inode)->ordered_tree;
+ spin_lock(&tree->lock);
+ node = tree_search(tree, *file_offset);
+ if (!node) {
+ ret = 1;
+ goto out;
+ }
+
+ entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
+ if (!offset_in_entry(entry, *file_offset)) {
+ ret = 1;
+ goto out;
+ }
+
+ dec_start = max(*file_offset, entry->file_offset);
+ dec_end = min(*file_offset + io_size, entry->file_offset +
+ entry->len);
+ *file_offset = dec_end;
+ if (dec_start > dec_end) {
+ printk(KERN_CRIT "bad ordering dec_start %llu end %llu\n",
+ (unsigned long long)dec_start,
+ (unsigned long long)dec_end);
+ }
+ to_dec = dec_end - dec_start;
+ if (to_dec > entry->bytes_left) {
+ printk(KERN_CRIT "bad ordered accounting left %llu size %llu\n",
+ (unsigned long long)entry->bytes_left,
+ (unsigned long long)to_dec);
+ }
+ entry->bytes_left -= to_dec;
+ if (entry->bytes_left == 0)
+ ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags);
+ else
+ ret = 1;
+out:
+ if (!ret && cached && entry) {
+ *cached = entry;
+ atomic_inc(&entry->refs);
+ }
+ spin_unlock(&tree->lock);
+ return ret == 0;
+}
+
/*
* this is used to account for finished IO across a given range
* of the file. The IO should not span ordered extents. If
int btrfs_dec_test_ordered_pending(struct inode *inode,
struct btrfs_ordered_extent **cached,
u64 file_offset, u64 io_size);
+int btrfs_dec_test_first_ordered_pending(struct inode *inode,
+ struct btrfs_ordered_extent **cached,
+ u64 *file_offset, u64 io_size);
int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
u64 start, u64 len, u64 disk_len, int type);
int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset,
return -ENOMEM;
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
- if (ret)
+ if (ret < 0)
goto out;
+ if (ret) {
+ ret = -ENOENT;
+ goto out;
+ }
ret = btrfs_del_item(trans, root, path);
case Opt_space_cache:
printk(KERN_INFO "btrfs: enabling disk space caching\n");
btrfs_set_opt(info->mount_opt, SPACE_CACHE);
+ break;
case Opt_clear_cache:
printk(KERN_INFO "btrfs: force clearing of disk cache\n");
btrfs_set_opt(info->mount_opt, CLEAR_CACHE);
static int btrfs_test_super(struct super_block *s, void *data)
{
- struct btrfs_fs_devices *test_fs_devices = data;
+ struct btrfs_root *test_root = data;
struct btrfs_root *root = btrfs_sb(s);
- return root->fs_info->fs_devices == test_fs_devices;
+ /*
+ * If this super block is going away, return false as it
+ * can't match as an existing super block.
+ */
+ if (!atomic_read(&s->s_active))
+ return 0;
+ return root->fs_info->fs_devices == test_root->fs_info->fs_devices;
+}
+
+static int btrfs_set_super(struct super_block *s, void *data)
+{
+ s->s_fs_info = data;
+
+ return set_anon_super(s, data);
}
+
/*
* Find a superblock for the given device / mount point.
*
struct super_block *s;
struct dentry *root;
struct btrfs_fs_devices *fs_devices = NULL;
+ struct btrfs_root *tree_root = NULL;
+ struct btrfs_fs_info *fs_info = NULL;
fmode_t mode = FMODE_READ;
char *subvol_name = NULL;
u64 subvol_objectid = 0;
goto error_close_devices;
}
+ /*
+ * Setup a dummy root and fs_info for test/set super. This is because
+ * we don't actually fill this stuff out until open_ctree, but we need
+ * it for searching for existing supers, so this lets us do that and
+ * then open_ctree will properly initialize everything later.
+ */
+ fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS);
+ tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
+ if (!fs_info || !tree_root) {
+ error = -ENOMEM;
+ goto error_close_devices;
+ }
+ fs_info->tree_root = tree_root;
+ fs_info->fs_devices = fs_devices;
+ tree_root->fs_info = fs_info;
+
bdev = fs_devices->latest_bdev;
- s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices);
+ s = sget(fs_type, btrfs_test_super, btrfs_set_super, tree_root);
if (IS_ERR(s))
goto error_s;
mutex_unlock(&root->d_inode->i_mutex);
if (IS_ERR(new_root)) {
+ dput(root);
deactivate_locked_super(s);
error = PTR_ERR(new_root);
- dput(root);
goto error_free_subvol_name;
}
if (!new_root->d_inode) {
error = PTR_ERR(s);
error_close_devices:
btrfs_close_devices(fs_devices);
+ kfree(fs_info);
+ kfree(tree_root);
error_free_subvol_name:
kfree(subvol_name);
return ERR_PTR(error);
struct btrfs_root *root = pending->root;
struct btrfs_root *parent_root;
struct inode *parent_inode;
+ struct dentry *parent;
struct dentry *dentry;
struct extent_buffer *tmp;
struct extent_buffer *old;
trans->block_rsv = &pending->block_rsv;
dentry = pending->dentry;
- parent_inode = dentry->d_parent->d_inode;
+ parent = dget_parent(dentry);
+ parent_inode = parent->d_inode;
parent_root = BTRFS_I(parent_inode)->root;
record_root_in_trans(trans, parent_root);
parent_inode->i_ino, index,
dentry->d_name.name, dentry->d_name.len);
BUG_ON(ret);
+ dput(parent);
key.offset = (u64)-1;
pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
{
int ret = 0;
struct btrfs_root *root;
+ struct dentry *old_parent = NULL;
/*
* for regular files, if its inode is already on disk, we don't
if (IS_ROOT(parent))
break;
- parent = parent->d_parent;
+ parent = dget_parent(parent);
+ dput(old_parent);
+ old_parent = parent;
inode = parent->d_inode;
}
+ dput(old_parent);
out:
return ret;
}
{
int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL;
struct super_block *sb;
+ struct dentry *old_parent = NULL;
int ret = 0;
u64 last_committed = root->fs_info->last_trans_committed;
if (IS_ROOT(parent))
break;
- parent = parent->d_parent;
+ parent = dget_parent(parent);
+ dput(old_parent);
+ old_parent = parent;
}
ret = 0;
end_trans:
+ dput(old_parent);
if (ret < 0) {
BUG_ON(ret != -ENOSPC);
root->fs_info->last_trans_log_full_commit = trans->transid;
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct dentry *dentry)
{
- return btrfs_log_inode_parent(trans, root, dentry->d_inode,
- dentry->d_parent, 0);
+ struct dentry *parent = dget_parent(dentry);
+ int ret;
+
+ ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, 0);
+ dput(parent);
+
+ return ret;
}
/*
device->fs_devices = fs_devices;
fs_devices->num_devices++;
- } else if (strcmp(device->name, path)) {
+ } else if (!device->name || strcmp(device->name, path)) {
name = kstrdup(path, GFP_NOFS);
if (!name)
return -ENOMEM;
kfree(device->name);
device->name = name;
+ if (device->missing) {
+ fs_devices->missing_devices--;
+ device->missing = 0;
+ }
}
if (found_transid > fs_devices->latest_trans) {
device->fs_devices->num_devices--;
+ if (device->missing)
+ root->fs_info->fs_devices->missing_devices--;
+
next_device = list_entry(root->fs_info->fs_devices->devices.next,
struct btrfs_device, dev_list);
if (device->bdev == root->fs_info->sb->s_bdev)
device->devid = devid;
device->work.func = pending_bios_fn;
device->fs_devices = fs_devices;
+ device->missing = 1;
fs_devices->num_devices++;
+ fs_devices->missing_devices++;
spin_lock_init(&device->io_lock);
INIT_LIST_HEAD(&device->dev_alloc_list);
memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE);
device = add_missing_dev(root, devid, dev_uuid);
if (!device)
return -ENOMEM;
+ } else if (!device->missing) {
+ /*
+ * this happens when a device that was properly setup
+ * in the device info lists suddenly goes bad.
+ * device->bdev is NULL, and so we have to set
+ * device->missing to one here
+ */
+ root->fs_info->fs_devices->missing_devices++;
+ device->missing = 1;
}
}
int writeable;
int in_fs_metadata;
+ int missing;
spinlock_t io_lock;
u64 num_devices;
u64 open_devices;
u64 rw_devices;
+ u64 missing_devices;
u64 total_rw_bytes;
struct block_device *latest_bdev;
err = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
page->index << PAGE_CACHE_SHIFT, &len,
ci->i_truncate_seq, ci->i_truncate_size,
- &page, 1);
+ &page, 1, 0);
if (err == -ENOENT)
err = 0;
if (err < 0) {
rc = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
offset, &len,
ci->i_truncate_seq, ci->i_truncate_size,
- pages, nr_pages);
+ pages, nr_pages, 0);
if (rc == -ENOENT)
rc = 0;
if (rc < 0)
snapc, do_sync,
ci->i_truncate_seq,
ci->i_truncate_size,
- &inode->i_mtime, true, 1);
+ &inode->i_mtime, true, 1, 0);
max_pages = req->r_num_pages;
alloc_page_vec(fsc, req);
invalidating_gen == ci->i_rdcache_gen) {
/* success. */
dout("try_nonblocking_invalidate %p success\n", inode);
- ci->i_rdcache_gen = 0;
- ci->i_rdcache_revoking = 0;
+ /* save any racing async invalidate some trouble */
+ ci->i_rdcache_revoking = ci->i_rdcache_gen - 1;
return 0;
}
dout("try_nonblocking_invalidate %p failed\n", inode);
{
struct ceph_inode_info *ci = ceph_inode(inode);
int mds = session->s_mds;
- unsigned seq = le32_to_cpu(grant->seq);
- unsigned issue_seq = le32_to_cpu(grant->issue_seq);
+ int seq = le32_to_cpu(grant->seq);
int newcaps = le32_to_cpu(grant->caps);
int issued, implemented, used, wanted, dirty;
u64 size = le64_to_cpu(grant->size);
int revoked_rdcache = 0;
int queue_invalidate = 0;
- dout("handle_cap_grant inode %p cap %p mds%d seq %u/%u %s\n",
- inode, cap, mds, seq, issue_seq, ceph_cap_string(newcaps));
+ dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n",
+ inode, cap, mds, seq, ceph_cap_string(newcaps));
dout(" size %llu max_size %llu, i_size %llu\n", size, max_size,
inode->i_size);
}
cap->seq = seq;
- cap->issue_seq = issue_seq;
/* file layout may have changed */
ci->i_layout = grant->layout;
NULL /* no caps context */);
try_flush_caps(inode, session, NULL);
up_read(&mdsc->snap_rwsem);
+
+ /* make sure we re-request max_size, if necessary */
+ spin_lock(&inode->i_lock);
+ ci->i_requested_max_size = 0;
+ spin_unlock(&inode->i_lock);
}
/*
spin_lock(&dcache_lock);
/* start at beginning? */
- if (filp->f_pos == 2 || (last &&
- filp->f_pos < ceph_dentry(last)->offset)) {
+ if (filp->f_pos == 2 || last == NULL ||
+ filp->f_pos < ceph_dentry(last)->offset) {
if (list_empty(&parent->d_subdirs))
goto out_unlock;
p = parent->d_subdirs.prev;
if (req->r_reply_info.dir_end) {
kfree(fi->last_name);
fi->last_name = NULL;
- fi->next_offset = 2;
+ if (ceph_frag_is_rightmost(frag))
+ fi->next_offset = 2;
+ else
+ fi->next_offset = 0;
} else {
rinfo = &req->r_reply_info;
err = note_last_dentry(fi,
u64 pos = ceph_make_fpos(frag, off);
struct ceph_mds_reply_inode *in =
rinfo->dir_in[off - fi->offset].in;
+ struct ceph_vino vino;
+ ino_t ino;
+
dout("readdir off %d (%d/%d) -> %lld '%.*s' %p\n",
off, off - fi->offset, rinfo->dir_nr, pos,
rinfo->dir_dname_len[off - fi->offset],
rinfo->dir_dname[off - fi->offset], in);
BUG_ON(!in);
ftype = le32_to_cpu(in->mode) >> 12;
+ vino.ino = le64_to_cpu(in->ino);
+ vino.snap = le64_to_cpu(in->snapid);
+ ino = ceph_vino_to_ino(vino);
if (filldir(dirent,
rinfo->dir_dname[off - fi->offset],
rinfo->dir_dname_len[off - fi->offset],
- pos,
- le64_to_cpu(in->ino),
- ftype) < 0) {
+ pos, ino, ftype) < 0) {
dout("filldir stopping us...\n");
return 0;
}
fi->last_readdir = NULL;
}
kfree(fi->last_name);
+ fi->last_name = NULL;
fi->next_offset = 2; /* compensate for . and .. */
if (fi->dentry) {
dput(fi->dentry);
}
/*
- * No need to block if we have any caps. Update wanted set
+ * No need to block if we have caps on the auth MDS (for
+ * write) or any MDS (for read). Update wanted set
* asynchronously.
*/
spin_lock(&inode->i_lock);
- if (__ceph_is_any_real_caps(ci)) {
+ if (__ceph_is_any_real_caps(ci) &&
+ (((fmode & CEPH_FILE_MODE_WR) == 0) || ci->i_auth_cap)) {
int mds_wanted = __ceph_caps_mds_wanted(ci);
int issued = __ceph_caps_issued(ci, NULL);
static int striped_read(struct inode *inode,
u64 off, u64 len,
struct page **pages, int num_pages,
- int *checkeof)
+ int *checkeof, bool align_to_pages)
{
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
struct ceph_inode_info *ci = ceph_inode(inode);
u64 pos, this_len;
+ int io_align, page_align;
int page_off = off & ~PAGE_CACHE_MASK; /* first byte's offset in page */
int left, pages_left;
int read;
page_pos = pages;
pages_left = num_pages;
read = 0;
+ io_align = off & ~PAGE_MASK;
more:
+ if (align_to_pages)
+ page_align = (pos - io_align) & ~PAGE_MASK;
+ else
+ page_align = pos & ~PAGE_MASK;
this_len = left;
ret = ceph_osdc_readpages(&fsc->client->osdc, ceph_vino(inode),
&ci->i_layout, pos, &this_len,
ci->i_truncate_seq,
ci->i_truncate_size,
- page_pos, pages_left);
+ page_pos, pages_left, page_align);
hit_stripe = this_len < left;
was_short = ret >= 0 && ret < this_len;
if (ret == -ENOENT)
dout("sync_read on file %p %llu~%u %s\n", file, off, len,
(file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
- if (file->f_flags & O_DIRECT) {
- pages = ceph_get_direct_page_vector(data, num_pages, off, len);
-
- /*
- * flush any page cache pages in this range. this
- * will make concurrent normal and O_DIRECT io slow,
- * but it will at least behave sensibly when they are
- * in sequence.
- */
- } else {
+ if (file->f_flags & O_DIRECT)
+ pages = ceph_get_direct_page_vector(data, num_pages);
+ else
pages = ceph_alloc_page_vector(num_pages, GFP_NOFS);
- }
if (IS_ERR(pages))
return PTR_ERR(pages);
+ /*
+ * flush any page cache pages in this range. this
+ * will make concurrent normal and sync io slow,
+ * but it will at least behave sensibly when they are
+ * in sequence.
+ */
ret = filemap_write_and_wait(inode->i_mapping);
if (ret < 0)
goto done;
- ret = striped_read(inode, off, len, pages, num_pages, checkeof);
+ ret = striped_read(inode, off, len, pages, num_pages, checkeof,
+ file->f_flags & O_DIRECT);
if (ret >= 0 && (file->f_flags & O_DIRECT) == 0)
ret = ceph_copy_page_vector_to_user(pages, data, off, ret);
int flags;
int do_sync = 0;
int check_caps = 0;
+ int page_align, io_align;
int ret;
struct timespec mtime = CURRENT_TIME;
else
pos = *offset;
+ io_align = pos & ~PAGE_MASK;
+
ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left);
if (ret < 0)
return ret;
*/
more:
len = left;
+ if (file->f_flags & O_DIRECT)
+ /* write from beginning of first page, regardless of
+ io alignment */
+ page_align = (pos - io_align) & ~PAGE_MASK;
+ else
+ page_align = pos & ~PAGE_MASK;
req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
ceph_vino(inode), pos, &len,
CEPH_OSD_OP_WRITE, flags,
ci->i_snap_realm->cached_context,
do_sync,
ci->i_truncate_seq, ci->i_truncate_size,
- &mtime, false, 2);
+ &mtime, false, 2, page_align);
if (!req)
return -ENOMEM;
num_pages = calc_pages_for(pos, len);
if (file->f_flags & O_DIRECT) {
- pages = ceph_get_direct_page_vector(data, num_pages, pos, len);
+ pages = ceph_get_direct_page_vector(data, num_pages);
if (IS_ERR(pages)) {
ret = PTR_ERR(pages);
goto out;
#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/uaccess.h>
if (issued & (CEPH_CAP_FILE_EXCL|
CEPH_CAP_FILE_WR|
- CEPH_CAP_FILE_BUFFER)) {
+ CEPH_CAP_FILE_BUFFER|
+ CEPH_CAP_AUTH_EXCL|
+ CEPH_CAP_XATTR_EXCL)) {
if (timespec_compare(ctime, &inode->i_ctime) > 0) {
dout("ctime %ld.%09ld -> %ld.%09ld inc w/ cap\n",
inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
warn = 1;
}
} else {
- /* we have no write caps; whatever the MDS says is true */
+ /* we have no write|excl caps; whatever the MDS says is true */
if (ceph_seq_cmp(time_warp_seq, ci->i_time_warp_seq) >= 0) {
inode->i_ctime = *ctime;
inode->i_mtime = *mtime;
/*
* provided version will be odd if inode value is projected,
- * even if stable. skip the update if we have a newer info
- * (e.g., due to inode info racing form multiple MDSs), or if
- * we are getting projected (unstable) inode info.
+ * even if stable. skip the update if we have newer stable
+ * info (ours>=theirs, e.g. due to racing mds replies), unless
+ * we are getting projected (unstable) info (in which case the
+ * version is odd, and we want ours>theirs).
+ * us them
+ * 2 2 skip
+ * 3 2 skip
+ * 3 3 update
*/
if (le64_to_cpu(info->version) > 0 &&
- (ci->i_version & ~1) > le64_to_cpu(info->version))
+ (ci->i_version & ~1) >= le64_to_cpu(info->version))
goto no_change;
issued = __ceph_caps_issued(ci, &implemented);
le32_to_cpu(info->time_warp_seq),
&ctime, &mtime, &atime);
- ci->i_max_size = le64_to_cpu(info->max_size);
+ /* only update max_size on auth cap */
+ if ((info->cap.flags & CEPH_CAP_FLAG_AUTH) &&
+ ci->i_max_size != le64_to_cpu(info->max_size)) {
+ dout("max_size %lld -> %llu\n", ci->i_max_size,
+ le64_to_cpu(info->max_size));
+ ci->i_max_size = le64_to_cpu(info->max_size);
+ }
+
ci->i_layout = info->layout;
inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
ininfo = rinfo->targeti.in;
vino.ino = le64_to_cpu(ininfo->ino);
vino.snap = le64_to_cpu(ininfo->snapid);
- if (!dn->d_inode) {
+ in = dn->d_inode;
+ if (!in) {
in = ceph_get_inode(sb, vino);
if (IS_ERR(in)) {
pr_err("fill_trace bad get_inode "
spin_lock(&inode->i_lock);
dout("invalidate_pages %p gen %d revoking %d\n", inode,
ci->i_rdcache_gen, ci->i_rdcache_revoking);
- if (ci->i_rdcache_gen == 0 ||
- ci->i_rdcache_revoking != ci->i_rdcache_gen) {
- BUG_ON(ci->i_rdcache_revoking > ci->i_rdcache_gen);
+ if (ci->i_rdcache_revoking != ci->i_rdcache_gen) {
/* nevermind! */
- ci->i_rdcache_revoking = 0;
spin_unlock(&inode->i_lock);
goto out;
}
ceph_invalidate_nondirty_pages(inode->i_mapping);
spin_lock(&inode->i_lock);
- if (orig_gen == ci->i_rdcache_gen) {
+ if (orig_gen == ci->i_rdcache_gen &&
+ orig_gen == ci->i_rdcache_revoking) {
dout("invalidate_pages %p gen %d successful\n", inode,
ci->i_rdcache_gen);
- ci->i_rdcache_gen = 0;
- ci->i_rdcache_revoking = 0;
+ ci->i_rdcache_revoking--;
check = 1;
} else {
- dout("invalidate_pages %p gen %d raced, gen now %d\n",
- inode, orig_gen, ci->i_rdcache_gen);
+ dout("invalidate_pages %p gen %d raced, now %d revoking %d\n",
+ inode, orig_gen, ci->i_rdcache_gen,
+ ci->i_rdcache_revoking);
}
spin_unlock(&inode->i_lock);
return 0;
}
- dout("do_getattr inode %p mask %s\n", inode, ceph_cap_string(mask));
+ dout("do_getattr inode %p mask %s mode 0%o\n", inode, ceph_cap_string(mask), inode->i_mode);
if (ceph_caps_issued_mask(ceph_inode(inode), mask, 1))
return 0;
#include <linux/ioctl.h>
#include <linux/types.h>
-#define CEPH_IOCTL_MAGIC 0x98
+#define CEPH_IOCTL_MAGIC 0x97
/* just use u64 to align sanely on all archs */
struct ceph_ioctl_layout {
* Implement fcntl and flock locking functions.
*/
static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
- u64 pid, u64 pid_ns,
- int cmd, u64 start, u64 length, u8 wait)
+ int cmd, u8 wait, struct file_lock *fl)
{
struct inode *inode = file->f_dentry->d_inode;
struct ceph_mds_client *mdsc =
ceph_sb_to_client(inode->i_sb)->mdsc;
struct ceph_mds_request *req;
int err;
+ u64 length = 0;
req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS);
if (IS_ERR(req))
return PTR_ERR(req);
req->r_inode = igrab(inode);
+ /* mds requires start and length rather than start and end */
+ if (LLONG_MAX == fl->fl_end)
+ length = 0;
+ else
+ length = fl->fl_end - fl->fl_start + 1;
+
dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
"length: %llu, wait: %d, type`: %d", (int)lock_type,
- (int)operation, pid, start, length, wait, cmd);
+ (int)operation, (u64)fl->fl_pid, fl->fl_start,
+ length, wait, fl->fl_type);
+
req->r_args.filelock_change.rule = lock_type;
req->r_args.filelock_change.type = cmd;
- req->r_args.filelock_change.pid = cpu_to_le64(pid);
+ req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid);
/* This should be adjusted, but I'm not sure if
namespaces actually get id numbers*/
req->r_args.filelock_change.pid_namespace =
- cpu_to_le64((u64)pid_ns);
- req->r_args.filelock_change.start = cpu_to_le64(start);
+ cpu_to_le64((u64)(unsigned long)fl->fl_nspid);
+ req->r_args.filelock_change.start = cpu_to_le64(fl->fl_start);
req->r_args.filelock_change.length = cpu_to_le64(length);
req->r_args.filelock_change.wait = wait;
err = ceph_mdsc_do_request(mdsc, inode, req);
+
+ if ( operation == CEPH_MDS_OP_GETFILELOCK){
+ fl->fl_pid = le64_to_cpu(req->r_reply_info.filelock_reply->pid);
+ if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type)
+ fl->fl_type = F_RDLCK;
+ else if (CEPH_LOCK_EXCL == req->r_reply_info.filelock_reply->type)
+ fl->fl_type = F_WRLCK;
+ else
+ fl->fl_type = F_UNLCK;
+
+ fl->fl_start = le64_to_cpu(req->r_reply_info.filelock_reply->start);
+ length = le64_to_cpu(req->r_reply_info.filelock_reply->start) +
+ le64_to_cpu(req->r_reply_info.filelock_reply->length);
+ if (length >= 1)
+ fl->fl_end = length -1;
+ else
+ fl->fl_end = 0;
+
+ }
ceph_mdsc_put_request(req);
dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
- "length: %llu, wait: %d, type`: %d err code %d", (int)lock_type,
- (int)operation, pid, start, length, wait, cmd, err);
+ "length: %llu, wait: %d, type`: %d, err code %d", (int)lock_type,
+ (int)operation, (u64)fl->fl_pid, fl->fl_start,
+ length, wait, fl->fl_type, err);
return err;
}
*/
int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
{
- u64 length;
u8 lock_cmd;
int err;
u8 wait = 0;
else
lock_cmd = CEPH_LOCK_UNLOCK;
- if (LLONG_MAX == fl->fl_end)
- length = 0;
- else
- length = fl->fl_end - fl->fl_start + 1;
-
- err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
- (u64)fl->fl_pid,
- (u64)(unsigned long)fl->fl_nspid,
- lock_cmd, fl->fl_start,
- length, wait);
+ err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl);
if (!err) {
- dout("mds locked, locking locally");
- err = posix_lock_file(file, fl, NULL);
- if (err && (CEPH_MDS_OP_SETFILELOCK == op)) {
- /* undo! This should only happen if the kernel detects
- * local deadlock. */
- ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
- (u64)fl->fl_pid,
- (u64)(unsigned long)fl->fl_nspid,
- CEPH_LOCK_UNLOCK, fl->fl_start,
- length, 0);
- dout("got %d on posix_lock_file, undid lock", err);
+ if ( op != CEPH_MDS_OP_GETFILELOCK ){
+ dout("mds locked, locking locally");
+ err = posix_lock_file(file, fl, NULL);
+ if (err && (CEPH_MDS_OP_SETFILELOCK == op)) {
+ /* undo! This should only happen if the kernel detects
+ * local deadlock. */
+ ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
+ CEPH_LOCK_UNLOCK, 0, fl);
+ dout("got %d on posix_lock_file, undid lock", err);
+ }
}
+
} else {
dout("mds returned error code %d", err);
}
int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
{
- u64 length;
u8 lock_cmd;
int err;
u8 wait = 1;
lock_cmd = CEPH_LOCK_EXCL;
else
lock_cmd = CEPH_LOCK_UNLOCK;
- /* mds requires start and length rather than start and end */
- if (LLONG_MAX == fl->fl_end)
- length = 0;
- else
- length = fl->fl_end - fl->fl_start + 1;
err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK,
- file, (u64)fl->fl_pid,
- (u64)(unsigned long)fl->fl_nspid,
- lock_cmd, fl->fl_start,
- length, wait);
+ file, lock_cmd, wait, fl);
if (!err) {
err = flock_lock_file_wait(file, fl);
if (err) {
ceph_lock_message(CEPH_LOCK_FLOCK,
CEPH_MDS_OP_SETFILELOCK,
- file, (u64)fl->fl_pid,
- (u64)(unsigned long)fl->fl_nspid,
- CEPH_LOCK_UNLOCK, fl->fl_start,
- length, 0);
+ file, CEPH_LOCK_UNLOCK, 0, fl);
dout("got %d on flock_lock_file_wait, undid lock", err);
}
} else {
#include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include "super.h"
#include "mds_client.h"
return err;
}
+/*
+ * parse fcntl F_GETLK results
+ */
+static int parse_reply_info_filelock(void **p, void *end,
+ struct ceph_mds_reply_info_parsed *info)
+{
+ if (*p + sizeof(*info->filelock_reply) > end)
+ goto bad;
+
+ info->filelock_reply = *p;
+ *p += sizeof(*info->filelock_reply);
+
+ if (unlikely(*p != end))
+ goto bad;
+ return 0;
+
+bad:
+ return -EIO;
+}
+
+/*
+ * parse extra results
+ */
+static int parse_reply_info_extra(void **p, void *end,
+ struct ceph_mds_reply_info_parsed *info)
+{
+ if (info->head->op == CEPH_MDS_OP_GETFILELOCK)
+ return parse_reply_info_filelock(p, end, info);
+ else
+ return parse_reply_info_dir(p, end, info);
+}
+
/*
* parse entire mds reply
*/
goto out_bad;
}
- /* dir content */
+ /* extra */
ceph_decode_32_safe(&p, end, len, bad);
if (len > 0) {
- err = parse_reply_info_dir(&p, p+len, info);
+ err = parse_reply_info_extra(&p, p+len, info);
if (err < 0)
goto out_bad;
}
ceph_mdsc_get_request(req);
__insert_request(mdsc, req);
+ req->r_uid = current_fsuid();
+ req->r_gid = current_fsgid();
+
if (dir) {
struct ceph_inode_info *ci = ceph_inode(dir);
head->mdsmap_epoch = cpu_to_le32(mdsc->mdsmap->m_epoch);
head->op = cpu_to_le32(req->r_op);
- head->caller_uid = cpu_to_le32(current_fsuid());
- head->caller_gid = cpu_to_le32(current_fsgid());
+ head->caller_uid = cpu_to_le32(req->r_uid);
+ head->caller_gid = cpu_to_le32(req->r_gid);
head->args = req->r_args;
ceph_encode_filepath(&p, end, ino1, path1);
mutex_lock(&session->s_mutex);
if (err < 0) {
- pr_err("mdsc_handle_reply got corrupt reply mds%d\n", mds);
+ pr_err("mdsc_handle_reply got corrupt reply mds%d(tid:%lld)\n", mds, tid);
ceph_msg_dump(msg);
goto out_err;
}
mutex_lock(&req->r_fill_mutex);
err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session);
if (err == 0) {
- if (result == 0 && rinfo->dir_nr)
+ if (result == 0 && req->r_op != CEPH_MDS_OP_GETFILELOCK &&
+ rinfo->dir_nr)
ceph_readdir_prepopulate(req, req->r_session);
ceph_unreserve_caps(mdsc, &req->r_caps_reservation);
}
};
/*
- * parsed info about an mds reply, including information about the
- * target inode and/or its parent directory and dentry, and directory
- * contents (for readdir results).
+ * parsed info about an mds reply, including information about
+ * either: 1) the target inode and/or its parent directory and dentry,
+ * and directory contents (for readdir results), or
+ * 2) the file range lock info (for fcntl F_GETLK results).
*/
struct ceph_mds_reply_info_parsed {
struct ceph_mds_reply_head *head;
+ /* trace */
struct ceph_mds_reply_info_in diri, targeti;
struct ceph_mds_reply_dirfrag *dirfrag;
char *dname;
u32 dname_len;
struct ceph_mds_reply_lease *dlease;
- struct ceph_mds_reply_dirfrag *dir_dir;
- int dir_nr;
- char **dir_dname;
- u32 *dir_dname_len;
- struct ceph_mds_reply_lease **dir_dlease;
- struct ceph_mds_reply_info_in *dir_in;
- u8 dir_complete, dir_end;
+ /* extra */
+ union {
+ /* for fcntl F_GETLK results */
+ struct ceph_filelock *filelock_reply;
+
+ /* for readdir results */
+ struct {
+ struct ceph_mds_reply_dirfrag *dir_dir;
+ int dir_nr;
+ char **dir_dname;
+ u32 *dir_dname_len;
+ struct ceph_mds_reply_lease **dir_dlease;
+ struct ceph_mds_reply_info_in *dir_in;
+ u8 dir_complete, dir_end;
+ };
+ };
/* encoded blob describing snapshot contexts for certain
operations (e.g., open) */
union ceph_mds_request_args r_args;
int r_fmode; /* file mode, if expecting cap */
+ uid_t r_uid;
+ gid_t r_gid;
/* for choosing which mds to send this request to */
int r_direct_mode;
int i_rd_ref, i_rdcache_ref, i_wr_ref;
int i_wrbuffer_ref, i_wrbuffer_ref_head;
u32 i_shared_gen; /* increment each time we get FILE_SHARED */
- u32 i_rdcache_gen; /* we increment this each time we get
- FILE_CACHE. If it's non-zero, we
- _may_ have cached pages. */
+ u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */
u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */
struct list_head i_unsafe_writes; /* uncommitted sync writes */
select NLS
select CRYPTO
select CRYPTO_MD5
+ select CRYPTO_HMAC
select CRYPTO_ARC4
help
This is the client VFS module for the Common Internet File System
to be cached locally on disk through the general filesystem cache
manager. If unsure, say N.
+config CIFS_ACL
+ bool "Provide CIFS ACL support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && CIFS_XATTR
+ help
+ Allows to fetch CIFS/NTFS ACL from the server. The DACL blob
+ is handed over to the application/caller.
+
config CIFS_EXPERIMENTAL
bool "CIFS Experimental Features (EXPERIMENTAL)"
depends on CIFS && EXPERIMENTAL
cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \
md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
- readdir.o ioctl.o sess.o export.o cifsacl.o
+ readdir.o ioctl.o sess.o export.o
+
+cifs-$(CONFIG_CIFS_ACL) += cifsacl.o
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
wsize default write size (default 57344)
maximum wsize currently allowed by CIFS is 57344 (fourteen
4096 byte pages)
+ actimeo=n attribute cache timeout in seconds (default 1 second).
+ After this timeout, the cifs client requests fresh attribute
+ information from the server. This option allows to tune the
+ attribute cache timeout to suit the workload needs. Shorter
+ timeouts mean better the cache coherency, but increased number
+ of calls to the server. Longer timeouts mean reduced number
+ of calls to the server at the expense of less stricter cache
+ coherency checks (i.e. incorrect attribute cache for a short
+ period of time).
rw mount the network share read-write (note that the
server may still consider the share read-only)
ro mount network share read-only
struct nls_table *local_nls;
unsigned int rsize;
unsigned int wsize;
+ unsigned long actimeo; /* attribute cache timeout (jiffies) */
atomic_t active;
uid_t mnt_uid;
gid_t mnt_gid;
#include "cifs_debug.h"
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-
static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
{{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
{{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
- return NULL;
+ return ERR_CAST(tlink);
xid = GetXid();
rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
cifs_put_tlink(tlink);
- cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);
+ cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
+ if (rc)
+ return ERR_PTR(rc);
return pntsd;
}
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
- return NULL;
+ return ERR_CAST(tlink);
tcon = tlink_tcon(tlink);
xid = GetXid();
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
&fid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc) {
- cERROR(1, "Unable to open file to get ACL");
- goto out;
+ if (!rc) {
+ rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
+ CIFSSMBClose(xid, tcon, fid);
}
- rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
- cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);
-
- CIFSSMBClose(xid, tcon, fid);
- out:
cifs_put_tlink(tlink);
FreeXid(xid);
+
+ cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
+ if (rc)
+ return ERR_PTR(rc);
return pntsd;
}
/* Retrieve an ACL from the server */
-static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
+struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
struct inode *inode, const char *path,
u32 *pacllen)
{
}
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
-void
+int
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
struct inode *inode, const char *path, const __u16 *pfid)
{
pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
- if (pntsd)
+ if (IS_ERR(pntsd)) {
+ rc = PTR_ERR(pntsd);
+ cERROR(1, "%s: error %d getting sec desc", __func__, rc);
+ } else {
rc = parse_sec_desc(pntsd, acllen, fattr);
- if (rc)
- cFYI(1, "parse sec desc failed rc = %d", rc);
+ kfree(pntsd);
+ if (rc)
+ cERROR(1, "parse sec desc failed rc = %d", rc);
+ }
- kfree(pntsd);
- return;
+ return rc;
}
/* Convert mode bits to an ACL so we can update the ACL on the server */
-int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
+int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
{
int rc = 0;
__u32 secdesclen = 0;
/* Add three ACEs for owner, group, everyone getting rid of
other ACEs as chmod disables ACEs and set the security descriptor */
- if (pntsd) {
+ if (IS_ERR(pntsd)) {
+ rc = PTR_ERR(pntsd);
+ cERROR(1, "%s: error %d getting sec desc", __func__, rc);
+ } else {
/* allocate memory for the smb header,
set security descriptor request security descriptor
parameters, and secuirty descriptor itself */
return rc;
}
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
char sidname[SIDNAMELENGTH];
} __attribute__((packed));
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-
extern int match_sid(struct cifs_sid *);
extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *);
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
-
#endif /* _CIFSACL_H */
seq_printf(s, ",acl");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
seq_printf(s, ",mfsymlinks");
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
+ seq_printf(s, ",fsc");
seq_printf(s, ",rsize=%d", cifs_sb->rsize);
seq_printf(s, ",wsize=%d", cifs_sb->wsize);
+ /* convert actimeo and display it in seconds */
+ seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);
return 0;
}
GlobalCurrentXid = 0;
GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0;
- memset(Local_System_Name, 0, 15);
spin_lock_init(&cifs_tcp_ses_lock);
spin_lock_init(&cifs_file_list_lock);
spin_lock_init(&GlobalMid_Lock);
#define CIFS_MIN_RCV_POOL 4
+/*
+ * default attribute cache timeout (jiffies)
+ */
+#define CIFS_DEF_ACTIMEO (1 * HZ)
+
+/*
+ * max attribute cache timeout (jiffies) - 2^30
+ */
+#define CIFS_MAX_ACTIMEO (1 << 30)
+
/*
* MAX_REQ is the maximum number of requests that WE will send
* on one socket concurrently. It also matches the most common
GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */
/* on midQ entries */
-GLOBAL_EXTERN char Local_System_Name[15];
-
/*
* Global counters, updated atomically
*/
__func__, curr_xid, (int)rc); \
} while (0)
extern char *build_path_from_dentry(struct dentry *);
-extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb);
+extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
+ struct cifsTconInfo *tcon);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
extern char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref,
struct TCP_Server_Info *);
extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
-#ifdef CONFIG_CIFS_EXPERIMENTAL
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
-#endif
extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
extern int decode_negTokenInit(unsigned char *security_blob, int length,
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
struct super_block *sb, int xid);
-extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
+extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr, struct inode *inode,
const char *path, const __u16 *pfid);
-extern int mode_to_acl(struct inode *inode, const char *path, __u64);
+extern int mode_to_cifs_acl(struct inode *inode, const char *path, __u64);
+extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
+ const char *, u32 *);
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
const char *);
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
-/* Initialize NT TRANSACT SMB into small smb request buffer.
- This assumes that all NT TRANSACTS that we init here have
- total parm and data under about 400 bytes (to fit in small cifs
- buffer size), which is the case so far, it easily fits. NB:
- Setup words themselves and ByteCount
- MaxSetupCount (size of returned setup area) and
- MaxParameterCount (returned parms size) must be set by caller */
-static int
-smb_init_nttransact(const __u16 sub_command, const int setup_count,
- const int parm_len, struct cifsTconInfo *tcon,
- void **ret_buf)
-{
- int rc;
- __u32 temp_offset;
- struct smb_com_ntransact_req *pSMB;
-
- rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
- (void **)&pSMB);
- if (rc)
- return rc;
- *ret_buf = (void *)pSMB;
- pSMB->Reserved = 0;
- pSMB->TotalParameterCount = cpu_to_le32(parm_len);
- pSMB->TotalDataCount = 0;
- pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
- MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->DataCount = pSMB->TotalDataCount;
- temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
- (setup_count * 2) - 4 /* for rfc1001 length itself */;
- pSMB->ParameterOffset = cpu_to_le32(temp_offset);
- pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
- pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
- pSMB->SubCommand = cpu_to_le16(sub_command);
- return 0;
-}
-
-static int
-validate_ntransact(char *buf, char **ppparm, char **ppdata,
- __u32 *pparmlen, __u32 *pdatalen)
-{
- char *end_of_smb;
- __u32 data_count, data_offset, parm_count, parm_offset;
- struct smb_com_ntransact_rsp *pSMBr;
-
- *pdatalen = 0;
- *pparmlen = 0;
-
- if (buf == NULL)
- return -EINVAL;
-
- pSMBr = (struct smb_com_ntransact_rsp *)buf;
-
- /* ByteCount was converted from little endian in SendReceive */
- end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
- (char *)&pSMBr->ByteCount;
-
- data_offset = le32_to_cpu(pSMBr->DataOffset);
- data_count = le32_to_cpu(pSMBr->DataCount);
- parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
- parm_count = le32_to_cpu(pSMBr->ParameterCount);
-
- *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
- *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
-
- /* should we also check that parm and data areas do not overlap? */
- if (*ppparm > end_of_smb) {
- cFYI(1, "parms start after end of smb");
- return -EINVAL;
- } else if (parm_count + *ppparm > end_of_smb) {
- cFYI(1, "parm end after end of smb");
- return -EINVAL;
- } else if (*ppdata > end_of_smb) {
- cFYI(1, "data starts after end of smb");
- return -EINVAL;
- } else if (data_count + *ppdata > end_of_smb) {
- cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
- *ppdata, data_count, (data_count + *ppdata),
- end_of_smb, pSMBr);
- return -EINVAL;
- } else if (parm_count + data_count > pSMBr->ByteCount) {
- cFYI(1, "parm count and data count larger than SMB");
- return -EINVAL;
- }
- *pdatalen = data_count;
- *pparmlen = parm_count;
- return 0;
-}
-
int
CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
#endif /* CONFIG_POSIX */
-#ifdef CONFIG_CIFS_EXPERIMENTAL
+#ifdef CONFIG_CIFS_ACL
+/*
+ * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
+ * all NT TRANSACTS that we init here have total parm and data under about 400
+ * bytes (to fit in small cifs buffer size), which is the case so far, it
+ * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
+ * returned setup area) and MaxParameterCount (returned parms size) must be set
+ * by caller
+ */
+static int
+smb_init_nttransact(const __u16 sub_command, const int setup_count,
+ const int parm_len, struct cifsTconInfo *tcon,
+ void **ret_buf)
+{
+ int rc;
+ __u32 temp_offset;
+ struct smb_com_ntransact_req *pSMB;
+
+ rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
+ (void **)&pSMB);
+ if (rc)
+ return rc;
+ *ret_buf = (void *)pSMB;
+ pSMB->Reserved = 0;
+ pSMB->TotalParameterCount = cpu_to_le32(parm_len);
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
+ MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->DataCount = pSMB->TotalDataCount;
+ temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
+ (setup_count * 2) - 4 /* for rfc1001 length itself */;
+ pSMB->ParameterOffset = cpu_to_le32(temp_offset);
+ pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
+ pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
+ pSMB->SubCommand = cpu_to_le16(sub_command);
+ return 0;
+}
+
+static int
+validate_ntransact(char *buf, char **ppparm, char **ppdata,
+ __u32 *pparmlen, __u32 *pdatalen)
+{
+ char *end_of_smb;
+ __u32 data_count, data_offset, parm_count, parm_offset;
+ struct smb_com_ntransact_rsp *pSMBr;
+
+ *pdatalen = 0;
+ *pparmlen = 0;
+
+ if (buf == NULL)
+ return -EINVAL;
+
+ pSMBr = (struct smb_com_ntransact_rsp *)buf;
+
+ /* ByteCount was converted from little endian in SendReceive */
+ end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
+ (char *)&pSMBr->ByteCount;
+
+ data_offset = le32_to_cpu(pSMBr->DataOffset);
+ data_count = le32_to_cpu(pSMBr->DataCount);
+ parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
+ parm_count = le32_to_cpu(pSMBr->ParameterCount);
+
+ *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
+ *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
+
+ /* should we also check that parm and data areas do not overlap? */
+ if (*ppparm > end_of_smb) {
+ cFYI(1, "parms start after end of smb");
+ return -EINVAL;
+ } else if (parm_count + *ppparm > end_of_smb) {
+ cFYI(1, "parm end after end of smb");
+ return -EINVAL;
+ } else if (*ppdata > end_of_smb) {
+ cFYI(1, "data starts after end of smb");
+ return -EINVAL;
+ } else if (data_count + *ppdata > end_of_smb) {
+ cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
+ *ppdata, data_count, (data_count + *ppdata),
+ end_of_smb, pSMBr);
+ return -EINVAL;
+ } else if (parm_count + data_count > pSMBr->ByteCount) {
+ cFYI(1, "parm count and data count larger than SMB");
+ return -EINVAL;
+ }
+ *pdatalen = data_count;
+ *pparmlen = parm_count;
+ return 0;
+}
+
/* Get Security Descriptor (by handle) from remote server for a file or dir */
int
CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
return (rc);
}
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
+#endif /* CONFIG_CIFS_ACL */
/* Legacy Query Path Information call for lookup to old servers such
as Win9x/WinME */
unsigned int wsize;
bool sockopt_tcp_nodelay:1;
unsigned short int port;
+ unsigned long actimeo; /* attribute cache timeout (jiffies) */
char *prepath;
struct sockaddr_storage srcaddr; /* allow binding to a local IP */
struct nls_table *local_nls;
short int override_gid = -1;
bool uid_specified = false;
bool gid_specified = false;
+ char *nodename = utsname()->nodename;
separator[0] = ',';
separator[1] = 0;
- if (Local_System_Name[0] != 0)
- memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
- else {
- char *nodename = utsname()->nodename;
- int n = strnlen(nodename, 15);
- memset(vol->source_rfc1001_name, 0x20, 15);
- for (i = 0; i < n; i++) {
- /* does not have to be perfect mapping since field is
- informational, only used for servers that do not support
- port 445 and it can be overridden at mount time */
- vol->source_rfc1001_name[i] = toupper(nodename[i]);
- }
- }
+ /*
+ * does not have to be perfect mapping since field is
+ * informational, only used for servers that do not support
+ * port 445 and it can be overridden at mount time
+ */
+ memset(vol->source_rfc1001_name, 0x20, 15);
+ for (i = 0; i < strnlen(nodename, 15); i++)
+ vol->source_rfc1001_name[i] = toupper(nodename[i]);
+
vol->source_rfc1001_name[15] = 0;
/* null target name indicates to use *SMBSERVR default called name
if we end up sending RFC1001 session initialize */
/* default to using server inode numbers where available */
vol->server_ino = 1;
+ vol->actimeo = CIFS_DEF_ACTIMEO;
+
if (!options)
return 1;
printk(KERN_WARNING "CIFS: server net"
"biosname longer than 15 truncated.\n");
}
+ } else if (strnicmp(data, "actimeo", 7) == 0) {
+ if (value && *value) {
+ vol->actimeo = HZ * simple_strtoul(value,
+ &value, 0);
+ if (vol->actimeo > CIFS_MAX_ACTIMEO) {
+ cERROR(1, "CIFS: attribute cache"
+ "timeout too large");
+ return 1;
+ }
+ }
} else if (strnicmp(data, "credentials", 4) == 0) {
/* ignore */
} else if (strnicmp(data, "version", 3) == 0) {
"supported. Instead set "
"/proc/fs/cifs/LookupCacheEnabled to 0\n");
} else if (strnicmp(data, "fsc", 3) == 0) {
+#ifndef CONFIG_CIFS_FSCACHE
+ cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE"
+ "kernel config option set");
+ return 1;
+#endif
vol->fsc = true;
} else if (strnicmp(data, "mfsymlinks", 10) == 0) {
vol->mfsymlinks = true;
cFYI(1, "file mode: 0x%x dir mode: 0x%x",
cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
+ cifs_sb->actimeo = pvolume_info->actimeo;
+
if (pvolume_info->noperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
if (pvolume_info->setuids)
/* check if a whole path (including prepath) is not remote */
if (!rc && cifs_sb->prepathlen && tcon) {
/* build_path_to_root works only when we have a valid tcon */
- full_path = cifs_build_path_to_root(cifs_sb);
+ full_path = cifs_build_path_to_root(cifs_sb, tcon);
if (full_path == NULL) {
rc = -ENOMEM;
goto mount_fail_check;
}
rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
- if (rc != -EREMOTE) {
+ if (rc != 0 && rc != -EREMOTE) {
kfree(full_path);
goto mount_fail_check;
}
/* Search for server name delimiter */
sep = memchr(hostname, '\\', len);
if (sep)
- len = sep - unc;
+ len = sep - hostname;
else
cFYI(1, "%s: probably server name is whole unc: %s",
__func__, unc);
return total_written;
}
-#ifdef CONFIG_CIFS_EXPERIMENTAL
struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
bool fsuid_only)
{
spin_unlock(&cifs_file_list_lock);
return NULL;
}
-#endif
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
bool fsuid_only)
void cifs_oplock_break_put(struct cifsFileInfo *cfile)
{
+ struct super_block *sb = cfile->dentry->d_sb;
+
cifsFileInfo_put(cfile);
- cifs_sb_deactive(cfile->dentry->d_sb);
+ cifs_sb_deactive(sb);
}
const struct address_space_operations cifs_addr_ops = {
* fs/cifs/fscache.c - CIFS filesystem cache interface
*
* Copyright (c) 2010 Novell, Inc.
- * Author(s): Suresh Jayaraman (sjayaraman@suse.de>
+ * Author(s): Suresh Jayaraman <sjayaraman@suse.de>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
if (cifsi->fscache)
return;
- cifsi->fscache = fscache_acquire_cookie(tcon->fscache,
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) {
+ cifsi->fscache = fscache_acquire_cookie(tcon->fscache,
&cifs_fscache_inode_object_def, cifsi);
- cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache,
+ cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache,
cifsi->fscache);
+ }
}
void cifs_fscache_release_inode_cookie(struct inode *inode)
{
if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
cifs_fscache_disable_inode_cookie(inode);
- else {
+ else
cifs_fscache_enable_inode_cookie(inode);
- cFYI(1, "CIFS: fscache inode cookie set");
- }
}
void cifs_fscache_reset_inode_cookie(struct inode *inode)
cFYI(1, "cifs_sfu_type failed: %d", tmprc);
}
-#ifdef CONFIG_CIFS_EXPERIMENTAL
+#ifdef CONFIG_CIFS_ACL
/* fill in 0777 bits from ACL */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
- cFYI(1, "Getting mode bits from ACL");
- cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
+ rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path,
+ pfid);
+ if (rc) {
+ cFYI(1, "%s: Getting ACL failed with error: %d",
+ __func__, rc);
+ goto cgii_exit;
+ }
}
-#endif
+#endif /* CONFIG_CIFS_ACL */
/* fill in remaining high mode bits e.g. SUID, VTX */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
.lookup = cifs_lookup,
};
-char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
+char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
+ struct cifsTconInfo *tcon)
{
int pplen = cifs_sb->prepathlen;
int dfsplen;
char *full_path = NULL;
- struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
/* if no prefix path, simply set path to the root of share to "" */
if (pplen == 0) {
char *full_path;
struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
- full_path = cifs_build_path_to_root(cifs_sb);
+ full_path = cifs_build_path_to_root(cifs_sb, tcon);
if (full_path == NULL)
return ERR_PTR(-ENOMEM);
rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
xid, NULL);
- if (!inode)
- return ERR_PTR(rc);
+ if (!inode) {
+ inode = ERR_PTR(rc);
+ goto out;
+ }
#ifdef CONFIG_CIFS_FSCACHE
/* populate tcon->resource_id */
inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid;
} else if (rc) {
- kfree(full_path);
- _FreeXid(xid);
iget_failed(inode);
- return ERR_PTR(rc);
+ inode = ERR_PTR(rc);
}
-
+out:
kfree(full_path);
/* can not call macro FreeXid here since in a void func
* TODO: This is no longer true
cifs_inode_needs_reval(struct inode *inode)
{
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
if (cifs_i->clientCanCacheRead)
return false;
if (cifs_i->time == 0)
return true;
- /* FIXME: the actimeo should be tunable */
- if (time_after_eq(jiffies, cifs_i->time + HZ))
+ if (!time_in_range(jiffies, cifs_i->time,
+ cifs_i->time + cifs_sb->actimeo))
return true;
/* hardlinked files w/ noserverino get "special" treatment */
- if (!(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
S_ISREG(inode->i_mode) && inode->i_nlink != 1)
return true;
return false;
}
-/* check invalid_mapping flag and zap the cache if it's set */
+/*
+ * Zap the cache. Called when invalid_mapping flag is set.
+ */
static void
cifs_invalidate_mapping(struct inode *inode)
{
if (attrs->ia_valid & ATTR_MODE) {
rc = 0;
-#ifdef CONFIG_CIFS_EXPERIMENTAL
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
- rc = mode_to_acl(inode, full_path, mode);
- else
-#endif
+#ifdef CONFIG_CIFS_ACL
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
+ rc = mode_to_cifs_acl(inode, full_path, mode);
+ if (rc) {
+ cFYI(1, "%s: Setting ACL failed with error: %d",
+ __func__, rc);
+ goto cifs_setattr_exit;
+ }
+ } else
+#endif /* CONFIG_CIFS_ACL */
if (((mode & S_IWUGO) == 0) &&
(cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
char *full_path = NULL;
struct cifsFileInfo *cifsFile;
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
- struct tcon_link *tlink;
+ struct tcon_link *tlink = NULL;
struct cifsTconInfo *pTcon;
- tlink = cifs_sb_tlink(cifs_sb);
- if (IS_ERR(tlink))
- return PTR_ERR(tlink);
- pTcon = tlink_tcon(tlink);
-
- if (file->private_data == NULL)
- file->private_data =
- kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
if (file->private_data == NULL) {
- rc = -ENOMEM;
- goto error_exit;
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+
+ cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+ if (cifsFile == NULL) {
+ rc = -ENOMEM;
+ goto error_exit;
+ }
+ file->private_data = cifsFile;
+ cifsFile->tlink = cifs_get_tlink(tlink);
+ pTcon = tlink_tcon(tlink);
+ } else {
+ cifsFile = file->private_data;
+ pTcon = tlink_tcon(cifsFile->tlink);
}
- cifsFile = file->private_data;
cifsFile->invalidHandle = true;
cifsFile->srch_inf.endOfSearch = false;
- cifsFile->tlink = cifs_get_tlink(tlink);
full_path = build_path_from_dentry(file->f_path.dentry);
if (full_path == NULL) {
rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
ino, fattr.cf_dtype);
- /*
- * we can not return filldir errors to the caller since they are
- * "normal" when the stat blocksize is too small - we return remapped
- * error instead
- *
- * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above
- * case already. Why should we be clobbering other errors from it?
- */
- if (rc) {
- cFYI(1, "filldir rc = %d", rc);
- rc = -EOVERFLOW;
- }
dput(tmp_dentry);
return rc;
}
#define MAX_EA_VALUE_SIZE 65535
#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
+#define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
#define CIFS_XATTR_USER_PREFIX "user."
#define CIFS_XATTR_SYSTEM_PREFIX "system."
#define CIFS_XATTR_OS2_PREFIX "os2."
-#define CIFS_XATTR_SECURITY_PREFIX ".security"
+#define CIFS_XATTR_SECURITY_PREFIX "security."
#define CIFS_XATTR_TRUSTED_PREFIX "trusted."
#define XATTR_TRUSTED_PREFIX_LEN 8
#define XATTR_SECURITY_PREFIX_LEN 9
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
-#ifdef CONFIG_CIFS_EXPERIMENTAL
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
- __u16 fid;
- int oplock = 0;
- struct cifs_ntsd *pacl = NULL;
- __u32 buflen = 0;
- if (experimEnabled)
- rc = CIFSSMBOpen(xid, pTcon, full_path,
- FILE_OPEN, GENERIC_READ, 0, &fid,
- &oplock, NULL, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- /* else rc is EOPNOTSUPP from above */
-
- if (rc == 0) {
- rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, &pacl,
- &buflen);
- CIFSSMBClose(xid, pTcon, fid);
- }
- }
-#endif /* EXPERIMENTAL */
#else
- cFYI(1, "query POSIX ACL not supported yet");
+ cFYI(1, "Query POSIX ACL not supported yet");
#endif /* CONFIG_CIFS_POSIX */
} else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
#else
- cFYI(1, "query POSIX default ACL not supported yet");
-#endif
+ cFYI(1, "Query POSIX default ACL not supported yet");
+#endif /* CONFIG_CIFS_POSIX */
+ } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
+ strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
+#ifdef CONFIG_CIFS_ACL
+ u32 acllen;
+ struct cifs_ntsd *pacl;
+
+ pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
+ full_path, &acllen);
+ if (IS_ERR(pacl)) {
+ rc = PTR_ERR(pacl);
+ cERROR(1, "%s: error %zd getting sec desc",
+ __func__, rc);
+ } else {
+ if (ea_value) {
+ if (acllen > buf_size)
+ acllen = -ERANGE;
+ else
+ memcpy(ea_value, pacl, acllen);
+ }
+ rc = acllen;
+ kfree(pacl);
+ }
+#else
+ cFYI(1, "Query CIFS ACL not supported yet");
+#endif /* CONFIG_CIFS_ACL */
} else if (strncmp(ea_name,
CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
cFYI(1, "Trusted xattr namespace not supported yet");
argv++;
if (i++ >= max)
return -E2BIG;
+
+ if (fatal_signal_pending(current))
+ return -ERESTARTNOHAND;
+ cond_resched();
}
}
return i;
while (len > 0) {
int offset, bytes_to_copy;
+ if (fatal_signal_pending(current)) {
+ ret = -ERESTARTNOHAND;
+ goto out;
+ }
+ cond_resched();
+
offset = pos % PAGE_SIZE;
if (offset == 0)
offset = PAGE_SIZE;
if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
struct page *page;
-#ifdef CONFIG_STACK_GROWSUP
- ret = expand_stack_downwards(bprm->vma, pos);
- if (ret < 0) {
- /* We've exceed the stack rlimit. */
- ret = -E2BIG;
- goto out;
- }
-#endif
- ret = get_user_pages(current, bprm->mm, pos,
- 1, 1, 1, &page, NULL);
- if (ret <= 0) {
- /* We've exceed the stack rlimit. */
+ page = get_arg_page(bprm, pos, 1);
+ if (!page) {
ret = -E2BIG;
goto out;
}
return retval;
out:
- if (bprm->mm)
+ if (bprm->mm) {
+ acct_arg_size(bprm, 0);
mmput(bprm->mm);
+ }
out_file:
if (bprm->file) {
#include <linux/compiler.h>
#include <linux/sched.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/ioctl.h>
#include <linux/if.h>
#include <linux/if_bridge.h>
#include <linux/key.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/file.h>
#include <linux/crypto.h>
#include "ecryptfs_kernel.h"
#ifdef CONFIG_MMU
-static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
+{
+ struct mm_struct *mm = current->mm;
+ long diff = (long)(pages - bprm->vma_pages);
+
+ if (!mm || !diff)
+ return;
+
+ bprm->vma_pages = pages;
+
+#ifdef SPLIT_RSS_COUNTING
+ add_mm_counter(mm, MM_ANONPAGES, diff);
+#else
+ spin_lock(&mm->page_table_lock);
+ add_mm_counter(mm, MM_ANONPAGES, diff);
+ spin_unlock(&mm->page_table_lock);
+#endif
+}
+
+struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
int write)
{
struct page *page;
unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
struct rlimit *rlim;
+ acct_arg_size(bprm, size / PAGE_SIZE);
+
/*
* We've historically supported up to 32 pages (ARG_MAX)
* of argument strings even with small stacks
vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP;
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
INIT_LIST_HEAD(&vma->anon_vma_chain);
+
+ err = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1);
+ if (err)
+ goto err;
+
err = insert_vm_struct(mm, vma);
if (err)
goto err;
#else
-static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
+{
+}
+
+struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
int write)
{
struct page *page;
/*
* Release all of the old mmap stuff
*/
+ acct_arg_size(bprm, 0);
retval = exec_mmap(bprm->mm);
if (retval)
goto out;
return retval;
out:
- if (bprm->mm)
- mmput (bprm->mm);
+ if (bprm->mm) {
+ acct_arg_size(bprm, 0);
+ mmput(bprm->mm);
+ }
out_file:
if (bprm->file) {
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/parser.h>
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/exportfs.h>
#include <linux/vfs.h>
#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */
#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */
#define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */
+#define EXT4_MOUNT_MBLK_IO_SUBMIT 0x4000000 /* multi-block io submits */
#define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */
#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
#define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */
*/
if (unlikely(journal_data && PageChecked(page)))
err = __ext4_journalled_writepage(page, len);
- else
+ else if (test_opt(inode->i_sb, MBLK_IO_SUBMIT))
err = ext4_bio_write_page(&io_submit, page,
len, mpd->wbc);
+ else
+ err = block_write_full_page(page,
+ noalloc_get_block_write, mpd->wbc);
if (!err)
mpd->pages_written++;
return err;
}
+ case FITRIM:
+ {
+ struct super_block *sb = inode->i_sb;
+ struct fstrim_range range;
+ int ret = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&range, (struct fstrim_range *)arg,
+ sizeof(range)))
+ return -EFAULT;
+
+ ret = ext4_trim_fs(sb, &range);
+ if (ret < 0)
+ return ret;
+
+ if (copy_to_user((struct fstrim_range *)arg, &range,
+ sizeof(range)))
+ return -EFAULT;
+
+ return 0;
+ }
+
default:
return -ENOTTY;
}
if (namelen > EXT4_NAME_LEN)
return NULL;
if ((namelen <= 2) && (name[0] == '.') &&
- (name[1] == '.' || name[1] == '0')) {
+ (name[1] == '.' || name[1] == '\0')) {
/*
* "." or ".." will only be in the first block
* NFS may look up ".."; "." should be handled by the VFS
} while (bh != head);
}
- put_io_page(io_end->pages[i]);
-
/*
* If this is a partial write which happened to make
* all buffers uptodate then we can optimize away a
*/
if (!partial_write)
SetPageUptodate(page);
+
+ put_io_page(io_end->pages[i]);
}
io_end->num_io_pages = 0;
inode = io_end->inode;
!(def_mount_opts & EXT4_DEFM_NODELALLOC))
seq_puts(seq, ",nodelalloc");
+ if (test_opt(sb, MBLK_IO_SUBMIT))
+ seq_puts(seq, ",mblk_io_submit");
if (sbi->s_stripe)
seq_printf(seq, ",stripe=%lu", sbi->s_stripe);
/*
.quota_write = ext4_quota_write,
#endif
.bdev_try_to_free_page = bdev_try_to_free_page,
- .trim_fs = ext4_trim_fs
};
static const struct super_operations ext4_nojournal_sops = {
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err,
Opt_resize, Opt_usrquota, Opt_grpquota, Opt_i_version,
- Opt_stripe, Opt_delalloc, Opt_nodelalloc,
- Opt_block_validity, Opt_noblock_validity,
+ Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
+ Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
Opt_inode_readahead_blks, Opt_journal_ioprio,
Opt_dioread_nolock, Opt_dioread_lock,
Opt_discard, Opt_nodiscard,
{Opt_resize, "resize"},
{Opt_delalloc, "delalloc"},
{Opt_nodelalloc, "nodelalloc"},
+ {Opt_mblk_io_submit, "mblk_io_submit"},
+ {Opt_nomblk_io_submit, "nomblk_io_submit"},
{Opt_block_validity, "block_validity"},
{Opt_noblock_validity, "noblock_validity"},
{Opt_inode_readahead_blks, "inode_readahead_blks=%u"},
case Opt_nodelalloc:
clear_opt(sbi->s_mount_opt, DELALLOC);
break;
+ case Opt_mblk_io_submit:
+ set_opt(sbi->s_mount_opt, MBLK_IO_SUBMIT);
+ break;
+ case Opt_nomblk_io_submit:
+ clear_opt(sbi->s_mount_opt, MBLK_IO_SUBMIT);
+ break;
case Opt_stripe:
if (match_int(&args[0], &option))
return 0;
struct ext4_li_request *elr;
mutex_lock(&ext4_li_info->li_list_mtx);
- if (list_empty(&ext4_li_info->li_request_list))
- return;
-
list_for_each_safe(pos, n, &ext4_li_info->li_request_list) {
elr = list_entry(pos, struct ext4_li_request,
lr_request);
* Test whether we have more sectors than will fit in sector_t,
* and whether the max offset is addressable by the page cache.
*/
- ret = generic_check_addressable(sb->s_blocksize_bits,
+ err = generic_check_addressable(sb->s_blocksize_bits,
ext4_blocks_count(es));
- if (ret) {
+ if (err) {
ext4_msg(sb, KERN_ERR, "filesystem"
" too large to mount safely on this system");
if (sizeof(sector_t) < 8)
ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled");
+ ret = err;
goto failed_mount;
}
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/module.h>
+#include <linux/compat.h>
static const struct file_operations fuse_direct_io_file_operations;
void fuse_finish_open(struct inode *inode, struct file *file)
{
struct fuse_file *ff = file->private_data;
+ struct fuse_conn *fc = get_fuse_conn(inode);
if (ff->open_flags & FOPEN_DIRECT_IO)
file->f_op = &fuse_direct_io_file_operations;
invalidate_inode_pages2(inode->i_mapping);
if (ff->open_flags & FOPEN_NONSEEKABLE)
nonseekable_open(inode, file);
+ if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) {
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
+ spin_lock(&fc->lock);
+ fi->attr_version = ++fc->attr_version;
+ i_size_write(inode, 0);
+ spin_unlock(&fc->lock);
+ fuse_invalidate_attr(inode);
+ }
}
int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
return 0;
}
+/*
+ * CUSE servers compiled on 32bit broke on 64bit kernels because the
+ * ABI was defined to be 'struct iovec' which is different on 32bit
+ * and 64bit. Fortunately we can determine which structure the server
+ * used from the size of the reply.
+ */
+static int fuse_copy_ioctl_iovec(struct iovec *dst, void *src,
+ size_t transferred, unsigned count,
+ bool is_compat)
+{
+#ifdef CONFIG_COMPAT
+ if (count * sizeof(struct compat_iovec) == transferred) {
+ struct compat_iovec *ciov = src;
+ unsigned i;
+
+ /*
+ * With this interface a 32bit server cannot support
+ * non-compat (i.e. ones coming from 64bit apps) ioctl
+ * requests
+ */
+ if (!is_compat)
+ return -EINVAL;
+
+ for (i = 0; i < count; i++) {
+ dst[i].iov_base = compat_ptr(ciov[i].iov_base);
+ dst[i].iov_len = ciov[i].iov_len;
+ }
+ return 0;
+ }
+#endif
+
+ if (count * sizeof(struct iovec) != transferred)
+ return -EIO;
+
+ memcpy(dst, src, transferred);
+ return 0;
+}
+
+/* Make sure iov_length() won't overflow */
+static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count)
+{
+ size_t n;
+ u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT;
+
+ for (n = 0; n < count; n++) {
+ if (iov->iov_len > (size_t) max)
+ return -ENOMEM;
+ max -= iov->iov_len;
+ }
+ return 0;
+}
+
/*
* For ioctls, there is no generic way to determine how much memory
* needs to be read and/or written. Furthermore, ioctls are allowed
in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV)
goto out;
- err = -EIO;
- if ((in_iovs + out_iovs) * sizeof(struct iovec) != transferred)
- goto out;
-
- /* okay, copy in iovs and retry */
vaddr = kmap_atomic(pages[0], KM_USER0);
- memcpy(page_address(iov_page), vaddr, transferred);
+ err = fuse_copy_ioctl_iovec(page_address(iov_page), vaddr,
+ transferred, in_iovs + out_iovs,
+ (flags & FUSE_IOCTL_COMPAT) != 0);
kunmap_atomic(vaddr, KM_USER0);
+ if (err)
+ goto out;
in_iov = page_address(iov_page);
out_iov = in_iov + in_iovs;
+ err = fuse_verify_ioctl_iov(in_iov, in_iovs);
+ if (err)
+ goto out;
+
+ err = fuse_verify_ioctl_iov(out_iov, out_iovs);
+ if (err)
+ goto out;
+
goto retry;
}
struct fs_disk_quota *fdq)
{
struct inode *inode = &ip->i_inode;
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
struct address_space *mapping = inode->i_mapping;
unsigned long index = loc >> PAGE_CACHE_SHIFT;
unsigned offset = loc & (PAGE_CACHE_SIZE - 1);
qd->qd_qb.qb_value = qp->qu_value;
if (fdq) {
if (fdq->d_fieldmask & FS_DQ_BSOFT) {
- qp->qu_warn = cpu_to_be64(fdq->d_blk_softlimit);
+ qp->qu_warn = cpu_to_be64(fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift);
qd->qd_qb.qb_warn = qp->qu_warn;
}
if (fdq->d_fieldmask & FS_DQ_BHARD) {
- qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit);
+ qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift);
qd->qd_qb.qb_limit = qp->qu_limit;
}
}
fdq->d_version = FS_DQUOT_VERSION;
fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
fdq->d_id = id;
- fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit);
- fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn);
- fdq->d_bcount = be64_to_cpu(qlvb->qb_value);
+ fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
+ fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
+ fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
gfs2_glock_dq_uninit(&q_gh);
out:
/* If nothing has changed, this is a no-op */
if ((fdq->d_fieldmask & FS_DQ_BSOFT) &&
- (fdq->d_blk_softlimit == be64_to_cpu(qd->qd_qb.qb_warn)))
+ ((fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_warn)))
fdq->d_fieldmask ^= FS_DQ_BSOFT;
if ((fdq->d_fieldmask & FS_DQ_BHARD) &&
- (fdq->d_blk_hardlimit == be64_to_cpu(qd->qd_qb.qb_limit)))
+ ((fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_limit)))
fdq->d_fieldmask ^= FS_DQ_BHARD;
if (fdq->d_fieldmask == 0)
goto out_i;
#include <linux/syscalls.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/capability.h>
#include <linux/file.h>
#include <linux/fs.h>
return thaw_super(sb);
}
-static int ioctl_fstrim(struct file *filp, void __user *argp)
-{
- struct super_block *sb = filp->f_path.dentry->d_inode->i_sb;
- struct fstrim_range range;
- int ret = 0;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- /* If filesystem doesn't support trim feature, return. */
- if (sb->s_op->trim_fs == NULL)
- return -EOPNOTSUPP;
-
- /* If a blockdevice-backed filesystem isn't specified, return EINVAL. */
- if (sb->s_bdev == NULL)
- return -EINVAL;
-
- if (argp == NULL) {
- range.start = 0;
- range.len = ULLONG_MAX;
- range.minlen = 0;
- } else if (copy_from_user(&range, argp, sizeof(range)))
- return -EFAULT;
-
- ret = sb->s_op->trim_fs(sb, &range);
- if (ret < 0)
- return ret;
-
- if ((argp != NULL) &&
- (copy_to_user(argp, &range, sizeof(range))))
- return -EFAULT;
-
- return 0;
-}
-
/*
* When you add any new common ioctls to the switches above and below
* please update compat_sys_ioctl() too.
error = ioctl_fsthaw(filp);
break;
- case FITRIM:
- error = ioctl_fstrim(filp, argp);
- break;
-
case FS_IOC_FIEMAP:
return ioctl_fiemap(filp, arg);
/* journal descriptor can store up to n blocks -bzzz */
journal->j_blocksize = blocksize;
+ journal->j_dev = bdev;
+ journal->j_fs_dev = fs_dev;
+ journal->j_blk_offset = start;
+ journal->j_maxlen = len;
+ bdevname(journal->j_dev, journal->j_devname);
+ p = journal->j_devname;
+ while ((p = strchr(p, '/')))
+ *p = '!';
jbd2_stats_proc_init(journal);
n = journal->j_blocksize / sizeof(journal_block_tag_t);
journal->j_wbufsize = n;
__func__);
goto out_err;
}
- journal->j_dev = bdev;
- journal->j_fs_dev = fs_dev;
- journal->j_blk_offset = start;
- journal->j_maxlen = len;
- bdevname(journal->j_dev, journal->j_devname);
- p = journal->j_devname;
- while ((p = strchr(p, '/')))
- *p = '!';
bh = __getblk(journal->j_dev, start, journal->j_blocksize);
if (!bh) {
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#define NLMDBG_FACILITY NLMDBG_CLIENT
*/
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/errno.h>
continue;
if (host->h_server != ni->server)
continue;
- if (ni->server &&
+ if (ni->server && ni->src_len != 0 &&
!rpc_cmp_addr(nlm_srcaddr(host), ni->src_sap))
continue;
host->h_addrlen = ni->salen;
rpc_set_port(nlm_addr(host), 0);
memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len);
+ host->h_srcaddrlen = ni->src_len;
host->h_version = ni->version;
host->h_proto = ni->protocol;
host->h_rpcclnt = NULL;
const char *hostname,
int noresvport)
{
- const struct sockaddr source = {
- .sa_family = AF_UNSPEC,
- };
struct nlm_lookup_host_info ni = {
.server = 0,
.sap = sap,
.version = version,
.hostname = hostname,
.hostname_len = strlen(hostname),
- .src_sap = &source,
- .src_len = sizeof(source),
.noresvport = noresvport,
};
.protocol = host->h_proto,
.address = nlm_addr(host),
.addrsize = host->h_addrlen,
- .saddress = nlm_srcaddr(host),
.timeout = &timeparms,
.servername = host->h_name,
.program = &nlm_program,
args.flags |= RPC_CLNT_CREATE_HARDRTRY;
if (host->h_noresvport)
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
+ if (host->h_srcaddrlen)
+ args.saddress = nlm_srcaddr(host);
clnt = rpc_create(&args);
if (!IS_ERR(clnt))
#include <linux/types.h>
#include <linux/time.h>
-#include <linux/smp_lock.h>
#include <linux/lockd/lockd.h>
#include <linux/lockd/share.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/lockd/nlm.h>
#include <linux/types.h>
#include <linux/time.h>
-#include <linux/smp_lock.h>
#include <linux/lockd/lockd.h>
#include <linux/lockd/share.h>
#include <linux/module.h>
#include <linux/security.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/time.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/percpu.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/acct.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
-#include <linux/smp_lock.h>
#include <linux/ncp_fs.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/ncp_fs.h>
#include "ncplib_kernel.h"
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/vfs.h>
#include <linux/mount.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/slab.h>
#include <linux/highuid.h>
-#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/ip.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/nfs_fs.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/nfs4.h>
#include <linux/mount.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
+#include <linux/kmemleak.h>
#include "delegation.h"
#include "iostat.h"
struct inode *, struct dentry *);
static int nfs_fsync_dir(struct file *, int);
static loff_t nfs_llseek_dir(struct file *, loff_t, int);
-static int nfs_readdir_clear_array(struct page*, gfp_t);
+static void nfs_readdir_clear_array(struct page*);
const struct file_operations nfs_dir_operations = {
.llseek = nfs_llseek_dir,
.setattr = nfs_setattr,
};
-const struct address_space_operations nfs_dir_addr_space_ops = {
- .releasepage = nfs_readdir_clear_array,
+const struct address_space_operations nfs_dir_aops = {
+ .freepage = nfs_readdir_clear_array,
};
#ifdef CONFIG_NFS_V3
u64 cookie;
u64 ino;
struct qstr string;
+ unsigned char d_type;
};
struct nfs_cache_array {
struct nfs_cache_array_entry array[0];
};
-#define MAX_READDIR_ARRAY ((PAGE_SIZE - sizeof(struct nfs_cache_array)) / sizeof(struct nfs_cache_array_entry))
-
typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
typedef struct {
struct file *file;
struct page *page;
unsigned long page_index;
u64 *dir_cookie;
+ u64 last_cookie;
loff_t current_index;
decode_dirent_t decode;
static
struct nfs_cache_array *nfs_readdir_get_array(struct page *page)
{
+ void *ptr;
if (page == NULL)
return ERR_PTR(-EIO);
- return (struct nfs_cache_array *)kmap(page);
+ ptr = kmap(page);
+ if (ptr == NULL)
+ return ERR_PTR(-ENOMEM);
+ return ptr;
}
static
* we are freeing strings created by nfs_add_to_readdir_array()
*/
static
-int nfs_readdir_clear_array(struct page *page, gfp_t mask)
+void nfs_readdir_clear_array(struct page *page)
{
- struct nfs_cache_array *array = nfs_readdir_get_array(page);
+ struct nfs_cache_array *array;
int i;
+
+ array = kmap_atomic(page, KM_USER0);
for (i = 0; i < array->size; i++)
kfree(array->array[i].string.name);
- nfs_readdir_release_array(page);
- return 0;
+ kunmap_atomic(array, KM_USER0);
}
/*
string->name = kmemdup(name, len, GFP_KERNEL);
if (string->name == NULL)
return -ENOMEM;
+ /*
+ * Avoid a kmemleak false positive. The pointer to the name is stored
+ * in a page cache page which kmemleak does not scan.
+ */
+ kmemleak_not_leak(string->name);
string->hash = full_name_hash(name, len);
return 0;
}
if (IS_ERR(array))
return PTR_ERR(array);
- ret = -EIO;
- if (array->size >= MAX_READDIR_ARRAY)
- goto out;
cache_entry = &array->array[array->size];
+
+ /* Check that this entry lies within the page bounds */
+ ret = -ENOSPC;
+ if ((char *)&cache_entry[1] - (char *)page_address(page) > PAGE_SIZE)
+ goto out;
+
cache_entry->cookie = entry->prev_cookie;
cache_entry->ino = entry->ino;
+ cache_entry->d_type = entry->d_type;
ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len);
if (ret)
goto out;
array->last_cookie = entry->cookie;
- if (entry->eof == 1)
- array->eof_index = array->size;
array->size++;
+ if (entry->eof != 0)
+ array->eof_index = array->size;
out:
nfs_readdir_release_array(page);
return ret;
if (diff < 0)
goto out_eof;
if (diff >= array->size) {
- if (array->eof_index > 0)
+ if (array->eof_index >= 0)
goto out_eof;
desc->current_index += array->size;
return -EAGAIN;
index = (unsigned int)diff;
*desc->dir_cookie = array->array[index].cookie;
desc->cache_entry_index = index;
- if (index == array->eof_index)
- desc->eof = 1;
return 0;
out_eof:
desc->eof = 1;
int status = -EAGAIN;
for (i = 0; i < array->size; i++) {
- if (i == array->eof_index) {
- desc->eof = 1;
- status = -EBADCOOKIE;
- }
if (array->array[i].cookie == *desc->dir_cookie) {
desc->cache_entry_index = i;
- status = 0;
- break;
+ return 0;
}
}
-
+ if (array->eof_index >= 0) {
+ status = -EBADCOOKIE;
+ if (*desc->dir_cookie == array->last_cookie)
+ desc->eof = 1;
+ }
return status;
}
int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc)
{
struct nfs_cache_array *array;
- int status = -EBADCOOKIE;
-
- if (desc->dir_cookie == NULL)
- goto out;
+ int status;
array = nfs_readdir_get_array(desc->page);
if (IS_ERR(array)) {
else
status = nfs_readdir_search_for_cookie(array, desc);
+ if (status == -EAGAIN) {
+ desc->last_cookie = array->last_cookie;
+ desc->page_index++;
+ }
nfs_readdir_release_array(desc->page);
out:
return status;
static
int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
{
- struct nfs_inode *node;
if (dentry->d_inode == NULL)
goto different;
- node = NFS_I(dentry->d_inode);
- if (node->fh.size != entry->fh->size)
- goto different;
- if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0)
+ if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0)
goto different;
return 1;
different:
/* Perform conversion from xdr to cache array */
static
-void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
+int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
void *xdr_page, struct page *page, unsigned int buflen)
{
struct xdr_stream stream;
struct xdr_buf buf;
__be32 *ptr = xdr_page;
- int status;
struct nfs_cache_array *array;
+ unsigned int count = 0;
+ int status;
buf.head->iov_base = xdr_page;
buf.head->iov_len = buflen;
do {
status = xdr_decode(desc, entry, &stream);
- if (status != 0)
+ if (status != 0) {
+ if (status == -EAGAIN)
+ status = 0;
break;
+ }
- if (nfs_readdir_add_to_array(entry, page) == -1)
- break;
- if (desc->plus == 1)
+ count++;
+
+ if (desc->plus != 0)
nfs_prime_dcache(desc->file->f_path.dentry, entry);
+
+ status = nfs_readdir_add_to_array(entry, page);
+ if (status != 0)
+ break;
} while (!entry->eof);
- if (status == -EBADCOOKIE && entry->eof) {
+ if (count == 0 || (status == -EBADCOOKIE && entry->eof != 0)) {
array = nfs_readdir_get_array(page);
- array->eof_index = array->size - 1;
- status = 0;
- nfs_readdir_release_array(page);
+ if (!IS_ERR(array)) {
+ array->eof_index = array->size;
+ status = 0;
+ nfs_readdir_release_array(page);
+ } else
+ status = PTR_ERR(array);
}
+ return status;
}
static
struct nfs_entry entry;
struct file *file = desc->file;
struct nfs_cache_array *array;
- int status = 0;
+ int status = -ENOMEM;
unsigned int array_size = ARRAY_SIZE(pages);
entry.prev_cookie = 0;
- entry.cookie = *desc->dir_cookie;
+ entry.cookie = desc->last_cookie;
entry.eof = 0;
entry.fh = nfs_alloc_fhandle();
entry.fattr = nfs_alloc_fattr();
goto out;
array = nfs_readdir_get_array(page);
+ if (IS_ERR(array)) {
+ status = PTR_ERR(array);
+ goto out;
+ }
memset(array, 0, sizeof(struct nfs_cache_array));
array->eof_index = -1;
if (!pages_ptr)
goto out_release_array;
do {
+ unsigned int pglen;
status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode);
if (status < 0)
break;
- nfs_readdir_page_filler(desc, &entry, pages_ptr, page, array_size * PAGE_SIZE);
- } while (array->eof_index < 0 && array->size < MAX_READDIR_ARRAY);
+ pglen = status;
+ status = nfs_readdir_page_filler(desc, &entry, pages_ptr, page, pglen);
+ if (status < 0) {
+ if (status == -ENOSPC)
+ status = 0;
+ break;
+ }
+ } while (array->eof_index < 0);
nfs_readdir_free_large_page(pages_ptr, pages, array_size);
out_release_array:
int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
{
struct inode *inode = desc->file->f_path.dentry->d_inode;
+ int ret;
- if (nfs_readdir_xdr_to_array(desc, page, inode) < 0)
+ ret = nfs_readdir_xdr_to_array(desc, page, inode);
+ if (ret < 0)
goto error;
SetPageUptodate(page);
return 0;
error:
unlock_page(page);
- return -EIO;
+ return ret;
}
static
void cache_page_release(nfs_readdir_descriptor_t *desc)
{
+ if (!desc->page->mapping)
+ nfs_readdir_clear_array(desc->page);
page_cache_release(desc->page);
desc->page = NULL;
}
static
struct page *get_cache_page(nfs_readdir_descriptor_t *desc)
{
- struct page *page;
- page = read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping,
+ return read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping,
desc->page_index, (filler_t *)nfs_readdir_filler, desc);
- if (IS_ERR(page))
- desc->eof = 1;
- return page;
}
/*
return PTR_ERR(desc->page);
res = nfs_readdir_search_array(desc);
- if (res == 0)
- return 0;
- cache_page_release(desc);
+ if (res != 0)
+ cache_page_release(desc);
return res;
}
static inline
int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
{
- int res = -EAGAIN;
+ int res;
- while (1) {
- res = find_cache_page(desc);
- if (res != -EAGAIN)
- break;
- desc->page_index++;
+ if (desc->page_index == 0) {
+ desc->current_index = 0;
+ desc->last_cookie = 0;
}
+ do {
+ res = find_cache_page(desc);
+ } while (res == -EAGAIN);
return res;
}
-static inline unsigned int dt_type(struct inode *inode)
-{
- return (inode->i_mode >> 12) & 15;
-}
-
/*
* Once we've found the start of the dirent within a page: fill 'er up...
*/
int i = 0;
int res = 0;
struct nfs_cache_array *array = NULL;
- unsigned int d_type = DT_UNKNOWN;
- struct dentry *dentry = NULL;
array = nfs_readdir_get_array(desc->page);
+ if (IS_ERR(array)) {
+ res = PTR_ERR(array);
+ goto out;
+ }
for (i = desc->cache_entry_index; i < array->size; i++) {
- d_type = DT_UNKNOWN;
+ struct nfs_cache_array_entry *ent;
- res = filldir(dirent, array->array[i].string.name,
- array->array[i].string.len, file->f_pos,
- nfs_compat_user_ino64(array->array[i].ino), d_type);
- if (res < 0)
+ ent = &array->array[i];
+ if (filldir(dirent, ent->string.name, ent->string.len,
+ file->f_pos, nfs_compat_user_ino64(ent->ino),
+ ent->d_type) < 0) {
+ desc->eof = 1;
break;
+ }
file->f_pos++;
- desc->cache_entry_index = i;
if (i < (array->size-1))
*desc->dir_cookie = array->array[i+1].cookie;
else
*desc->dir_cookie = array->last_cookie;
- if (i == array->eof_index) {
- desc->eof = 1;
- break;
- }
}
+ if (array->eof_index >= 0)
+ desc->eof = 1;
nfs_readdir_release_array(desc->page);
+out:
cache_page_release(desc);
- if (dentry != NULL)
- dput(dentry);
dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n",
(unsigned long long)*desc->dir_cookie, res);
return res;
goto out;
}
- if (nfs_readdir_xdr_to_array(desc, page, inode) == -1) {
- status = -EIO;
- goto out_release;
- }
-
desc->page_index = 0;
+ desc->last_cookie = *desc->dir_cookie;
desc->page = page;
+
+ status = nfs_readdir_xdr_to_array(desc, page, inode);
+ if (status < 0)
+ goto out_release;
+
status = nfs_do_filldir(desc, dirent, filldir);
out:
struct inode *inode = dentry->d_inode;
nfs_readdir_descriptor_t my_desc,
*desc = &my_desc;
- int res = -ENOMEM;
+ int res;
dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
if (res < 0)
goto out;
- while (desc->eof != 1) {
+ do {
res = readdir_search_pagecache(desc);
if (res == -EBADCOOKIE) {
+ res = 0;
/* This means either end of directory */
if (*desc->dir_cookie && desc->eof == 0) {
/* Or that the server has 'lost' a cookie */
res = uncached_readdir(desc, dirent, filldir);
- if (res >= 0)
+ if (res == 0)
continue;
}
- res = 0;
break;
}
if (res == -ETOOSMALL && desc->plus) {
break;
res = nfs_do_filldir(desc, dirent, filldir);
- if (res < 0) {
- res = 0;
+ if (res < 0)
break;
- }
- }
+ } while (!desc->eof);
out:
nfs_unblock_sillyrename(dentry);
if (res > 0)
res = NULL;
goto out;
/* This turned out not to be a regular file */
- case -EISDIR:
case -ENOTDIR:
goto no_open;
case -ELOOP:
if (!(nd->intent.open.flags & O_NOFOLLOW))
goto no_open;
+ /* case -EISDIR: */
/* case -EINVAL: */
default:
res = ERR_CAST(inode);
goto out;
nfs_alloc_commit_data(dreq);
- if (dreq->commit_data == NULL || count < wsize)
+ if (dreq->commit_data == NULL || count <= wsize)
sync = NFS_FILE_SYNC;
dreq->inode = inode;
{
struct inode *inode = filp->f_mapping->host;
int status = 0;
+ unsigned int saved_type = fl->fl_type;
/* Try local locking first */
posix_test_lock(filp, fl);
/* found a conflict */
goto out;
}
+ fl->fl_type = saved_type;
if (nfs_have_delegation(inode, FMODE_READ))
goto out_noconflict;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
inode->i_fop = &nfs_dir_operations;
+ inode->i_data.a_ops = &nfs_dir_aops;
if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS))
set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
/* Deal with crossing mountpoints */
return 0;
}
+/*
+ * Convert a umode to a dirent->d_type
+ */
+static inline
+unsigned char nfs_umode_to_dtype(umode_t mode)
+{
+ return (mode >> 12) & 15;
+}
+
/*
* Determine the number of pages in an array of length 'len' and
* with a base offset of 'base'
static struct rpc_version mnt_version1 = {
.number = 1,
- .nrprocs = 2,
+ .nrprocs = ARRAY_SIZE(mnt_procedures),
.procs = mnt_procedures,
};
static struct rpc_version mnt_version3 = {
.number = 3,
- .nrprocs = 2,
+ .nrprocs = ARRAY_SIZE(mnt3_procedures),
.procs = mnt3_procedures,
};
struct page **page;
size_t hdrlen;
unsigned int pglen, recvd;
- int status, nr = 0;
+ int status;
if ((status = ntohl(*p++)))
return nfs_stat_to_errno(status);
if (pglen > recvd)
pglen = recvd;
page = rcvbuf->pages;
- return nr;
+ return pglen;
}
static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
entry->prev_cookie = entry->cookie;
entry->cookie = ntohl(*p++);
+ entry->d_type = DT_UNKNOWN;
+
p = xdr_inline_peek(xdr, 8);
if (p != NULL)
entry->eof = !p[0] && p[1];
out_overflow:
print_overflow_msg(__func__, xdr);
- return ERR_PTR(-EIO);
+ return ERR_PTR(-EAGAIN);
}
/*
struct page **page;
size_t hdrlen;
u32 recvd, pglen;
- int status, nr = 0;
+ int status;
status = ntohl(*p++);
/* Decode post_op_attrs */
pglen = recvd;
page = rcvbuf->pages;
- return nr;
+ return pglen;
}
__be32 *
entry->prev_cookie = entry->cookie;
p = xdr_decode_hyper(p, &entry->cookie);
+ entry->d_type = DT_UNKNOWN;
if (plus) {
entry->fattr->valid = 0;
p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
if (IS_ERR(p))
goto out_overflow_exit;
+ entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
/* In fact, a post_op_fh3: */
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
out_overflow:
print_overflow_msg(__func__, xdr);
out_overflow_exit:
- return ERR_PTR(-EIO);
+ return ERR_PTR(-EAGAIN);
}
/*
nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
res.pgbase = args.pgbase;
status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0);
- if (status == 0)
+ if (status >= 0) {
memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
+ status += args.pgbase;
+ }
nfs_invalidate_atime(dir);
ret = nfs_revalidate_inode(server, inode);
if (ret < 0)
return ret;
+ if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
+ nfs_zap_acl_cache(inode);
ret = nfs4_read_cached_acl(inode, buf, buflen);
if (ret != -ENOENT)
return ret;
nfs_inode_return_delegation(inode);
buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
ret = nfs4_call_sync(server, &msg, &arg, &res, 1);
+ /*
+ * Acl update can result in inode attribute update.
+ * so mark the attribute cache invalid.
+ */
+ spin_lock(&inode->i_lock);
+ NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
+ spin_unlock(&inode->i_lock);
nfs_access_zap_cache(inode);
nfs_zap_acl_cache(inode);
return ret;
xdr_read_pages(xdr, pglen);
- return 0;
+ return pglen;
}
static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
entry->ino = entry->fattr->fileid;
+ entry->d_type = DT_UNKNOWN;
+ if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
+ entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
+
if (verify_attr_len(xdr, p, len) < 0)
goto out_overflow;
out_overflow:
print_overflow_msg(__func__, xdr);
- return ERR_PTR(-EIO);
+ return ERR_PTR(-EAGAIN);
}
/*
{
if (!nfs_lock_request_dontget(req))
return 0;
- if (req->wb_page != NULL)
+ if (test_bit(PG_MAPPED, &req->wb_flags))
radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
return 1;
}
*/
void nfs_clear_page_tag_locked(struct nfs_page *req)
{
- if (req->wb_page != NULL) {
+ if (test_bit(PG_MAPPED, &req->wb_flags)) {
struct inode *inode = req->wb_context->path.dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
- nfs_clear_request(req);
nfs_release_request(req);
}
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
#include <linux/lockd/bind.h>
-#include <linux/smp_lock.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/mnt_namespace.h>
#define NFSDBG_FACILITY NFSDBG_VFS
+#ifdef CONFIG_NFS_V3
+#define NFS_DEFAULT_VERSION 3
+#else
+#define NFS_DEFAULT_VERSION 2
+#endif
+
enum {
/* Mount options that take no arguments */
Opt_soft, Opt_hard,
mnt->flags |= NFS_MOUNT_VER3;
mnt->version = 3;
break;
-#ifdef CONFIG_NFS_V4
case Opt_v4:
mnt->flags &= ~NFS_MOUNT_VER3;
mnt->version = 4;
break;
-#endif
case Opt_udp:
mnt->flags &= ~NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
mnt->flags |= NFS_MOUNT_VER3;
mnt->version = 3;
break;
-#ifdef CONFIG_NFS_V4
case NFS4_VERSION:
mnt->flags &= ~NFS_MOUNT_VER3;
mnt->version = 4;
break;
-#endif
default:
goto out_invalid_value;
}
};
int error = -ENOMEM;
- data = nfs_alloc_parsed_mount_data(3);
+ data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION);
mntfh = nfs_alloc_fhandle();
if (data == NULL || mntfh == NULL)
goto out_free_fh;
if (nfs_have_delegation(inode, FMODE_WRITE))
nfsi->change_attr++;
}
+ set_bit(PG_MAPPED, &req->wb_flags);
SetPagePrivate(req->wb_page);
set_page_private(req->wb_page, (unsigned long)req);
nfsi->npages++;
spin_lock(&inode->i_lock);
set_page_private(req->wb_page, 0);
ClearPagePrivate(req->wb_page);
+ clear_bit(PG_MAPPED, &req->wb_flags);
radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
nfsi->npages--;
if (!nfsi->npages) {
iput(inode);
} else
spin_unlock(&inode->i_lock);
- nfs_clear_request(req);
nfs_release_request(req);
}
err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry,
&fhp->fh_post_attr);
fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version;
- if (err)
+ if (err) {
fhp->fh_post_saved = 0;
- else
+ /* Grab the ctime anyway - set_change_info might use it */
+ fhp->fh_post_attr.ctime = fhp->fh_dentry->d_inode->i_ctime;
+ } else
fhp->fh_post_saved = 1;
}
* Spawn a thread to perform a recall on the delegation represented
* by the lease (file_lock)
*
- * Called from break_lease() with lock_kernel() held.
+ * Called from break_lease() with lock_flocks() held.
* Note: we assume break_lease will only call this *once* for any given
* lease.
*/
list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
spin_unlock(&recall_lock);
- /* only place dl_time is set. protected by lock_kernel*/
+ /* only place dl_time is set. protected by lock_flocks*/
dp->dl_time = get_seconds();
/*
/*
* The file_lock is being reapd.
*
- * Called by locks_free_lock() with lock_kernel() held.
+ * Called by locks_free_lock() with lock_flocks() held.
*/
static
void nfsd_release_deleg_cb(struct file_lock *fl)
}
/*
- * Called from setlease() with lock_kernel() held
+ * Called from setlease() with lock_flocks() held
*/
static
int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
static inline void
set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
{
- BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved);
- cinfo->atomic = 1;
+ BUG_ON(!fhp->fh_pre_saved);
+ cinfo->atomic = fhp->fh_post_saved;
cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode);
- if (cinfo->change_supported) {
- cinfo->before_change = fhp->fh_pre_change;
- cinfo->after_change = fhp->fh_post_change;
- } else {
- cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec;
- cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec;
- cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec;
- cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec;
- }
+
+ cinfo->before_change = fhp->fh_pre_change;
+ cinfo->after_change = fhp->fh_post_change;
+ cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec;
+ cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec;
+ cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec;
+ cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec;
+
}
int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
* the device at this point.
*
* To prevent nilfs_dat_translate() from returning the
- * uncommited block number, this makes a copy of the entry
+ * uncommitted block number, this makes a copy of the entry
* buffer and redirects nilfs_dat_translate() to the copy.
*/
if (!buffer_nilfs_redirected(entry_bh)) {
ino = vdesc->vd_ino;
cno = vdesc->vd_cno;
inode = nilfs_iget_for_gc(sb, ino, cno);
- if (unlikely(inode == NULL)) {
- ret = -ENOMEM;
+ if (IS_ERR(inode)) {
+ ret = PTR_ERR(inode);
goto failed;
}
do {
if (reg == NULL)
return ERR_PTR(-ENOMEM);
- if (strlen(name) > O2HB_MAX_REGION_NAME_LEN)
- return ERR_PTR(-ENAMETOOLONG);
+ if (strlen(name) > O2HB_MAX_REGION_NAME_LEN) {
+ ret = -ENAMETOOLONG;
+ goto free;
+ }
spin_lock(&o2hb_live_lock);
reg->hr_region_num = 0;
O2NM_MAX_REGIONS);
if (reg->hr_region_num >= O2NM_MAX_REGIONS) {
spin_unlock(&o2hb_live_lock);
- return ERR_PTR(-EFBIG);
+ ret = -EFBIG;
+ goto free;
}
set_bit(reg->hr_region_num, o2hb_region_bitmap);
}
ret = o2hb_debug_region_init(reg, o2hb_debug_dir);
if (ret) {
config_item_put(®->hr_item);
- return ERR_PTR(ret);
+ goto free;
}
return ®->hr_item;
+free:
+ kfree(reg);
+ return ERR_PTR(ret);
}
static void o2hb_heartbeat_group_drop_item(struct config_group *group,
out:
iput(inode);
- ocfs2_dentry_attach_gen(dentry);
}
/*
r += O2HB_MAX_REGION_NAME_LEN;
}
- local = kmalloc(sizeof(qr->qr_regions), GFP_KERNEL);
+ local = kmalloc(sizeof(qr->qr_regions), GFP_ATOMIC);
if (!local) {
status = -ENOMEM;
goto bail;
char l_name[OCFS2_LOCK_ID_MAX_LEN];
unsigned int l_ro_holders;
unsigned int l_ex_holders;
- char l_level;
- char l_requested;
- char l_blocking;
+ signed char l_level;
+ signed char l_requested;
+ signed char l_blocking;
/* Data packed - type enum ocfs2_lock_type */
unsigned char l_type;
return c;
}
- return c;
+ return NULL;
}
/*
#include <linux/mount.h>
#include <linux/seq_file.h>
#include <linux/quotaops.h>
-#include <linux/smp_lock.h>
#define MLOG_MASK_PREFIX ML_SUPER
#include <cluster/masklog.h>
return ret;
}
+/*
+ * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same
+ * location, so checking ->i_pipe is not enough to verify that this is a
+ * pipe.
+ */
+struct pipe_inode_info *get_pipe_info(struct file *file)
+{
+ struct inode *i = file->f_path.dentry->d_inode;
+
+ return S_ISFIFO(i->i_mode) ? i->i_pipe : NULL;
+}
+
long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct pipe_inode_info *pipe;
long ret;
- pipe = file->f_path.dentry->d_inode->i_pipe;
+ pipe = get_pipe_info(file);
if (!pipe)
return -EBADF;
if (!tmp)
return -ENOMEM;
- pathname = d_path_with_unreachable(path, tmp, PAGE_SIZE);
+ pathname = d_path(path, tmp, PAGE_SIZE);
len = PTR_ERR(pathname);
if (IS_ERR(pathname))
goto out;
#include <linux/limits.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/sysctl.h>
#include <linux/slab.h>
* skip over unmapped regions.
*/
#define PAGEMAP_WALK_SIZE (PMD_SIZE)
+#define PAGEMAP_WALK_MASK (PMD_MASK)
static ssize_t pagemap_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long end;
pm.pos = 0;
- end = start_vaddr + PAGEMAP_WALK_SIZE;
+ end = (start_vaddr + PAGEMAP_WALK_SIZE) & PAGEMAP_WALK_MASK;
/* overflow ? */
if (end < start_vaddr || end > end_vaddr)
end = end_vaddr;
#include <linux/fcntl.h>
#include <linux/file.h>
#include <linux/uio.h>
-#include <linux/smp_lock.h>
#include <linux/fsnotify.h>
#include <linux/security.h>
#include <linux/module.h>
#include <linux/reiserfs_acl.h>
#include <linux/reiserfs_xattr.h>
#include <linux/exportfs.h>
-#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <asm/uaccess.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/compat.h>
/*
return 0;
}
- /* we need to make sure nobody is changing the file size beneath
- ** us
- */
- reiserfs_mutex_lock_safe(&inode->i_mutex, inode->i_sb);
depth = reiserfs_write_lock_once(inode->i_sb);
+ /* we need to make sure nobody is changing the file size beneath us */
+ reiserfs_mutex_lock_safe(&inode->i_mutex, inode->i_sb);
+
write_from = inode->i_size & (blocksize - 1);
/* if we are on a block boundary, we are already unpacked. */
if (write_from == 0) {
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/workqueue.h>
#include <linux/writeback.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/crc32.h>
-#include <linux/smp_lock.h>
struct file_system_type reiserfs_fs_type;
struct reiserfs_transaction_handle th;
size_t size = reiserfs_xattr_nblocks(inode,
reiserfs_acl_size(clone->a_count));
- reiserfs_write_lock(inode->i_sb);
+ int depth;
+
+ depth = reiserfs_write_lock_once(inode->i_sb);
error = journal_begin(&th, inode->i_sb, size * 2);
if (!error) {
int error2;
if (error2)
error = error2;
}
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, depth);
}
posix_acl_release(clone);
return error;
static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
struct pipe_inode_info *opipe,
size_t len, unsigned int flags);
-/*
- * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same
- * location, so checking ->i_pipe is not enough to verify that this is a
- * pipe.
- */
-static inline struct pipe_inode_info *pipe_info(struct inode *inode)
-{
- if (S_ISFIFO(inode->i_mode))
- return inode->i_pipe;
-
- return NULL;
-}
/*
* Determine where to splice to/from.
loff_t offset, *off;
long ret;
- ipipe = pipe_info(in->f_path.dentry->d_inode);
- opipe = pipe_info(out->f_path.dentry->d_inode);
+ ipipe = get_pipe_info(in);
+ opipe = get_pipe_info(out);
if (ipipe && opipe) {
if (off_in || off_out)
int error;
long ret;
- pipe = pipe_info(file->f_path.dentry->d_inode);
+ pipe = get_pipe_info(file);
if (!pipe)
return -EBADF;
};
long ret;
- pipe = pipe_info(file->f_path.dentry->d_inode);
+ pipe = get_pipe_info(file);
if (!pipe)
return -EBADF;
static long do_tee(struct file *in, struct file *out, size_t len,
unsigned int flags)
{
- struct pipe_inode_info *ipipe = pipe_info(in->f_path.dentry->d_inode);
- struct pipe_inode_info *opipe = pipe_info(out->f_path.dentry->d_inode);
+ struct pipe_inode_info *ipipe = get_pipe_info(in);
+ struct pipe_inode_info *opipe = get_pipe_info(out);
int ret = -EINVAL;
/*
struct xfs_inode *ip = XFS_I(inode);
struct buffer_head *bh, *head;
loff_t offset = page_offset(page);
- ssize_t len = 1 << inode->i_blkbits;
if (!xfs_is_delayed_page(page, IO_DELAY))
goto out_invalidate;
xfs_ilock(ip, XFS_ILOCK_EXCL);
bh = head = page_buffers(page);
do {
- int done;
- xfs_fileoff_t offset_fsb;
- xfs_bmbt_irec_t imap;
- int nimaps = 1;
int error;
- xfs_fsblock_t firstblock;
- xfs_bmap_free_t flist;
+ xfs_fileoff_t start_fsb;
if (!buffer_delay(bh))
goto next_buffer;
- offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
-
- /*
- * Map the range first and check that it is a delalloc extent
- * before trying to unmap the range. Otherwise we will be
- * trying to remove a real extent (which requires a
- * transaction) or a hole, which is probably a bad idea...
- */
- error = xfs_bmapi(NULL, ip, offset_fsb, 1,
- XFS_BMAPI_ENTIRE, NULL, 0, &imap,
- &nimaps, NULL);
-
- if (error) {
- /* something screwed, just bail */
- if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
- xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
- "page discard failed delalloc mapping lookup.");
- }
- break;
- }
- if (!nimaps) {
- /* nothing there */
- goto next_buffer;
- }
- if (imap.br_startblock != DELAYSTARTBLOCK) {
- /* been converted, ignore */
- goto next_buffer;
- }
- WARN_ON(imap.br_blockcount == 0);
-
- /*
- * Note: while we initialise the firstblock/flist pair, they
- * should never be used because blocks should never be
- * allocated or freed for a delalloc extent and hence we need
- * don't cancel or finish them after the xfs_bunmapi() call.
- */
- xfs_bmap_init(&flist, &firstblock);
- error = xfs_bunmapi(NULL, ip, offset_fsb, 1, 0, 1, &firstblock,
- &flist, &done);
-
- ASSERT(!flist.xbf_count && !flist.xbf_first);
+ start_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
+ error = xfs_bmap_punch_delalloc_range(ip, start_fsb, 1);
if (error) {
/* something screwed, just bail */
if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
break;
}
next_buffer:
- offset += len;
+ offset += 1 << inode->i_blkbits;
} while ((bh = bh->b_this_page) != head);
struct inode *inode = mapping->host;
if (to > inode->i_size) {
- struct iattr ia = {
- .ia_valid = ATTR_SIZE | ATTR_FORCE,
- .ia_size = inode->i_size,
- };
- xfs_setattr(XFS_I(inode), &ia, XFS_ATTR_NOLOCK);
+ /*
+ * punch out the delalloc blocks we have already allocated. We
+ * don't call xfs_setattr() to do this as we may be in the
+ * middle of a multi-iovec write and so the vfs inode->i_size
+ * will not match the xfs ip->i_size and so it will zero too
+ * much. Hence we jus truncate the page cache to zero what is
+ * necessary and punch the delalloc blocks directly.
+ */
+ struct xfs_inode *ip = XFS_I(inode);
+ xfs_fileoff_t start_fsb;
+ xfs_fileoff_t end_fsb;
+ int error;
+
+ truncate_pagecache(inode, to, inode->i_size);
+
+ /*
+ * Check if there are any blocks that are outside of i_size
+ * that need to be trimmed back.
+ */
+ start_fsb = XFS_B_TO_FSB(ip->i_mount, inode->i_size) + 1;
+ end_fsb = XFS_B_TO_FSB(ip->i_mount, to);
+ if (end_fsb <= start_fsb)
+ return;
+
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ error = xfs_bmap_punch_delalloc_range(ip, start_fsb,
+ end_fsb - start_fsb);
+ if (error) {
+ /* something screwed, just bail */
+ if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+ xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
+ "xfs_vm_write_failed: unable to clean up ino %lld",
+ ip->i_ino);
+ }
+ }
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
}
spin_unlock(&pag->pag_buf_lock);
xfs_perag_put(pag);
- /* Attempt to get the semaphore without sleeping,
- * if this does not work then we need to drop the
- * spinlock and do a hard attempt on the semaphore.
- */
- if (down_trylock(&bp->b_sema)) {
+ if (xfs_buf_cond_lock(bp)) {
+ /* failed, so wait for the lock if requested. */
if (!(flags & XBF_TRYLOCK)) {
- /* wait for buffer ownership */
xfs_buf_lock(bp);
XFS_STATS_INC(xb_get_locked_waited);
} else {
- /* We asked for a trylock and failed, no need
- * to look at file offset and length here, we
- * know that this buffer at least overlaps our
- * buffer and is locked, therefore our buffer
- * either does not exist, or is this buffer.
- */
xfs_buf_rele(bp);
XFS_STATS_INC(xb_busy_locked);
return NULL;
}
- } else {
- /* trylock worked */
- XB_SET_OWNER(bp);
}
if (bp->b_flags & XBF_STALE) {
*/
/*
- * Locks a buffer object, if it is not already locked.
- * Note that this in no way locks the underlying pages, so it is only
- * useful for synchronizing concurrent use of buffer objects, not for
- * synchronizing independent access to the underlying pages.
+ * Locks a buffer object, if it is not already locked. Note that this in
+ * no way locks the underlying pages, so it is only useful for
+ * synchronizing concurrent use of buffer objects, not for synchronizing
+ * independent access to the underlying pages.
+ *
+ * If we come across a stale, pinned, locked buffer, we know that we are
+ * being asked to lock a buffer that has been reallocated. Because it is
+ * pinned, we know that the log has not been pushed to disk and hence it
+ * will still be locked. Rather than continuing to have trylock attempts
+ * fail until someone else pushes the log, push it ourselves before
+ * returning. This means that the xfsaild will not get stuck trying
+ * to push on stale inode buffers.
*/
int
xfs_buf_cond_lock(
locked = down_trylock(&bp->b_sema) == 0;
if (locked)
XB_SET_OWNER(bp);
+ else if (atomic_read(&bp->b_pin_count) && (bp->b_flags & XBF_STALE))
+ xfs_log_force(bp->b_target->bt_mount, 0);
trace_xfs_buf_cond_lock(bp, _RET_IP_);
return locked ? 0 : -EBUSY;
if (error)
goto out_unlock_iolock;
}
-
- ASSERT(ip->i_delayed_blks == 0);
+ /*
+ * even after flushing the inode, there can still be delalloc
+ * blocks on the inode beyond EOF due to speculative
+ * preallocation. These are not removed until the release
+ * function is called or the inode is inactivated. Hence we
+ * cannot assert here that ip->i_delayed_blks == 0.
+ */
}
lock = xfs_ilock_map_shared(ip);
*count += xfs_bmbt_disk_get_blockcount(frp);
}
}
+
+/*
+ * dead simple method of punching delalyed allocation blocks from a range in
+ * the inode. Walks a block at a time so will be slow, but is only executed in
+ * rare error cases so the overhead is not critical. This will alays punch out
+ * both the start and end blocks, even if the ranges only partially overlap
+ * them, so it is up to the caller to ensure that partial blocks are not
+ * passed in.
+ */
+int
+xfs_bmap_punch_delalloc_range(
+ struct xfs_inode *ip,
+ xfs_fileoff_t start_fsb,
+ xfs_fileoff_t length)
+{
+ xfs_fileoff_t remaining = length;
+ int error = 0;
+
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+
+ do {
+ int done;
+ xfs_bmbt_irec_t imap;
+ int nimaps = 1;
+ xfs_fsblock_t firstblock;
+ xfs_bmap_free_t flist;
+
+ /*
+ * Map the range first and check that it is a delalloc extent
+ * before trying to unmap the range. Otherwise we will be
+ * trying to remove a real extent (which requires a
+ * transaction) or a hole, which is probably a bad idea...
+ */
+ error = xfs_bmapi(NULL, ip, start_fsb, 1,
+ XFS_BMAPI_ENTIRE, NULL, 0, &imap,
+ &nimaps, NULL);
+
+ if (error) {
+ /* something screwed, just bail */
+ if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+ xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
+ "Failed delalloc mapping lookup ino %lld fsb %lld.",
+ ip->i_ino, start_fsb);
+ }
+ break;
+ }
+ if (!nimaps) {
+ /* nothing there */
+ goto next_block;
+ }
+ if (imap.br_startblock != DELAYSTARTBLOCK) {
+ /* been converted, ignore */
+ goto next_block;
+ }
+ WARN_ON(imap.br_blockcount == 0);
+
+ /*
+ * Note: while we initialise the firstblock/flist pair, they
+ * should never be used because blocks should never be
+ * allocated or freed for a delalloc extent and hence we need
+ * don't cancel or finish them after the xfs_bunmapi() call.
+ */
+ xfs_bmap_init(&flist, &firstblock);
+ error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock,
+ &flist, &done);
+ if (error)
+ break;
+
+ ASSERT(!flist.xbf_count && !flist.xbf_first);
+next_block:
+ start_fsb++;
+ remaining--;
+ } while(remaining > 0);
+
+ return error;
+}
int whichfork,
int *count);
+int
+xfs_bmap_punch_delalloc_range(
+ struct xfs_inode *ip,
+ xfs_fileoff_t start_fsb,
+ xfs_fileoff_t length);
#endif /* __KERNEL__ */
#endif /* __XFS_BMAP_H__ */
ip->i_d.di_format = tip->i_d.di_format;
tip->i_d.di_format = tmp;
+ /*
+ * The extents in the source inode could still contain speculative
+ * preallocation beyond EOF (e.g. the file is open but not modified
+ * while defrag is in progress). In that case, we need to copy over the
+ * number of delalloc blocks the data fork in the source inode is
+ * tracking beyond EOF so that when the fork is truncated away when the
+ * temporary inode is unlinked we don't underrun the i_delayed_blks
+ * counter on that inode.
+ */
+ ASSERT(tip->i_delayed_blks == 0);
+ tip->i_delayed_blks = ip->i_delayed_blks;
+ ip->i_delayed_blks = 0;
+
ilf_fields = XFS_ILOG_CORE;
switch(ip->i_d.di_format) {
int xfs_etest[XFS_NUM_INJECT_ERROR];
int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR];
char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR];
+int xfs_error_test_active;
int
xfs_error_test(int error_tag, int *fsidp, char *expression,
len = strlen(mp->m_fsname);
xfs_etest_fsname[i] = kmem_alloc(len + 1, KM_SLEEP);
strcpy(xfs_etest_fsname[i], mp->m_fsname);
+ xfs_error_test_active++;
return 0;
}
}
xfs_etest_fsid[i] = 0LL;
kmem_free(xfs_etest_fsname[i]);
xfs_etest_fsname[i] = NULL;
+ xfs_error_test_active--;
}
}
#define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT
#ifdef DEBUG
+extern int xfs_error_test_active;
extern int xfs_error_test(int, int *, char *, int, char *, unsigned long);
#define XFS_NUM_INJECT_ERROR 10
#define XFS_TEST_ERROR(expr, mp, tag, rf) \
- ((expr) || \
+ ((expr) || (xfs_error_test_active && \
xfs_error_test((tag), (mp)->m_fixedfsid, "expr", __LINE__, __FILE__, \
- (rf)))
+ (rf))))
extern int xfs_errortag_add(int error_tag, xfs_mount_t *mp);
extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud);
}
/*
- * This is called to find out where the oldest active copy of the
- * inode log item in the on disk log resides now that the last log
- * write of it completed at the given lsn. Since we always re-log
- * all dirty data in an inode, the latest copy in the on disk log
- * is the only one that matters. Therefore, simply return the
- * given lsn.
+ * This is called to find out where the oldest active copy of the inode log
+ * item in the on disk log resides now that the last log write of it completed
+ * at the given lsn. Since we always re-log all dirty data in an inode, the
+ * latest copy in the on disk log is the only one that matters. Therefore,
+ * simply return the given lsn.
+ *
+ * If the inode has been marked stale because the cluster is being freed, we
+ * don't want to (re-)insert this inode into the AIL. There is a race condition
+ * where the cluster buffer may be unpinned before the inode is inserted into
+ * the AIL during transaction committed processing. If the buffer is unpinned
+ * before the inode item has been committed and inserted, then it is possible
+ * for the buffer to be written and IO completions before the inode is inserted
+ * into the AIL. In that case, we'd be inserting a clean, stale inode into the
+ * AIL which will never get removed. It will, however, get reclaimed which
+ * triggers an assert in xfs_inode_free() complaining about freein an inode
+ * still in the AIL.
+ *
+ * To avoid this, return a lower LSN than the one passed in so that the
+ * transaction committed code will not move the inode forward in the AIL but
+ * will still unpin it properly.
*/
STATIC xfs_lsn_t
xfs_inode_item_committed(
struct xfs_log_item *lip,
xfs_lsn_t lsn)
{
+ struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+ struct xfs_inode *ip = iip->ili_inode;
+
+ if (xfs_iflags_test(ip, XFS_ISTALE))
+ return lsn - 1;
return lsn;
}
* it and some incremental backup programs won't work without it.
*/
xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG);
+ xfs_trans_log_inode(tp, src_ip, XFS_ILOG_CORE);
/*
* Adjust the link count on src_dp. This is necessary when
#ifndef __ACPI_VIDEO_H
#define __ACPI_VIDEO_H
+#include <linux/errno.h> /* for ENODEV */
+
+struct acpi_device;
+
#define ACPI_VIDEO_DISPLAY_CRT 1
#define ACPI_VIDEO_DISPLAY_TV 2
#define ACPI_VIDEO_DISPLAY_DVI 3
#endif
#endif
-
#define I915_PARAM_HAS_EXECBUF2 9
#define I915_PARAM_HAS_BSD 10
#define I915_PARAM_HAS_BLT 11
+#define I915_PARAM_HAS_RELAXED_FENCING 12
+#define I915_PARAM_HAS_COHERENT_RINGS 13
typedef struct drm_i915_getparam {
int param;
#define NOUVEAU_GETPARAM_VM_VRAM_BASE 12
#define NOUVEAU_GETPARAM_GRAPH_UNITS 13
#define NOUVEAU_GETPARAM_PTIMER_TIME 14
+#define NOUVEAU_GETPARAM_HAS_BO_USAGE 15
struct drm_nouveau_getparam {
uint64_t param;
uint64_t value;
#define NOUVEAU_GEM_DOMAIN_GART (1 << 2)
#define NOUVEAU_GEM_DOMAIN_MAPPABLE (1 << 3)
+#define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00
+#define NOUVEAU_GEM_TILE_16BPP 0x00000001
+#define NOUVEAU_GEM_TILE_32BPP 0x00000002
+#define NOUVEAU_GEM_TILE_ZETA 0x00000004
+#define NOUVEAU_GEM_TILE_NONCONTIG 0x00000008
+
struct drm_nouveau_gem_info {
uint32_t handle;
uint32_t domain;
extern int acpi_blacklisted(void);
extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
-extern int acpi_osi_setup(char *str);
+extern void acpi_osi_setup(char *str);
#ifdef CONFIG_ACPI_NUMA
int acpi_get_pxm(acpi_handle handle);
#define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb))
-struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
- int number,unsigned long *flags); /* number == -1: pick first available */
+struct atm_dev *atm_dev_register(const char *type, struct device *parent,
+ const struct atmdev_ops *ops,
+ int number, /* -1 == pick first available */
+ unsigned long *flags);
struct atm_dev *atm_dev_lookup(int number);
void atm_dev_deregister(struct atm_dev *dev);
char buf[BINPRM_BUF_SIZE];
#ifdef CONFIG_MMU
struct vm_area_struct *vma;
+ unsigned long vma_pages;
#else
# define MAX_ARG_PAGES 32
struct page *page[MAX_ARG_PAGES];
unsigned long loader, exec;
};
+extern void acct_arg_size(struct linux_binprm *bprm, unsigned long pages);
+extern struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ int write);
+
#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
#define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT)
extern void ceph_release_page_vector(struct page **pages, int num_pages);
extern struct page **ceph_get_direct_page_vector(const char __user *data,
- int num_pages,
- loff_t off, size_t len);
+ int num_pages);
extern void ceph_put_page_vector(struct page **pages, int num_pages);
extern void ceph_release_page_vector(struct page **pages, int num_pages);
extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
struct ceph_buffer *middle;
struct page **pages; /* data payload. NOT OWNER. */
unsigned nr_pages; /* size of page array */
+ unsigned page_alignment; /* io offset in first page */
struct ceph_pagelist *pagelist; /* instead of pages */
struct list_head list_head;
struct kref kref;
struct ceph_file_layout r_file_layout;
struct ceph_snap_context *r_snapc; /* snap context for writes */
unsigned r_num_pages; /* size of page array (follows) */
+ unsigned r_page_alignment; /* io offset in first page */
struct page **r_pages; /* pages for data payload */
int r_pages_from_pool;
int r_own_pages; /* if true, i own page list */
int do_sync, u32 truncate_seq,
u64 truncate_size,
struct timespec *mtime,
- bool use_mempool, int num_reply);
+ bool use_mempool, int num_reply,
+ int page_align);
static inline void ceph_osdc_get_request(struct ceph_osd_request *req)
{
struct ceph_file_layout *layout,
u64 off, u64 *plen,
u32 truncate_seq, u64 truncate_size,
- struct page **pages, int nr_pages);
+ struct page **pages, int nr_pages,
+ int page_align);
extern int ceph_osdc_writepages(struct ceph_osd_client *osdc,
struct ceph_vino vino,
*
* CPUs are exported via sysfs in the class/cpu/devices/
* directory.
- *
- * Per-cpu interfaces can be implemented using a struct device_interface.
- * See the following for how to do this:
- * - drivers/base/intf.c
- * - Documentation/driver-model/interface.txt
*/
#ifndef _LINUX_CPU_H_
#define _LINUX_CPU_H_
return 0;
}
-#define enable_intr_remapping(mode) (-1)
-#define disable_intr_remapping() (0)
-#define reenable_intr_remapping(mode) (0)
#define intr_remapping_enabled (0)
+
+static inline int enable_intr_remapping(int eim)
+{
+ return -1;
+}
+
+static inline void disable_intr_remapping(void)
+{
+}
+
+static inline int reenable_intr_remapping(int eim)
+{
+ return 0;
+}
#endif
/* Can't use the common MSI interrupt functions
/* drivers/video/fbcmap.c */
extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp);
+extern int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags);
extern void fb_dealloc_cmap(struct fb_cmap *cmap);
extern int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to);
extern int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to);
#define SEEK_MAX SEEK_END
struct fstrim_range {
- uint64_t start;
- uint64_t len;
- uint64_t minlen;
+ __u64 start;
+ __u64 len;
+ __u64 minlen;
};
/* And dynamically-tunable limits and defaults: */
sector_t (*bmap)(struct address_space *, sector_t);
void (*invalidatepage) (struct page *, unsigned long);
int (*releasepage) (struct page *, gfp_t);
+ void (*freepage)(struct page *);
ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
loff_t offset, unsigned long nr_segs);
int (*get_xip_mem)(struct address_space *, pgoff_t, int,
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
#endif
int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
- int (*trim_fs) (struct super_block *, struct fstrim_range *);
};
/*
extern gfp_t gfp_allowed_mask;
-extern void set_gfp_allowed_mask(gfp_t mask);
-extern gfp_t clear_gfp_allowed_mask(gfp_t mask);
+extern void pm_restrict_gfp_mask(void);
+extern void pm_restore_gfp_mask(void);
#endif /* __LINUX_GFP_H */
struct gpio_keys_platform_data {
struct gpio_keys_button *buttons;
int nbuttons;
+ unsigned int poll_interval; /* polling interval in msecs -
+ for polling driver only */
unsigned int rep:1; /* enable input subsystem auto repeat */
int (*enable)(struct device *dev);
void (*disable)(struct device *dev);
#define LINUX_HARDIRQ_H
#include <linux/preempt.h>
-#ifdef CONFIG_PREEMPT
-#include <linux/smp_lock.h>
-#endif
#include <linux/lockdep.h>
#include <linux/ftrace_irq.h>
#include <asm/hardirq.h>
#define in_nmi() (preempt_count() & NMI_MASK)
#if defined(CONFIG_PREEMPT) && defined(CONFIG_BKL)
-# define PREEMPT_INATOMIC_BASE kernel_locked()
+# include <linux/sched.h>
+# define PREEMPT_INATOMIC_BASE (current->lock_depth >= 0)
#else
# define PREEMPT_INATOMIC_BASE 0
#endif
#ifdef CONFIG_HAVE_HW_BREAKPOINT
+extern int __init init_hw_breakpoint(void);
+
static inline void hw_breakpoint_init(struct perf_event_attr *attr)
{
memset(attr, 0, sizeof(*attr));
#else /* !CONFIG_HAVE_HW_BREAKPOINT */
+static inline int __init init_hw_breakpoint(void) { return 0; }
+
static inline struct perf_event *
register_user_hw_breakpoint(struct perf_event_attr *attr,
perf_overflow_handler_t triggered,
__u16 version;
};
+/**
+ * struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls
+ * @value: latest reported value for the axis.
+ * @minimum: specifies minimum value for the axis.
+ * @maximum: specifies maximum value for the axis.
+ * @fuzz: specifies fuzz value that is used to filter noise from
+ * the event stream.
+ * @flat: values that are within this value will be discarded by
+ * joydev interface and reported as 0 instead.
+ * @resolution: specifies resolution for the values reported for
+ * the axis.
+ *
+ * Note that input core does not clamp reported values to the
+ * [minimum, maximum] limits, such task is left to userspace.
+ *
+ * Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in
+ * units per millimeter (units/mm), resolution for rotational axes
+ * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
+ */
struct input_absinfo {
__s32 value;
__s32 minimum;
#define KEY_CAMERA_FOCUS 0x210
#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */
+#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */
+#define KEY_TOUCHPAD_ON 0x213
+#define KEY_TOUCHPAD_OFF 0x214
+
#define BTN_TRIGGER_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0
#define BTN_TRIGGER_HAPPY2 0x2c1
* of tracked contacts
* @mtsize: number of MT slots the device uses
* @slot: MT slot currently being transmitted
- * @absinfo: array of &struct absinfo elements holding information
+ * @absinfo: array of &struct input_absinfo elements holding information
* about absolute axes (current value, min, max, flat, fuzz,
* resolution)
* @key: reflects current state of device's keys/buttons
unsigned long, struct ata_port_operations *);
extern int ata_scsi_detect(struct scsi_host_template *sht);
extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
-extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+extern int ata_scsi_queuecmd(struct Scsi_Host *h, struct scsi_cmnd *cmd);
extern int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *dev,
int cmd, void __user *arg);
extern void ata_sas_port_destroy(struct ata_port *);
struct sockaddr_storage h_addr; /* peer address */
size_t h_addrlen;
struct sockaddr_storage h_srcaddr; /* our address (optional) */
+ size_t h_srcaddrlen;
struct rpc_clnt *h_rpcclnt; /* RPC client to talk to peer */
char *h_name; /* remote hostname */
u32 h_version; /* interface version */
#define MARVELL_PHY_ID_88E1118 0x01410e10
#define MARVELL_PHY_ID_88E1121R 0x01410cb0
#define MARVELL_PHY_ID_88E1145 0x01410cd0
+#define MARVELL_PHY_ID_88E1149R 0x01410e50
#define MARVELL_PHY_ID_88E1240 0x01410e30
#define MARVELL_PHY_ID_88E1318S 0x01410e90
extern void put_page_bootmem(struct page *page);
#endif
+void lock_memory_hotplug(void);
+void unlock_memory_hotplug(void);
+
#else /* ! CONFIG_MEMORY_HOTPLUG */
/*
* Stub functions for when hotplug is off
{
}
+static inline void lock_memory_hotplug(void) {}
+static inline void unlock_memory_hotplug(void) {}
+
#endif /* ! CONFIG_MEMORY_HOTPLUG */
#ifdef CONFIG_MEMORY_HOTREMOVE
#define WM8350_MCLK_SEL_PLL_32K 3
#define WM8350_MCLK_SEL_MCLK 5
-#define WM8350_MCLK_DIR_OUT 0
-#define WM8350_MCLK_DIR_IN 1
-
/* clock divider id's */
#define WM8350_ADC_CLKDIV 0
#define WM8350_DAC_CLKDIV 1
#define WM8994_CONFIGURE_GPIO 0x8000
#define WM8994_DRC_REGS 5
-#define WM8994_EQ_REGS 19
+#define WM8994_EQ_REGS 20
/**
* DRC configurations are specified with a label and a set of register
/* DDR mode at 1.8V */
#define MMC_CAP_1_2V_DDR (1 << 12) /* can support */
/* DDR mode at 1.2V */
+#define MMC_CAP_POWER_OFF_CARD (1 << 13) /* Can power off after boot */
mmc_pm_flag_t pm_caps; /* supported pm features */
#define symbol_put_addr(p) do { } while(0)
#endif /* CONFIG_MODULE_UNLOAD */
-int use_module(struct module *a, struct module *b);
+int ref_module(struct module *a, struct module *b);
/* This is a #define so the string doesn't get put in every .o file */
#define module_name(mod) \
#endif /* CONFIG_NFS_V3 */
extern const struct file_operations nfs_file_operations;
extern const struct address_space_operations nfs_file_aops;
+extern const struct address_space_operations nfs_dir_aops;
static inline struct nfs_open_context *nfs_file_open_context(struct file *filp)
{
return ino;
}
-#define nfs_wait_event(clnt, wq, condition) \
-({ \
- int __retval = wait_event_killable(wq, condition); \
- __retval; \
-})
-
#define NFS_JUKEBOX_RETRY_TIME (5 * HZ)
#endif /* __KERNEL__ */
*/
enum {
PG_BUSY = 0,
+ PG_MAPPED,
PG_CLEAN,
PG_NEED_COMMIT,
PG_NEED_RESCHED,
int eof;
struct nfs_fh * fh;
struct nfs_fattr * fattr;
+ unsigned char d_type;
};
/*
*
* Nodes are exported via driverfs in the class/node/devices/
* directory.
- *
- * Per-node interfaces can be implemented using a struct device_interface.
- * See the following for how to do this:
- * - drivers/base/intf.c
- * - Documentation/driver-model/interface.txt
*/
#ifndef _LINUX_NODE_H_
#define _LINUX_NODE_H_
static inline int TestClearPageCgroup##uname(struct page_cgroup *pc) \
{ return test_and_clear_bit(PCG_##lname, &pc->flags); }
-TESTPCGFLAG(Locked, LOCK)
-
/* Cache flag is set only once (at allocation) */
TESTPCGFLAG(Cache, CACHE)
CLEARPCGFLAG(Cache, CACHE)
bit_spin_unlock(PCG_LOCK, &pc->flags);
}
+static inline int page_is_cgroup_locked(struct page_cgroup *pc)
+{
+ return bit_spin_is_locked(PCG_LOCK, &pc->flags);
+}
+
#else /* CONFIG_CGROUP_MEM_RES_CTLR */
struct page_cgroup;
#define PCI_DEVICE_ID_AFAVLAB_P030 0x2182
#define PCI_SUBDEVICE_ID_AFAVLAB_P061 0x2150
+#define PCI_VENDOR_ID_BCM_GVC 0x14a4
#define PCI_VENDOR_ID_BROADCOM 0x14e4
#define PCI_DEVICE_ID_TIGON3_5752 0x1600
#define PCI_DEVICE_ID_TIGON3_5752M 0x1601
#define PCI_DEVICE_ID_INTEL_MFD_SDIO2 0x0822
#define PCI_DEVICE_ID_INTEL_MFD_EMMC0 0x0823
#define PCI_DEVICE_ID_INTEL_MFD_EMMC1 0x0824
+#define PCI_DEVICE_ID_INTEL_MRST_SD2 0x084F
#define PCI_DEVICE_ID_INTEL_I960 0x0960
#define PCI_DEVICE_ID_INTEL_I960RM 0x0962
#define PCI_DEVICE_ID_INTEL_8257X_SOL 0x1062
int nr_active;
int is_active;
int nr_stat;
+ int rotate_disable;
atomic_t refcount;
struct task_struct *task;
extern const char *perf_pmu_name(void);
extern void __perf_event_task_sched_in(struct task_struct *task);
extern void __perf_event_task_sched_out(struct task_struct *task, struct task_struct *next);
-
-extern atomic_t perf_task_events;
-
-static inline void perf_event_task_sched_in(struct task_struct *task)
-{
- COND_STMT(&perf_task_events, __perf_event_task_sched_in(task));
-}
-
-static inline
-void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next)
-{
- COND_STMT(&perf_task_events, __perf_event_task_sched_out(task, next));
-}
-
extern int perf_event_init_task(struct task_struct *child);
extern void perf_event_exit_task(struct task_struct *child);
extern void perf_event_free_task(struct task_struct *task);
__perf_sw_event(event_id, nr, nmi, regs, addr);
}
+extern atomic_t perf_task_events;
+
+static inline void perf_event_task_sched_in(struct task_struct *task)
+{
+ COND_STMT(&perf_task_events, __perf_event_task_sched_in(task));
+}
+
+static inline
+void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next)
+{
+ perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0);
+
+ COND_STMT(&perf_task_events, __perf_event_task_sched_out(task, next));
+}
+
extern void perf_event_mmap(struct vm_area_struct *vma);
extern struct perf_guest_info_callbacks *perf_guest_cbs;
extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks);
/* for F_SETPIPE_SZ and F_GETPIPE_SZ */
long pipe_fcntl(struct file *, unsigned int, unsigned long arg);
+struct pipe_inode_info *get_pipe_info(struct file *file);
#endif
#include <asm/unaligned.h>
#include <linux/bitops.h>
#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/reiserfs_fs_i.h>
#include <linux/reiserfs_fs_sb.h>
#include <linux/if_link.h>
#include <linux/if_addr.h>
#include <linux/neighbour.h>
-#include <linux/netdevice.h>
/* rtnetlink families. Values up to 127 are reserved for real address
* families, values above 128 may be used arbitrarily.
#ifdef __KERNEL__
#include <linux/mutex.h>
+#include <linux/netdevice.h>
static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
{
* single CPU.
*/
unsigned int cpu_power, cpu_power_orig;
+ unsigned int group_weight;
/*
* The CPUs this group covers.
};
struct clk_ops {
+#ifdef CONFIG_SH_CLK_CPG_LEGACY
void (*init)(struct clk *clk);
+#endif
int (*enable)(struct clk *clk);
void (*disable)(struct clk *clk);
unsigned long (*recalc)(struct clk *clk);
- int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
+ int (*set_rate)(struct clk *clk, unsigned long rate);
int (*set_parent)(struct clk *clk, struct clk *parent);
long (*round_rate)(struct clk *clk, unsigned long rate);
};
void clk_unregister(struct clk *);
void clk_enable_init_clocks(void);
-/**
- * clk_set_rate_ex - set the clock rate for a clock source, with additional parameter
- * @clk: clock source
- * @rate: desired clock rate in Hz
- * @algo_id: algorithm id to be passed down to ops->set_rate
- *
- * Returns success (0) or negative errno.
- */
-int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id);
-
-enum clk_sh_algo_id {
- NO_CHANGE = 0,
-
- IUS_N1_N1,
- IUS_322,
- IUS_522,
- IUS_N11,
-
- SB_N1,
-
- SB3_N1,
- SB3_32,
- SB3_43,
- SB3_54,
-
- BP_N1,
-
- IP_N1,
-};
-
struct clk_div_mult_table {
unsigned int *divisors;
unsigned int nr_divisors;
#ifdef CONFIG_LOCK_KERNEL
#include <linux/sched.h>
-#define kernel_locked() (current->lock_depth >= 0)
-
extern int __lockfunc __reacquire_kernel_lock(void);
extern void __lockfunc __release_kernel_lock(void);
#define lock_kernel()
#define unlock_kernel()
#define cycle_kernel_lock() do { } while(0)
-#define kernel_locked() 1
#endif /* CONFIG_BKL */
#define release_kernel_lock(task) do { } while(0)
LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */
LINUX_MIB_TCPDEFERACCEPTDROP,
LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
+ LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */
__LINUX_MIB_MAX
};
#include <linux/tty_driver.h>
#include <linux/tty_ldisc.h>
#include <linux/mutex.h>
-#include <linux/smp_lock.h>
#include <asm/system.h>
#define TTY_HUPPED 18 /* Post driver->hangup() */
#define TTY_FLUSHING 19 /* Flushing to ldisc in progress */
#define TTY_FLUSHPENDING 20 /* Queued buffer flush pending */
+#define TTY_HUPPING 21 /* ->hangup() in progress */
#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
*
* Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de>
* Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de>
- * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de>
+ * Copyright(C) 2006, Hans J. Koch <hjk@hansjkoch.de>
* Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com>
*
* Userspace IO driver.
int busnum; /* Bus number (in order of reg) */
const char *bus_name; /* stable id (PCI slot_name etc) */
u8 uses_dma; /* Does the host controller use DMA? */
+ u8 uses_pio_for_control; /*
+ * Does the host controller use PIO
+ * for control transfers?
+ */
u8 otg_port; /* 0, or number of OTG/HNP port */
unsigned is_b_host:1; /* true during some HNP roleswitches */
unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */
#ifndef _LINUX_VIDEO_OUTPUT_H
#define _LINUX_VIDEO_OUTPUT_H
#include <linux/device.h>
+#include <linux/err.h>
struct output_device;
struct output_properties {
int (*set_state)(struct output_device *);
struct device dev;
};
#define to_output_device(obj) container_of(obj, struct output_device, dev)
+#if defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE)
struct output_device *video_output_register(const char *name,
struct device *dev,
void *devdata,
struct output_properties *op);
void video_output_unregister(struct output_device *dev);
+#else
+static struct output_device *video_output_register(const char *name,
+ struct device *dev,
+ void *devdata,
+ struct output_properties *op)
+{
+ return ERR_PTR(-ENODEV);
+}
+static void video_output_unregister(struct output_device *dev)
+{
+ return;
+}
+#endif
#endif
struct vm_area_struct; /* vma defining user mapping in mm_types.h */
-extern bool vmap_lazy_unmap;
-
/* bits in flags of vmalloc's vm_struct below */
#define VM_IOREMAP 0x00000001 /* ioremap() and friends */
#define VM_ALLOC 0x00000002 /* vmalloc() */
/* Load an i2c module and return an initialized v4l2_subdev struct.
- Only call request_module if module_name != NULL.
The client_type argument is the name of the chip that's on the adapter. */
struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter,
- const char *module_name, const char *client_type,
+ struct i2c_adapter *adapter, const char *client_type,
int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs);
/* Load an i2c module and return an initialized v4l2_subdev struct.
- Only call request_module if module_name != NULL.
The client_type argument is the name of the chip that's on the adapter. */
static inline struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter,
- const char *module_name, const char *client_type,
+ struct i2c_adapter *adapter, const char *client_type,
u8 addr, const unsigned short *probe_addrs)
{
- return v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, module_name,
- client_type, 0, NULL, addr, probe_addrs);
+ return v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, client_type, 0, NULL,
+ addr, probe_addrs);
}
struct i2c_board_info;
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter, const char *module_name,
- struct i2c_board_info *info, const unsigned short *probe_addrs);
+ struct i2c_adapter *adapter, struct i2c_board_info *info,
+ const unsigned short *probe_addrs);
/* Initialize an v4l2_subdev with data from an i2c_client struct */
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
extern void unix_notinflight(struct file *fp);
extern void unix_gc(void);
extern void wait_for_unix_gc(void);
+extern struct sock *unix_get_socket(struct file *filp);
#define UNIX_HASH_SIZE 256
spinlock_t lock;
unsigned int gc_candidate : 1;
unsigned int gc_maybe_cycle : 1;
+ unsigned char recursion_level;
struct socket_wq peer_wq;
};
#define unix_sk(__sk) ((struct unix_sock *)__sk)
WIPHY_FLAG_4ADDR_AP = BIT(5),
WIPHY_FLAG_4ADDR_STATION = BIT(6),
WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7),
- WIPHY_FLAG_IBSS_RSN = BIT(7),
+ WIPHY_FLAG_IBSS_RSN = BIT(8),
};
struct mac_address {
static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
- unsigned long now = ACCESS_ONCE(jiffies);
+ unsigned long now = jiffies;
if (neigh->used != now)
neigh->used = now;
/* Initialise core socket variables */
extern void sock_init_data(struct socket *sock, struct sock *sk);
+extern void sk_filter_release_rcu(struct rcu_head *rcu);
+
/**
* sk_filter_release - release a socket filter
* @fp: filter to remove
static inline void sk_filter_release(struct sk_filter *fp)
{
if (atomic_dec_and_test(&fp->refcnt))
- kfree(fp);
+ call_rcu_bh(&fp->rcu, sk_filter_release_rcu);
}
static inline void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp)
* @InputRequests: Number of input requests
* @OutputRequests: Number of output requests
* @ControlRequests: Number of control requests
- * @InputMegabytes: Number of received megabytes
- * @OutputMegabytes: Number of transmitted megabytes
+ * @InputBytes: Number of received bytes
+ * @OutputBytes: Number of transmitted bytes
* @VLinkFailureCount: Number of virtual link failures
* @MissDiscAdvCount: Number of missing FIP discovery advertisement
*/
u64 InputRequests;
u64 OutputRequests;
u64 ControlRequests;
- u64 InputMegabytes;
- u64 OutputMegabytes;
+ u64 InputBytes;
+ u64 OutputBytes;
u64 VLinkFailureCount;
u64 MissDiscAdvCount;
};
* struct fc_fcp_pkt - FCP request structure (one for each scsi_cmnd request)
* @lp: The associated local port
* @state: The state of the I/O
- * @tgt_flags: Target's flags
* @ref_cnt: Reference count
* @scsi_pkt_lock: Lock to protect the SCSI packet (must be taken before the
* host_lock if both are to be held at the same time)
/* Housekeeping information */
struct fc_lport *lp;
u16 state;
- u16 tgt_flags;
atomic_t ref_cnt;
spinlock_t scsi_pkt_lock;
/*
* SCSI INTERACTION LAYER
*****************************/
-int fc_queuecommand(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+int fc_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
int fc_eh_abort(struct scsi_cmnd *);
int fc_eh_device_reset(struct scsi_cmnd *);
int fc_eh_host_reset(struct scsi_cmnd *);
* @timer_work: &work_struct for doing keep-alives and resets.
* @recv_work: &work_struct for receiving FIP frames.
* @fip_recv_list: list of received FIP frames.
+ * @flogi_req: clone of FLOGI request sent
* @rnd_state: state for pseudo-random number generator.
* @port_id: proposed or selected local-port ID.
* @user_mfs: configured maximum FC frame size, including FC header.
* @flogi_oxid: exchange ID of most recent fabric login.
+ * @flogi_req_send: send of FLOGI requested
* @flogi_count: number of FLOGI attempts in AUTO mode.
* @map_dest: use the FC_MAP mode for destination MAC addresses.
* @spma: supports SPMA server-provided MACs mode
* @update_mac: LLD-supplied function to handle changes to MAC addresses.
* @get_src_addr: LLD-supplied function to supply a source MAC address.
* @ctlr_mutex: lock protecting this structure.
+ * @ctlr_lock: spinlock covering flogi_req
*
* This structure is used by all FCoE drivers. It contains information
* needed by all FCoE low-level drivers (LLDs) as well as internal state
struct work_struct timer_work;
struct work_struct recv_work;
struct sk_buff_head fip_recv_list;
+ struct sk_buff *flogi_req;
struct rnd_state rnd_state;
u32 port_id;
u16 user_mfs;
u16 flogi_oxid;
+ u8 flogi_req_send;
u8 flogi_count;
u8 map_dest;
u8 spma;
void (*update_mac)(struct fc_lport *, u8 *addr);
u8 * (*get_src_addr)(struct fc_lport *);
struct mutex ctlr_mutex;
+ spinlock_t ctlr_lock;
};
/**
* @fcf_mac: Ethernet address of the FCF
* @vfid: virtual fabric ID
* @pri: selection priority, smaller values are better
+ * @flogi_sent: current FLOGI sent to this FCF
* @flags: flags received from advertisement
* @fka_period: keep-alive period, in jiffies
*
u8 fcf_mac[ETH_ALEN];
u8 pri;
+ u8 flogi_sent;
u16 flags;
u32 fka_period;
u8 fd_flags:1;
extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
-extern int iscsi_queuecommand(struct scsi_cmnd *sc,
- void (*done)(struct scsi_cmnd *));
+extern int iscsi_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *sc);
/*
* iSCSI host helpers.
extern struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *, itt_t);
extern void iscsi_requeue_task(struct iscsi_task *task);
extern void iscsi_put_task(struct iscsi_task *task);
+extern void __iscsi_put_task(struct iscsi_task *task);
extern void __iscsi_get_task(struct iscsi_task *task);
extern void iscsi_complete_scsi_task(struct iscsi_task *task,
uint32_t exp_cmdsn, uint32_t max_cmdsn);
/* The class calls this to send a task for execution. */
int lldd_max_execute_num;
int lldd_queue_size;
+ int strict_wide_ports; /* both sas_addr and attached_sas_addr must match
+ * their siblings when forming wide ports */
/* LLDD calls these to notify the class of an event. */
void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
int sas_phy_enable(struct sas_phy *phy, int enabled);
int sas_phy_reset(struct sas_phy *phy, int hard_reset);
int sas_queue_up(struct sas_task *task);
-extern int sas_queuecommand(struct scsi_cmnd *,
- void (*scsi_done)(struct scsi_cmnd *));
+extern int sas_queuecommand(struct Scsi_Host * ,struct scsi_cmnd *);
extern int sas_target_alloc(struct scsi_target *);
extern int sas_slave_alloc(struct scsi_device *);
extern int sas_slave_configure(struct scsi_device *);
#define PERSISTENT_RESERVE_OUT 0x5f
#define VARIABLE_LENGTH_CMD 0x7f
#define REPORT_LUNS 0xa0
+#define SECURITY_PROTOCOL_IN 0xa2
#define MAINTENANCE_IN 0xa3
#define MAINTENANCE_OUT 0xa4
#define MOVE_MEDIUM 0xa5
#define EXCHANGE_MEDIUM 0xa6
#define READ_12 0xa8
#define WRITE_12 0xaa
+#define READ_MEDIA_SERIAL_NUMBER 0xab
#define WRITE_VERIFY_12 0xae
#define VERIFY_12 0xaf
#define SEARCH_HIGH_12 0xb0
#define SEARCH_EQUAL_12 0xb1
#define SEARCH_LOW_12 0xb2
+#define SECURITY_PROTOCOL_OUT 0xb5
#define READ_ELEMENT_STATUS 0xb8
#define SEND_VOLUME_TAG 0xb6
#define WRITE_LONG_2 0xea
+#define EXTENDED_COPY 0x83
+#define RECEIVE_COPY_RESULTS 0x84
+#define ACCESS_CONTROL_IN 0x86
+#define ACCESS_CONTROL_OUT 0x87
#define READ_16 0x88
#define WRITE_16 0x8a
+#define READ_ATTRIBUTE 0x8c
+#define WRITE_ATTRIBUTE 0x8d
#define VERIFY_16 0x8f
#define WRITE_SAME_16 0x93
#define SERVICE_ACTION_IN 0x9e
/* values for service action in */
#define SAI_READ_CAPACITY_16 0x10
#define SAI_GET_LBA_STATUS 0x12
+/* values for VARIABLE_LENGTH_CMD service action codes
+ * see spc4r17 Section D.3.5, table D.7 and D.8 */
+#define VLC_SA_RECEIVE_CREDENTIAL 0x1800
/* values for maintenance in */
+#define MI_REPORT_IDENTIFYING_INFORMATION 0x05
#define MI_REPORT_TARGET_PGS 0x0a
+#define MI_REPORT_ALIASES 0x0b
+#define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c
+#define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d
+#define MI_REPORT_PRIORITY 0x0e
+#define MI_REPORT_TIMESTAMP 0x0f
+#define MI_MANAGEMENT_PROTOCOL_IN 0x10
/* values for maintenance out */
+#define MO_SET_IDENTIFYING_INFORMATION 0x06
#define MO_SET_TARGET_PGS 0x0a
+#define MO_CHANGE_ALIASES 0x0b
+#define MO_SET_PRIORITY 0x0e
+#define MO_SET_TIMESTAMP 0x0f
+#define MO_MANAGEMENT_PROTOCOL_OUT 0x10
/* values for variable length command */
+#define XDREAD_32 0x03
+#define XDWRITE_32 0x04
+#define XPWRITE_32 0x06
+#define XDWRITEREAD_32 0x07
#define READ_32 0x09
#define VERIFY_32 0x0a
#define WRITE_32 0x0b
*
* STATUS: REQUIRED
*/
- int (* queuecommand)(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+ int (* queuecommand)(struct Scsi_Host *, struct scsi_cmnd *);
/*
* The transfer functions are used to queue a scsi command to
u64 vendor_id;
};
+/*
+ * Temporary #define for host lock push down. Can be removed when all
+ * drivers have been updated to take advantage of unlocked
+ * queuecommand.
+ *
+ */
+#define DEF_SCSI_QCMD(func_name) \
+ int func_name(struct Scsi_Host *shost, struct scsi_cmnd *cmd) \
+ { \
+ unsigned long irq_flags; \
+ int rc; \
+ spin_lock_irqsave(shost->host_lock, irq_flags); \
+ scsi_cmd_get_serial(shost, cmd); \
+ rc = func_name##_lck (cmd, cmd->scsi_done); \
+ spin_unlock_irqrestore(shost->host_lock, irq_flags); \
+ return rc; \
+ }
+
+
/*
* shost state: If you alter this, you also need to alter scsi_sysfs.c
* (for the ascii descriptions) and the state model enforcer:
extern void scsi_host_put(struct Scsi_Host *t);
extern struct Scsi_Host *scsi_host_lookup(unsigned short);
extern const char *scsi_host_state_name(enum scsi_host_state);
+extern void scsi_cmd_get_serial(struct Scsi_Host *, struct scsi_cmnd *);
extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
* ACK_MD (FSI2)
* CKG1 (FSI)
*
- * err: return value < 0
+ * err : return value < 0
+ * no change : return value == 0
+ * change xMD : return value > 0
*
* 0x-00000AB
*
struct sh_fsi_platform_info {
unsigned long porta_flags;
unsigned long portb_flags;
- int (*set_rate)(int is_porta, int rate); /* for master mode */
+ int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
};
#endif /* __SOUND_FSI_H */
#define FBIPUT_COLOR _IOW('F', 6, int)
#define FBIPUT_HSYNC _IOW('F', 9, int)
#define FBIPUT_VSYNC _IOW('F', 10, int)
-#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t)
#endif /* ifndef DA8XX_FB_H */
#ifdef CONFIG_PCI_MSI
/* Allocate an irq and a pirq to be used with MSIs. */
-void xen_allocate_pirq_msi(char *name, int *irq, int *pirq);
+#define XEN_ALLOC_PIRQ (1 << 0)
+#define XEN_ALLOC_IRQ (1 << 1)
+void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_mask);
int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type);
#endif
/* Return gsi allocated to pirq */
int xen_gsi_from_irq(unsigned pirq);
+/* Return irq from pirq */
+int xen_irq_from_pirq(unsigned pirq);
+
#endif /* _XEN_EVENTS_H */
* A ring contains as many entries as will fit, rounded down to the nearest
* power of two (so we can mask with (size-1) to loop around).
*/
-#define __RING_SIZE(_s, _sz) \
- (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
+#define __CONST_RING_SIZE(_s, _sz) \
+ (__RD32(((_sz) - offsetof(struct _s##_sring, ring)) / \
+ sizeof(((struct _s##_sring *)0)->ring[0])))
+
+/*
+ * The same for passing in an actual pointer instead of a name tag.
+ */
+#define __RING_SIZE(_s, _sz) \
+ (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
/*
* Macros to make the correct C datatypes for a new kind of ring.
};
DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
+/*
+ * Returns the location in virtual address space of the machine_to_phys
+ * mapping table. Architectures which do not have a m2p table, or which do not
+ * map it by default into guest address space, do not implement this command.
+ * arg == addr of xen_machphys_mapping_t.
+ */
+#define XENMEM_machphys_mapping 12
+struct xen_machphys_mapping {
+ unsigned long v_start, v_end; /* Start and end virtual addresses. */
+ unsigned long max_mfn; /* Maximum MFN that can be looked up. */
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mapping_t);
+
/*
* Sets the GPFN at which a particular page appears in the specified guest's
* pseudophysical address space.
uint32_t nr_pirqs;
};
+/* type is MAP_PIRQ_TYPE_GSI or MAP_PIRQ_TYPE_MSI
+ * the hypercall returns a free pirq */
+#define PHYSDEVOP_get_free_pirq 23
+struct physdev_get_free_pirq {
+ /* IN */
+ int type;
+ /* OUT */
+ uint32_t pirq;
+};
+
/*
* Notify that some PIRQ-bound event channels have been unmasked.
* ** This command is obsolete since interface version 0x00030202 and is **
+#ifndef _XEN_PAGE_H
+#define _XEN_PAGE_H
+
#include <asm/xen/page.h>
+
+extern phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
+
+#endif /* _XEN_PAGE_H */
#define __LINUX_PUBLIC_PRIVCMD_H__
#include <linux/types.h>
+#include <linux/compiler.h>
typedef unsigned long xen_pfn_t;
-#ifndef __user
-#define __user
-#endif
-
struct privcmd_hypercall {
__u64 op;
__u64 arg[5];
if boot option "noswapaccount" is set, swap will not be accounted.
Now, memory usage of swap_cgroup is 2 bytes per entry. If swap page
size is 4096bytes, 512k per 1Gbytes of swap.
+config CGROUP_MEM_RES_CTLR_SWAP_ENABLED
+ bool "Memory Resource Controller Swap Extension enabled by default"
+ depends on CGROUP_MEM_RES_CTLR_SWAP
+ default y
+ help
+ Memory Resource Controller Swap Extension comes with its price in
+ a bigger memory consumption. General purpose distribution kernels
+ which want to enable the feautre but keep it disabled by default
+ and let the user enable it by swapaccount boot command line
+ parameter should have this option unselected.
+ For those who want to have the feature enabled by default should
+ select this option (if, for some reason, they need to disable it
+ then noswapaccount does the trick).
menuconfig CGROUP_SCHED
bool "Group CPU scheduler"
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/initrd.h>
#include <linux/bootmem.h>
#include <linux/acpi.h>
#define for_each_kdbcmd(cmd, num) \
for ((cmd) = kdb_base_commands, (num) = 0; \
num < kdb_max_commands; \
- num == KDB_BASE_CMD_MAX ? cmd = kdb_commands : cmd++, num++)
+ num++, num == KDB_BASE_CMD_MAX ? cmd = kdb_commands : cmd++)
typedef struct _kdbmsg {
int km_diag; /* kdb diagnostic */
}
if (!s->usable)
return KDB_NOTIMP;
- s->command = kmalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB);
+ s->command = kzalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB);
if (!s->command) {
kdb_printf("Could not allocate new kdb_defcmd table for %s\n",
cmdstr);
*/
static int kdb_ll(int argc, const char **argv)
{
- int diag;
+ int diag = 0;
unsigned long addr;
long offset = 0;
unsigned long va;
char buf[80];
if (KDB_FLAG(CMD_INTERRUPT))
- return 0;
+ goto out;
sprintf(buf, "%s " kdb_machreg_fmt "\n", command, va);
diag = kdb_parse(buf);
if (diag)
- return diag;
+ goto out;
addr = va + linkoffset;
if (kdb_getword(&va, addr, sizeof(va)))
- return 0;
+ goto out;
}
- kfree(command);
- return 0;
+out:
+ kfree(command);
+ return diag;
}
static int kdb_kgdb(int argc, const char **argv)
}
if (kdb_commands) {
memcpy(new, kdb_commands,
- kdb_max_commands * sizeof(*new));
+ (kdb_max_commands - KDB_BASE_CMD_MAX) * sizeof(*new));
kfree(kdb_commands);
}
memset(new + kdb_max_commands, 0,
kdb_command_extend * sizeof(*new));
kdb_commands = new;
- kp = kdb_commands + kdb_max_commands;
+ kp = kdb_commands + kdb_max_commands - KDB_BASE_CMD_MAX;
kdb_max_commands += kdb_command_extend;
}
if (unlikely(!tsk->pid))
panic("Attempted to kill the idle task!");
+ /*
+ * If do_exit is called because this processes oopsed, it's possible
+ * that get_fs() was left as KERNEL_DS, so reset it to USER_DS before
+ * continuing. Amongst other possible reasons, this is to prevent
+ * mm_release()->clear_child_tid() from writing to a user-controlled
+ * kernel address.
+ */
+ set_fs(USER_DS);
+
tracehook_report_exit(&code);
validate_creds_for_do_exit(tsk);
{
struct robust_list_head __user *head = curr->robust_list;
struct robust_list __user *entry, *next_entry, *pending;
- unsigned int limit = ROBUST_LIST_LIMIT, pi, next_pi, pip;
+ unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
+ unsigned int uninitialized_var(next_pi);
unsigned long futex_offset;
int rc;
{
struct compat_robust_list_head __user *head = curr->compat_robust_list;
struct robust_list __user *entry, *next_entry, *pending;
- unsigned int limit = ROBUST_LIST_LIMIT, pi, next_pi, pip;
+ unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
+ unsigned int uninitialized_var(next_pi);
compat_uptr_t uentry, next_uentry, upending;
compat_long_t futex_offset;
int rc;
.read = hw_breakpoint_pmu_read,
};
-static int __init init_hw_breakpoint(void)
+int __init init_hw_breakpoint(void)
{
unsigned int **task_bp_pinned;
int cpu, err_cpu;
return -ENOMEM;
}
-core_initcall(init_hw_breakpoint);
static int irq_spurious_proc_open(struct inode *inode, struct file *file)
{
- return single_open(file, irq_spurious_proc_show, NULL);
+ return single_open(file, irq_spurious_proc_show, PDE(inode)->data);
}
static const struct file_operations irq_spurious_proc_fops = {
* Clear the BUSY bit and return to the free state if
* no-one else claimed it meanwhile.
*/
- cmpxchg(&entry->next, next_flags(NULL, IRQ_WORK_BUSY), NULL);
+ (void)cmpxchg(&entry->next,
+ next_flags(NULL, IRQ_WORK_BUSY),
+ NULL);
}
}
EXPORT_SYMBOL_GPL(irq_work_run);
kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) *
mod->num_trace_events, GFP_KERNEL);
#endif
+#ifdef CONFIG_TRACING
+ mod->trace_bprintk_fmt_start = section_objs(info, "__trace_printk_fmt",
+ sizeof(*mod->trace_bprintk_fmt_start),
+ &mod->num_trace_bprintk_fmt);
+ /*
+ * This section contains pointers to allocated objects in the trace
+ * code and not scanning it leads to false positives.
+ */
+ kmemleak_scan_area(mod->trace_bprintk_fmt_start,
+ sizeof(*mod->trace_bprintk_fmt_start) *
+ mod->num_trace_bprintk_fmt, GFP_KERNEL);
+#endif
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
/* sechdrs[0].sh_size is always zero */
mod->ftrace_callsites = section_objs(info, "__mcount_loc",
#include <linux/kernel_stat.h>
#include <linux/perf_event.h>
#include <linux/ftrace_event.h>
+#include <linux/hw_breakpoint.h>
#include <asm/irq_regs.h>
{
int ctxn;
- perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0);
-
for_each_task_context_nr(ctxn)
perf_event_context_sched_out(task, ctxn, next);
}
{
raw_spin_lock(&ctx->lock);
- /* Rotate the first entry last of non-pinned groups */
- list_rotate_left(&ctx->flexible_groups);
+ /*
+ * Rotate the first entry last of non-pinned groups. Rotation might be
+ * disabled by the inheritance code.
+ */
+ if (!ctx->rotate_disable)
+ list_rotate_left(&ctx->flexible_groups);
raw_spin_unlock(&ctx->lock);
}
raw_spin_unlock_irq(&ctx->lock);
mutex_unlock(&ctx->mutex);
- mutex_lock(&event->owner->perf_event_mutex);
- list_del_init(&event->owner_entry);
- mutex_unlock(&event->owner->perf_event_mutex);
- put_task_struct(event->owner);
-
free_event(event);
return 0;
static int perf_release(struct inode *inode, struct file *file)
{
struct perf_event *event = file->private_data;
+ struct task_struct *owner;
file->private_data = NULL;
+ rcu_read_lock();
+ owner = ACCESS_ONCE(event->owner);
+ /*
+ * Matches the smp_wmb() in perf_event_exit_task(). If we observe
+ * !owner it means the list deletion is complete and we can indeed
+ * free this event, otherwise we need to serialize on
+ * owner->perf_event_mutex.
+ */
+ smp_read_barrier_depends();
+ if (owner) {
+ /*
+ * Since delayed_put_task_struct() also drops the last
+ * task reference we can safely take a new reference
+ * while holding the rcu_read_lock().
+ */
+ get_task_struct(owner);
+ }
+ rcu_read_unlock();
+
+ if (owner) {
+ mutex_lock(&owner->perf_event_mutex);
+ /*
+ * We have to re-check the event->owner field, if it is cleared
+ * we raced with perf_event_exit_task(), acquiring the mutex
+ * ensured they're done, and we can proceed with freeing the
+ * event.
+ */
+ if (event->owner)
+ list_del_init(&event->owner_entry);
+ mutex_unlock(&owner->perf_event_mutex);
+ put_task_struct(owner);
+ }
+
return perf_event_release_kernel(event);
}
mutex_unlock(&ctx->mutex);
event->owner = current;
- get_task_struct(current);
+
mutex_lock(¤t->perf_event_mutex);
list_add_tail(&event->owner_entry, ¤t->perf_event_list);
mutex_unlock(¤t->perf_event_mutex);
++ctx->generation;
mutex_unlock(&ctx->mutex);
- event->owner = current;
- get_task_struct(current);
- mutex_lock(¤t->perf_event_mutex);
- list_add_tail(&event->owner_entry, ¤t->perf_event_list);
- mutex_unlock(¤t->perf_event_mutex);
-
return event;
err_free:
*/
void perf_event_exit_task(struct task_struct *child)
{
+ struct perf_event *event, *tmp;
int ctxn;
+ mutex_lock(&child->perf_event_mutex);
+ list_for_each_entry_safe(event, tmp, &child->perf_event_list,
+ owner_entry) {
+ list_del_init(&event->owner_entry);
+
+ /*
+ * Ensure the list deletion is visible before we clear
+ * the owner, closes a race against perf_release() where
+ * we need to serialize on the owner->perf_event_mutex.
+ */
+ smp_wmb();
+ event->owner = NULL;
+ }
+ mutex_unlock(&child->perf_event_mutex);
+
for_each_task_context_nr(ctxn)
perf_event_exit_task_context(child, ctxn);
}
struct perf_event *event;
struct task_struct *parent = current;
int inherited_all = 1;
+ unsigned long flags;
int ret = 0;
child->perf_event_ctxp[ctxn] = NULL;
break;
}
+ /*
+ * We can't hold ctx->lock when iterating the ->flexible_group list due
+ * to allocations, but we need to prevent rotation because
+ * rotate_ctx() will change the list from interrupt context.
+ */
+ raw_spin_lock_irqsave(&parent_ctx->lock, flags);
+ parent_ctx->rotate_disable = 1;
+ raw_spin_unlock_irqrestore(&parent_ctx->lock, flags);
+
list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) {
ret = inherit_task_group(event, parent, parent_ctx,
child, ctxn, &inherited_all);
break;
}
+ raw_spin_lock_irqsave(&parent_ctx->lock, flags);
+ parent_ctx->rotate_disable = 0;
+ raw_spin_unlock_irqrestore(&parent_ctx->lock, flags);
+
child_ctx = child->perf_event_ctxp[ctxn];
if (child_ctx && inherited_all) {
void __init perf_event_init(void)
{
+ int ret;
+
perf_event_init_all_cpus();
init_srcu_struct(&pmus_srcu);
perf_pmu_register(&perf_swevent);
perf_pmu_register(&perf_task_clock);
perf_tp_register();
perf_cpu_notifier(perf_cpu_notify);
+
+ ret = init_hw_breakpoint();
+ WARN(ret, "hw_breakpoint initialization failed with: %d", ret);
}
switch (o->type) {
case PM_QOS_MIN:
- return plist_last(&o->requests)->prio;
+ return plist_first(&o->requests)->prio;
case PM_QOS_MAX:
- return plist_first(&o->requests)->prio;
+ return plist_last(&o->requests)->prio;
default:
/* runtime check for not using enum */
if (pid == 0)
return 0;
- read_lock(&tasklist_lock);
+ rcu_read_lock();
p = find_task_by_vpid(pid);
if (!p || !(CPUCLOCK_PERTHREAD(which_clock) ?
- same_thread_group(p, current) : thread_group_leader(p))) {
+ same_thread_group(p, current) : has_group_leader_pid(p))) {
error = -EINVAL;
}
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
return error;
}
INIT_LIST_HEAD(&new_timer->it.cpu.entry);
- read_lock(&tasklist_lock);
+ rcu_read_lock();
if (CPUCLOCK_PERTHREAD(new_timer->it_clock)) {
if (pid == 0) {
p = current;
p = current->group_leader;
} else {
p = find_task_by_vpid(pid);
- if (p && !thread_group_leader(p))
+ if (p && !has_group_leader_pid(p))
p = NULL;
}
}
} else {
ret = -EINVAL;
}
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
return ret;
}
depends on PM_SLEEP || PM_RUNTIME
default y
+config ARCH_HAS_OPP
+ bool
+
config PM_OPP
bool "Operating Performance Point (OPP) Layer library"
depends on PM
+ depends on ARCH_HAS_OPP
---help---
SOCs have a standard set of tuples consisting of frequency and
voltage pairs that the device will support per voltage domain. This
int hibernation_snapshot(int platform_mode)
{
int error;
- gfp_t saved_mask;
error = platform_begin(platform_mode);
if (error)
goto Close;
suspend_console();
- saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
+ pm_restrict_gfp_mask();
error = dpm_suspend_start(PMSG_FREEZE);
if (error)
goto Recover_platform;
goto Recover_platform;
error = create_image(platform_mode);
- /* Control returns here after successful restore */
+ /*
+ * Control returns here (1) after the image has been created or the
+ * image creation has failed and (2) after a successful restore.
+ */
Resume_devices:
/* We may need to release the preallocated image pages here. */
dpm_resume_end(in_suspend ?
(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
- set_gfp_allowed_mask(saved_mask);
+
+ if (error || !in_suspend)
+ pm_restore_gfp_mask();
+
resume_console();
Close:
platform_end(platform_mode);
int hibernation_restore(int platform_mode)
{
int error;
- gfp_t saved_mask;
pm_prepare_console();
suspend_console();
- saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
+ pm_restrict_gfp_mask();
error = dpm_suspend_start(PMSG_QUIESCE);
if (!error) {
error = resume_target_kernel(platform_mode);
dpm_resume_end(PMSG_RECOVER);
}
- set_gfp_allowed_mask(saved_mask);
+ pm_restore_gfp_mask();
resume_console();
pm_restore_console();
return error;
int hibernation_platform_enter(void)
{
int error;
- gfp_t saved_mask;
if (!hibernation_ops)
return -ENOSYS;
entering_platform_hibernation = true;
suspend_console();
- saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
error = dpm_suspend_start(PMSG_HIBERNATE);
if (error) {
if (hibernation_ops->recover)
Resume_devices:
entering_platform_hibernation = false;
dpm_resume_end(PMSG_RESTORE);
- set_gfp_allowed_mask(saved_mask);
resume_console();
Close:
swsusp_free();
if (!error)
power_down();
+ pm_restore_gfp_mask();
} else {
pr_debug("PM: Image restored successfully.\n");
}
int suspend_devices_and_enter(suspend_state_t state)
{
int error;
- gfp_t saved_mask;
if (!suspend_ops)
return -ENOSYS;
goto Close;
}
suspend_console();
- saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
+ pm_restrict_gfp_mask();
suspend_test_start();
error = dpm_suspend_start(PMSG_SUSPEND);
if (error) {
suspend_test_start();
dpm_resume_end(PMSG_RESUME);
suspend_test_finish("resume devices");
- set_gfp_allowed_mask(saved_mask);
+ pm_restore_gfp_mask();
resume_console();
Close:
if (suspend_ops->end)
*
* Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
+ * Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com>
*
* This file is released under the GPLv2.
*
{
unsigned int m;
int error = 0;
+ struct bio *bio;
struct timeval start;
struct timeval stop;
unsigned nr_pages;
- size_t off, unc_len, cmp_len;
- unsigned char *unc, *cmp, *page;
+ size_t i, off, unc_len, cmp_len;
+ unsigned char *unc, *cmp, *page[LZO_CMP_PAGES];
- page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
- if (!page) {
- printk(KERN_ERR "PM: Failed to allocate LZO page\n");
- return -ENOMEM;
+ for (i = 0; i < LZO_CMP_PAGES; i++) {
+ page[i] = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+ if (!page[i]) {
+ printk(KERN_ERR "PM: Failed to allocate LZO page\n");
+
+ while (i)
+ free_page((unsigned long)page[--i]);
+
+ return -ENOMEM;
+ }
}
unc = vmalloc(LZO_UNC_SIZE);
if (!unc) {
printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
- free_page((unsigned long)page);
+
+ for (i = 0; i < LZO_CMP_PAGES; i++)
+ free_page((unsigned long)page[i]);
+
return -ENOMEM;
}
cmp = vmalloc(LZO_CMP_SIZE);
if (!cmp) {
printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
+
vfree(unc);
- free_page((unsigned long)page);
+ for (i = 0; i < LZO_CMP_PAGES; i++)
+ free_page((unsigned long)page[i]);
+
return -ENOMEM;
}
if (!m)
m = 1;
nr_pages = 0;
+ bio = NULL;
do_gettimeofday(&start);
error = snapshot_write_next(snapshot);
goto out_finish;
for (;;) {
- error = swap_read_page(handle, page, NULL); /* sync */
+ error = swap_read_page(handle, page[0], NULL); /* sync */
if (error)
break;
- cmp_len = *(size_t *)page;
+ cmp_len = *(size_t *)page[0];
if (unlikely(!cmp_len ||
cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {
printk(KERN_ERR "PM: Invalid LZO compressed length\n");
break;
}
- memcpy(cmp, page, PAGE_SIZE);
- for (off = PAGE_SIZE; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) {
- error = swap_read_page(handle, page, NULL); /* sync */
+ for (off = PAGE_SIZE, i = 1;
+ off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
+ error = swap_read_page(handle, page[i], &bio);
if (error)
goto out_finish;
+ }
- memcpy(cmp + off, page, PAGE_SIZE);
+ error = hib_wait_on_bio_chain(&bio); /* need all data now */
+ if (error)
+ goto out_finish;
+
+ for (off = 0, i = 0;
+ off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
+ memcpy(cmp + off, page[i], PAGE_SIZE);
}
unc_len = LZO_UNC_SIZE;
vfree(cmp);
vfree(unc);
- free_page((unsigned long)page);
+ for (i = 0; i < LZO_CMP_PAGES; i++)
+ free_page((unsigned long)page[i]);
return error;
}
case SNAPSHOT_UNFREEZE:
if (!data->frozen || data->ready)
break;
+ pm_restore_gfp_mask();
thaw_processes();
usermodehelper_enable();
data->frozen = 0;
error = -EPERM;
break;
}
+ pm_restore_gfp_mask();
error = hibernation_snapshot(data->platform_support);
if (!error)
error = put_user(in_suspend, (int __user *)arg);
int printk_needs_cpu(int cpu)
{
+ if (unlikely(cpu_is_offline(cpu)))
+ printk_tick();
return per_cpu(printk_pending, cpu);
}
void wake_up_klogd(void)
{
if (waitqueue_active(&log_wait))
- __raw_get_cpu_var(printk_pending) = 1;
+ this_cpu_write(printk_pending, 1);
}
/**
static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
-static inline
-void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
-{
- rq->curr->sched_class->check_preempt_curr(rq, p, flags);
- /*
- * A queue event has occurred, and we're going to schedule. In
- * this case, we can save a useless back to back clock update.
- */
- if (test_tsk_need_resched(p))
- rq->skip_clock_update = 1;
-}
+static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags);
static inline int cpu_of(struct rq *rq)
{
p->sched_class->prio_changed(rq, p, oldprio, running);
}
+static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
+{
+ const struct sched_class *class;
+
+ if (p->sched_class == rq->curr->sched_class) {
+ rq->curr->sched_class->check_preempt_curr(rq, p, flags);
+ } else {
+ for_each_class(class) {
+ if (class == rq->curr->sched_class)
+ break;
+ if (class == p->sched_class) {
+ resched_task(rq->curr);
+ break;
+ }
+ }
+ }
+
+ /*
+ * A queue event has occurred, and we're going to schedule. In
+ * this case, we can save a useless back to back clock update.
+ */
+ if (test_tsk_need_resched(rq->curr))
+ rq->skip_clock_update = 1;
+}
+
#ifdef CONFIG_SMP
/*
* Is this task likely cache-hot:
if (cpu != group_first_cpu(sd->groups))
return;
+ sd->groups->group_weight = cpumask_weight(sched_group_cpus(sd->groups));
+
child = sd->child;
sd->groups->cpu_power = 0;
struct cfs_rq *cfs_rq = task_cfs_rq(curr);
int scale = cfs_rq->nr_running >= sched_nr_latency;
- if (unlikely(rt_prio(p->prio)))
- goto preempt;
-
- if (unlikely(p->sched_class != &fair_sched_class))
- return;
-
if (unlikely(se == pse))
return;
set_task_cpu(p, this_cpu);
activate_task(this_rq, p, 0);
check_preempt_curr(this_rq, p, 0);
-
- /* re-arm NEWIDLE balancing when moving tasks */
- src_rq->avg_idle = this_rq->avg_idle = 2*sysctl_sched_migration_cost;
- this_rq->idle_stamp = 0;
}
/*
unsigned long this_load_per_task;
unsigned long this_nr_running;
unsigned long this_has_capacity;
+ unsigned int this_idle_cpus;
/* Statistics of the busiest group */
+ unsigned int busiest_idle_cpus;
unsigned long max_load;
unsigned long busiest_load_per_task;
unsigned long busiest_nr_running;
unsigned long busiest_group_capacity;
unsigned long busiest_has_capacity;
+ unsigned int busiest_group_weight;
int group_imb; /* Is there imbalance in this sd */
#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
unsigned long sum_nr_running; /* Nr tasks running in the group */
unsigned long sum_weighted_load; /* Weighted load of group's tasks */
unsigned long group_capacity;
+ unsigned long idle_cpus;
+ unsigned long group_weight;
int group_imb; /* Is there an imbalance in the group ? */
int group_has_capacity; /* Is there extra capacity in the group? */
};
sgs->group_load += load;
sgs->sum_nr_running += rq->nr_running;
sgs->sum_weighted_load += weighted_cpuload(i);
-
+ if (idle_cpu(i))
+ sgs->idle_cpus++;
}
/*
sgs->group_capacity = DIV_ROUND_CLOSEST(group->cpu_power, SCHED_LOAD_SCALE);
if (!sgs->group_capacity)
sgs->group_capacity = fix_small_capacity(sd, group);
+ sgs->group_weight = group->group_weight;
if (sgs->group_capacity > sgs->sum_nr_running)
sgs->group_has_capacity = 1;
sds->this_nr_running = sgs.sum_nr_running;
sds->this_load_per_task = sgs.sum_weighted_load;
sds->this_has_capacity = sgs.group_has_capacity;
+ sds->this_idle_cpus = sgs.idle_cpus;
} else if (update_sd_pick_busiest(sd, sds, sg, &sgs, this_cpu)) {
sds->max_load = sgs.avg_load;
sds->busiest = sg;
sds->busiest_nr_running = sgs.sum_nr_running;
+ sds->busiest_idle_cpus = sgs.idle_cpus;
sds->busiest_group_capacity = sgs.group_capacity;
sds->busiest_load_per_task = sgs.sum_weighted_load;
sds->busiest_has_capacity = sgs.group_has_capacity;
+ sds->busiest_group_weight = sgs.group_weight;
sds->group_imb = sgs.group_imb;
}
if (sds.this_load >= sds.avg_load)
goto out_balanced;
- if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load)
- goto out_balanced;
+ /*
+ * In the CPU_NEWLY_IDLE, use imbalance_pct to be conservative.
+ * And to check for busy balance use !idle_cpu instead of
+ * CPU_NOT_IDLE. This is because HT siblings will use CPU_NOT_IDLE
+ * even when they are idle.
+ */
+ if (idle == CPU_NEWLY_IDLE || !idle_cpu(this_cpu)) {
+ if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load)
+ goto out_balanced;
+ } else {
+ /*
+ * This cpu is idle. If the busiest group load doesn't
+ * have more tasks than the number of available cpu's and
+ * there is no imbalance between this and busiest group
+ * wrt to idle cpu's, it is balanced.
+ */
+ if ((sds.this_idle_cpus <= sds.busiest_idle_cpus + 1) &&
+ sds.busiest_nr_running <= sds.busiest_group_weight)
+ goto out_balanced;
+ }
force_balance:
/* Looks like there is an imbalance. Compute it */
interval = msecs_to_jiffies(sd->balance_interval);
if (time_after(next_balance, sd->last_balance + interval))
next_balance = sd->last_balance + interval;
- if (pulled_task)
+ if (pulled_task) {
+ this_rq->idle_stamp = 0;
break;
+ }
}
raw_spin_lock(&this_rq->lock);
static void
check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags)
{
- resched_task(rq->curr); /* we preempt everything */
+ /* we're never preempted */
}
static struct task_struct *pick_next_task_stop(struct rq *rq)
{
struct task_struct *stop = rq->stop;
- if (stop && stop->state == TASK_RUNNING)
+ if (stop && stop->se.on_rq)
return stop;
return NULL;
.extra1 = &zero,
.extra2 = &ten_thousand,
},
-#endif
{
.procname = "dmesg_restrict",
.data = &dmesg_restrict,
.extra1 = &zero,
.extra2 = &one,
},
+#endif
{
.procname = "ngroups_max",
.data = &ngroups_max,
config FUNCTION_TRACER
bool "Kernel Function Tracer"
depends on HAVE_FUNCTION_TRACER
- select FRAME_POINTER if (!ARM_UNWIND)
+ select FRAME_POINTER if !ARM_UNWIND && !S390
select KALLSYMS
select GENERIC_TRACER
select CONTEXT_SWITCH_TRACER
#include <linux/writeback.h>
#include <linux/kallsyms.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/notifier.h>
#include <linux/irqflags.h>
#include <linux/debugfs.h>
__ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count());
}
+static DEFINE_PER_CPU(int, user_stack_count);
+
void
ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc)
{
if (unlikely(in_nmi()))
return;
+ /*
+ * prevent recursion, since the user stack tracing may
+ * trigger other kernel events.
+ */
+ preempt_disable();
+ if (__this_cpu_read(user_stack_count))
+ goto out;
+
+ __this_cpu_inc(user_stack_count);
+
+
+
event = trace_buffer_lock_reserve(buffer, TRACE_USER_STACK,
sizeof(*entry), flags, pc);
if (!event)
save_stack_trace_user(&trace);
if (!filter_check_discard(call, entry, buffer, event))
ring_buffer_unlock_commit(buffer, event);
+
+ __this_cpu_dec(user_stack_count);
+
+ out:
+ preempt_enable();
}
#ifdef UNUSED
{
struct worker *worker = kthread_data(task);
- if (likely(!(worker->flags & WORKER_NOT_RUNNING)))
+ if (!(worker->flags & WORKER_NOT_RUNNING))
atomic_inc(get_gcwq_nr_running(cpu));
}
struct global_cwq *gcwq = get_gcwq(cpu);
atomic_t *nr_running = get_gcwq_nr_running(cpu);
- if (unlikely(worker->flags & WORKER_NOT_RUNNING))
+ if (worker->flags & WORKER_NOT_RUNNING)
return NULL;
/* this can only happen on the local cpu */
system_nrt_wq = alloc_workqueue("events_nrt", WQ_NON_REENTRANT, 0);
system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND,
WQ_UNBOUND_MAX_ACTIVE);
- BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq);
+ BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq ||
+ !system_unbound_wq);
return 0;
}
early_initcall(init_workqueues);
*
* Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
*/
-#include <linux/kernel.h>
#include <linux/rwsem.h>
#include <linux/mutex.h>
#include <linux/module.h>
{
if (__debug_locks_off()) {
if (!debug_locks_silent) {
- oops_in_progress = 1;
console_verbose();
return 1;
}
void remove_from_page_cache(struct page *page)
{
struct address_space *mapping = page->mapping;
+ void (*freepage)(struct page *);
BUG_ON(!PageLocked(page));
+ freepage = mapping->a_ops->freepage;
spin_lock_irq(&mapping->tree_lock);
__remove_from_page_cache(page);
spin_unlock_irq(&mapping->tree_lock);
mem_cgroup_uncharge_cache_page(page);
+
+ if (freepage)
+ freepage(page);
}
EXPORT_SYMBOL(remove_from_page_cache);
unlock_page(pagecache_page);
put_page(pagecache_page);
}
- unlock_page(page);
+ if (page != pagecache_page)
+ unlock_page(page);
out_mutex:
mutex_unlock(&hugetlb_instantiation_mutex);
/*
* Keep it very simple for now: just lock out ksmd and
* MADV_UNMERGEABLE while any memory is going offline.
+ * mutex_lock_nested() is necessary because lockdep was alarmed
+ * that here we take ksm_thread_mutex inside notifier chain
+ * mutex, and later take notifier chain mutex inside
+ * ksm_thread_mutex to unlock it. But that's safe because both
+ * are inside mem_hotplug_mutex.
*/
- mutex_lock(&ksm_thread_mutex);
+ mutex_lock_nested(&ksm_thread_mutex, SINGLE_DEPTH_NESTING);
break;
case MEM_OFFLINE:
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
/* Turned on only when memory cgroup is enabled && really_do_swap_account = 1 */
int do_swap_account __read_mostly;
-static int really_do_swap_account __initdata = 1; /* for remember boot option*/
+
+/* for remember boot option*/
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED
+static int really_do_swap_account __initdata = 1;
+#else
+static int really_do_swap_account __initdata = 0;
+#endif
+
#else
#define do_swap_account (0)
#endif
/* "mc" and its members are protected by cgroup_mutex */
static struct move_charge_struct {
- spinlock_t lock; /* for from, to, moving_task */
+ spinlock_t lock; /* for from, to */
struct mem_cgroup *from;
struct mem_cgroup *to;
unsigned long precharge;
unsigned long moved_charge;
unsigned long moved_swap;
struct task_struct *moving_task; /* a task moving charges */
+ struct mm_struct *mm;
wait_queue_head_t waitq; /* a waitq for other context */
} mc = {
.lock = __SPIN_LOCK_UNLOCKED(mc.lock),
{
VM_BUG_ON(from == to);
VM_BUG_ON(PageLRU(pc->page));
- VM_BUG_ON(!PageCgroupLocked(pc));
+ VM_BUG_ON(!page_is_cgroup_locked(pc));
VM_BUG_ON(!PageCgroupUsed(pc));
VM_BUG_ON(pc->mem_cgroup != from);
unsigned long precharge;
struct vm_area_struct *vma;
- down_read(&mm->mmap_sem);
+ /* We've already held the mmap_sem */
for (vma = mm->mmap; vma; vma = vma->vm_next) {
struct mm_walk mem_cgroup_count_precharge_walk = {
.pmd_entry = mem_cgroup_count_precharge_pte_range,
walk_page_range(vma->vm_start, vma->vm_end,
&mem_cgroup_count_precharge_walk);
}
- up_read(&mm->mmap_sem);
precharge = mc.precharge;
mc.precharge = 0;
mc.moved_swap = 0;
}
+ if (mc.mm) {
+ up_read(&mc.mm->mmap_sem);
+ mmput(mc.mm);
+ }
spin_lock(&mc.lock);
mc.from = NULL;
mc.to = NULL;
- mc.moving_task = NULL;
spin_unlock(&mc.lock);
+ mc.moving_task = NULL;
+ mc.mm = NULL;
mem_cgroup_end_move(from);
memcg_oom_recover(from);
memcg_oom_recover(to);
return 0;
/* We move charges only when we move a owner of the mm */
if (mm->owner == p) {
+ /*
+ * We do all the move charge works under one mmap_sem to
+ * avoid deadlock with down_write(&mmap_sem)
+ * -> try_charge() -> if (mc.moving_task) -> sleep.
+ */
+ down_read(&mm->mmap_sem);
+
VM_BUG_ON(mc.from);
VM_BUG_ON(mc.to);
VM_BUG_ON(mc.precharge);
VM_BUG_ON(mc.moved_charge);
VM_BUG_ON(mc.moved_swap);
VM_BUG_ON(mc.moving_task);
+ VM_BUG_ON(mc.mm);
+
mem_cgroup_start_move(from);
spin_lock(&mc.lock);
mc.from = from;
mc.precharge = 0;
mc.moved_charge = 0;
mc.moved_swap = 0;
- mc.moving_task = current;
spin_unlock(&mc.lock);
+ mc.moving_task = current;
+ mc.mm = mm;
ret = mem_cgroup_precharge_mc(mm);
if (ret)
mem_cgroup_clear_mc();
- }
- mmput(mm);
+ /* We call up_read() and mmput() in clear_mc(). */
+ } else
+ mmput(mm);
}
return ret;
}
struct vm_area_struct *vma;
lru_add_drain_all();
- down_read(&mm->mmap_sem);
+ /* We've already held the mmap_sem */
for (vma = mm->mmap; vma; vma = vma->vm_next) {
int ret;
struct mm_walk mem_cgroup_move_charge_walk = {
*/
break;
}
- up_read(&mm->mmap_sem);
}
static void mem_cgroup_move_task(struct cgroup_subsys *ss,
struct task_struct *p,
bool threadgroup)
{
- struct mm_struct *mm;
-
- if (!mc.to)
+ if (!mc.mm)
/* no need to move charge */
return;
- mm = get_task_mm(p);
- if (mm) {
- mem_cgroup_move_charge(mm);
- mmput(mm);
- }
+ mem_cgroup_move_charge(mc.mm);
mem_cgroup_clear_mc();
}
#else /* !CONFIG_MMU */
};
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
+static int __init enable_swap_account(char *s)
+{
+ /* consider enabled if no parameter or 1 is given */
+ if (!s || !strcmp(s, "1"))
+ really_do_swap_account = 1;
+ else if (!strcmp(s, "0"))
+ really_do_swap_account = 0;
+ return 1;
+}
+__setup("swapaccount", enable_swap_account);
static int __init disable_swap_account(char *s)
{
- really_do_swap_account = 0;
+ enable_swap_account("0");
return 1;
}
__setup("noswapaccount", disable_swap_account);
#include <linux/slab.h>
#include <linux/swapops.h>
#include <linux/hugetlb.h>
+#include <linux/memory_hotplug.h>
#include "internal.h"
int sysctl_memory_failure_early_kill __read_mostly = 0;
return 1;
/*
- * The lock_system_sleep prevents a race with memory hotplug,
- * because the isolation assumes there's only a single user.
+ * The lock_memory_hotplug prevents a race with memory hotplug.
* This is a big hammer, a better would be nicer.
*/
- lock_system_sleep();
+ lock_memory_hotplug();
/*
* Isolate the page, so that it doesn't get reallocated if it
ret = 1;
}
unset_migratetype_isolate(p);
- unlock_system_sleep();
+ unlock_memory_hotplug();
return ret;
}
#include "internal.h"
+DEFINE_MUTEX(mem_hotplug_mutex);
+
+void lock_memory_hotplug(void)
+{
+ mutex_lock(&mem_hotplug_mutex);
+
+ /* for exclusive hibernation if CONFIG_HIBERNATION=y */
+ lock_system_sleep();
+}
+
+void unlock_memory_hotplug(void)
+{
+ unlock_system_sleep();
+ mutex_unlock(&mem_hotplug_mutex);
+}
+
+
/* add this memory to iomem resource */
static struct resource *register_memory_resource(u64 start, u64 size)
{
pg_data_t *pgdat;
int ret;
- lock_system_sleep();
+ lock_memory_hotplug();
pgdat = hotadd_new_pgdat(nid, 0);
if (pgdat) {
ret = -ENOMEM;
BUG_ON(ret);
out:
- unlock_system_sleep();
+ unlock_memory_hotplug();
return ret;
}
struct resource *res;
int ret;
- lock_system_sleep();
+ lock_memory_hotplug();
res = register_memory_resource(start, size);
ret = -EEXIST;
release_memory_resource(res);
out:
- unlock_system_sleep();
+ unlock_memory_hotplug();
return ret;
}
EXPORT_SYMBOL_GPL(add_memory);
if (!test_pages_in_a_zone(start_pfn, end_pfn))
return -EINVAL;
- lock_system_sleep();
+ lock_memory_hotplug();
zone = page_zone(pfn_to_page(start_pfn));
node = zone_to_nid(zone);
writeback_set_ratelimit();
memory_notify(MEM_OFFLINE, &arg);
- unlock_system_sleep();
+ unlock_memory_hotplug();
return 0;
failed_removal:
undo_isolate_page_range(start_pfn, end_pfn);
out:
- unlock_system_sleep();
+ unlock_memory_hotplug();
return ret;
}
goto out;
/* Find the mm_struct */
+ rcu_read_lock();
read_lock(&tasklist_lock);
task = pid ? find_task_by_vpid(pid) : current;
if (!task) {
read_unlock(&tasklist_lock);
+ rcu_read_unlock();
err = -ESRCH;
goto out;
}
mm = get_task_mm(task);
read_unlock(&tasklist_lock);
+ rcu_read_unlock();
err = -EINVAL;
if (!mm)
unsigned long addr, unsigned long len,
unsigned long vm_flags, struct page **pages)
{
+ int ret;
struct vm_area_struct *vma;
vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
vma->vm_ops = &special_mapping_vmops;
vma->vm_private_data = pages;
- if (unlikely(insert_vm_struct(mm, vma))) {
- kmem_cache_free(vm_area_cachep, vma);
- return -ENOMEM;
- }
+ ret = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1);
+ if (ret)
+ goto out;
+
+ ret = insert_vm_struct(mm, vma);
+ if (ret)
+ goto out;
mm->total_vm += len >> PAGE_SHIFT;
perf_event_mmap(vma);
return 0;
+
+out:
+ kmem_cache_free(vm_area_cachep, vma);
+ return ret;
}
static DEFINE_MUTEX(mm_all_locks_mutex);
mm->mmap = vma->vm_next;
delete_vma_from_mm(vma);
delete_vma(mm, vma);
+ cond_resched();
}
kleave("");
* only be modified with pm_mutex held, unless the suspend/hibernate code is
* guaranteed not to run in parallel with that modification).
*/
-void set_gfp_allowed_mask(gfp_t mask)
+
+static gfp_t saved_gfp_mask;
+
+void pm_restore_gfp_mask(void)
{
WARN_ON(!mutex_is_locked(&pm_mutex));
- gfp_allowed_mask = mask;
+ if (saved_gfp_mask) {
+ gfp_allowed_mask = saved_gfp_mask;
+ saved_gfp_mask = 0;
+ }
}
-gfp_t clear_gfp_allowed_mask(gfp_t mask)
+void pm_restrict_gfp_mask(void)
{
- gfp_t ret = gfp_allowed_mask;
-
WARN_ON(!mutex_is_locked(&pm_mutex));
- gfp_allowed_mask &= ~mask;
- return ret;
+ WARN_ON(saved_gfp_mask);
+ saved_gfp_mask = gfp_allowed_mask;
+ gfp_allowed_mask &= ~GFP_IOFS;
}
#endif /* CONFIG_PM_SLEEP */
build_zonelist_cache(pgdat);
}
-#ifdef CONFIG_MEMORY_HOTPLUG
- /* Setup real pagesets for the new zone */
- if (data) {
- struct zone *zone = data;
- setup_zone_pageset(zone);
- }
-#endif
-
/*
* Initialize the boot_pagesets that are going to be used
* for bootstrapping processors. The real pagesets for
} else {
/* we have to stop all cpus to guarantee there is no user
of zonelist */
- stop_machine(__build_all_zonelists, data, NULL);
+#ifdef CONFIG_MEMORY_HOTPLUG
+ if (data)
+ setup_zone_pageset((struct zone *)data);
+#endif
+ stop_machine(__build_all_zonelists, NULL, NULL);
/* cpuset refresh routine should be here */
}
vm_total_pages = nr_free_pagecache_pages();
pgd_t *pgd;
unsigned long next;
int err = 0;
- struct vm_area_struct *vma;
if (addr >= end)
return err;
pgd = pgd_offset(walk->mm, addr);
do {
+ struct vm_area_struct *uninitialized_var(vma);
+
next = pgd_addr_end(addr, end);
+#ifdef CONFIG_HUGETLB_PAGE
/*
* handle hugetlb vma individually because pagetable walk for
* the hugetlb page is dependent on the architecture and
* we can't handled it in the same manner as non-huge pages.
*/
vma = find_vma(walk->mm, addr);
-#ifdef CONFIG_HUGETLB_PAGE
if (vma && is_vm_hugetlb_page(vma)) {
if (vma->vm_end < next)
next = vma->vm_end;
for_each_free_object(p, s, page->freelist) {
set_bit(slab_index(p, s, addr), map);
- if (!check_object(s, page, p, 0))
+ if (!check_object(s, page, p, SLUB_RED_INACTIVE))
return 0;
}
for_each_object(p, s, addr, page->objects)
if (!test_bit(slab_index(p, s, addr), map))
- if (!check_object(s, page, p, 1))
+ if (!check_object(s, page, p, SLUB_RED_ACTIVE))
return 0;
return 1;
}
__remove_from_page_cache(page);
spin_unlock_irq(&mapping->tree_lock);
mem_cgroup_uncharge_cache_page(page);
+
+ if (mapping->a_ops->freepage)
+ mapping->a_ops->freepage(page);
+
page_cache_release(page); /* pagecache ref */
return 1;
failed:
#include <asm/tlbflush.h>
#include <asm/shmparam.h>
-bool vmap_lazy_unmap __read_mostly = true;
-
/*** Page table manipulation functions ***/
static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end)
{
unsigned int log;
- if (!vmap_lazy_unmap)
- return 0;
-
log = fls(num_online_cpus());
return log * (32UL * 1024 * 1024 / PAGE_SIZE);
if (va->va_end > *end)
*end = va->va_end;
nr += (va->va_end - va->va_start) >> PAGE_SHIFT;
- unmap_vmap_area(va);
list_add_tail(&va->purge_list, &valist);
va->flags |= VM_LAZY_FREEING;
va->flags &= ~VM_LAZY_FREE;
}
/*
- * Free and unmap a vmap area, caller ensuring flush_cache_vunmap had been
- * called for the correct range previously.
+ * Free a vmap area, caller ensuring that the area has been unmapped
+ * and flush_cache_vunmap had been called for the correct range
+ * previously.
*/
-static void free_unmap_vmap_area_noflush(struct vmap_area *va)
+static void free_vmap_area_noflush(struct vmap_area *va)
{
va->flags |= VM_LAZY_FREE;
atomic_add((va->va_end - va->va_start) >> PAGE_SHIFT, &vmap_lazy_nr);
try_purge_vmap_area_lazy();
}
+/*
+ * Free and unmap a vmap area, caller ensuring flush_cache_vunmap had been
+ * called for the correct range previously.
+ */
+static void free_unmap_vmap_area_noflush(struct vmap_area *va)
+{
+ unmap_vmap_area(va);
+ free_vmap_area_noflush(va);
+}
+
/*
* Free and unmap a vmap area
*/
spin_unlock(&vmap_block_tree_lock);
BUG_ON(tmp != vb);
- free_unmap_vmap_area_noflush(vb->va);
+ free_vmap_area_noflush(vb->va);
call_rcu(&vb->rcu_head, rcu_free_vb);
}
rcu_read_unlock();
BUG_ON(!vb);
+ vunmap_page_range((unsigned long)addr, (unsigned long)addr + size);
+
spin_lock(&vb->lock);
BUG_ON(bitmap_allocate_region(vb->dirty_map, offset >> PAGE_SHIFT, order));
s = vb->va->va_start + (i << PAGE_SHIFT);
e = vb->va->va_start + (j << PAGE_SHIFT);
- vunmap_page_range(s, e);
flush = 1;
if (s < start)
spin_unlock_irq(&mapping->tree_lock);
swapcache_free(swap, page);
} else {
+ void (*freepage)(struct page *);
+
+ freepage = mapping->a_ops->freepage;
+
__remove_from_page_cache(page);
spin_unlock_irq(&mapping->tree_lock);
mem_cgroup_uncharge_cache_page(page);
+
+ if (freepage != NULL)
+ freepage(page);
}
return 1;
"nr_shmem",
"nr_dirtied",
"nr_written",
- "nr_dirty_threshold",
- "nr_dirty_background_threshold",
#ifdef CONFIG_NUMA
"numa_hit",
"numa_local",
"numa_other",
#endif
+ "nr_dirty_threshold",
+ "nr_dirty_background_threshold",
#ifdef CONFIG_VM_EVENT_COUNTERS
"pgpgin",
.dev_uevent = atm_uevent,
};
-int atm_register_sysfs(struct atm_dev *adev)
+int atm_register_sysfs(struct atm_dev *adev, struct device *parent)
{
struct device *cdev = &adev->class_dev;
int i, j, err;
cdev->class = &atm_class;
+ cdev->parent = parent;
dev_set_drvdata(cdev, adev);
dev_set_name(cdev, "%s%d", adev->type, adev->number);
}
EXPORT_SYMBOL(atm_dev_lookup);
-struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
- int number, unsigned long *flags)
+struct atm_dev *atm_dev_register(const char *type, struct device *parent,
+ const struct atmdev_ops *ops, int number,
+ unsigned long *flags)
{
struct atm_dev *dev, *inuse;
goto out_fail;
}
- if (atm_register_sysfs(dev) < 0) {
+ if (atm_register_sysfs(dev, parent) < 0) {
pr_err("atm_register_sysfs failed for dev %s\n", type);
atm_proc_dev_deregister(dev);
goto out_fail;
#endif /* CONFIG_PROC_FS */
-int atm_register_sysfs(struct atm_dev *adev);
+int atm_register_sysfs(struct atm_dev *adev, struct device *parent);
void atm_unregister_sysfs(struct atm_dev *adev);
#endif
int lm = 0;
if (type != SCO_LINK && type != ESCO_LINK)
- return 0;
+ return -EINVAL;
BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
- return 0;
+ return -EINVAL;
if (!status) {
struct sco_conn *conn;
BT_DBG("hcon %p reason %d", hcon, reason);
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
- return 0;
+ return -EINVAL;
sco_conn_del(hcon, bt_err(reason));
#
# Makefile for CEPH filesystem.
#
-
-ifneq ($(KERNELRELEASE),)
-
obj-$(CONFIG_CEPH_LIB) += libceph.o
libceph-objs := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \
ceph_fs.o ceph_strings.o ceph_hash.o \
pagevec.o
-else
-#Otherwise we were called directly from the command
-# line; invoke the kernel build system.
-
-KERNELDIR ?= /lib/modules/$(shell uname -r)/build
-PWD := $(shell pwd)
-
-default: all
-
-all:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_LIB=m modules
-
-modules_install:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_LIB=m modules_install
-
-clean:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
-
-endif
if (b->vec.iov_base) {
b->is_vmalloc = false;
} else {
- b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL);
+ b->vec.iov_base = __vmalloc(len, gfp | __GFP_HIGHMEM, PAGE_KERNEL);
if (!b->vec.iov_base) {
kfree(b);
return NULL;
/* initialize page iterator */
con->out_msg_pos.page = 0;
if (m->pages)
- con->out_msg_pos.page_pos =
- le16_to_cpu(m->hdr.data_off) & ~PAGE_MASK;
+ con->out_msg_pos.page_pos = m->page_alignment;
else
con->out_msg_pos.page_pos = 0;
con->out_msg_pos.data_pos = 0;
struct ceph_msg *m = con->in_msg;
int ret;
int to, left;
- unsigned front_len, middle_len, data_len, data_off;
+ unsigned front_len, middle_len, data_len;
int datacrc = con->msgr->nocrc;
int skip;
u64 seq;
data_len = le32_to_cpu(con->in_hdr.data_len);
if (data_len > CEPH_MSG_MAX_DATA_LEN)
return -EIO;
- data_off = le16_to_cpu(con->in_hdr.data_off);
/* verify seq# */
seq = le64_to_cpu(con->in_hdr.seq);
if ((s64)seq - (s64)con->in_seq < 1) {
- pr_info("skipping %s%lld %s seq %lld, expected %lld\n",
+ pr_info("skipping %s%lld %s seq %lld expected %lld\n",
ENTITY_NAME(con->peer_name),
ceph_pr_addr(&con->peer_addr.in_addr),
seq, con->in_seq + 1);
con->in_base_pos = -front_len - middle_len - data_len -
sizeof(m->footer);
con->in_tag = CEPH_MSGR_TAG_READY;
- con->in_seq++;
return 0;
} else if ((s64)seq - (s64)con->in_seq > 1) {
pr_err("read_partial_message bad seq %lld expected %lld\n",
con->in_msg_pos.page = 0;
if (m->pages)
- con->in_msg_pos.page_pos = data_off & ~PAGE_MASK;
+ con->in_msg_pos.page_pos = m->page_alignment;
else
con->in_msg_pos.page_pos = 0;
con->in_msg_pos.data_pos = 0;
/* data */
m->nr_pages = 0;
+ m->page_alignment = 0;
m->pages = NULL;
m->pagelist = NULL;
m->bio = NULL;
type, front_len);
return NULL;
}
+ msg->page_alignment = le16_to_cpu(hdr->data_off);
}
memcpy(&msg->hdr, &con->in_hdr, sizeof(con->in_hdr));
op->extent.length = objlen;
}
req->r_num_pages = calc_pages_for(off, *plen);
+ req->r_page_alignment = off & ~PAGE_MASK;
if (op->op == CEPH_OSD_OP_WRITE)
op->payload_len = *plen;
req->r_request->hdr.data_len = cpu_to_le32(data_len);
}
+ req->r_request->page_alignment = req->r_page_alignment;
+
BUG_ON(p > msg->front.iov_base + msg->front.iov_len);
msg_size = p - msg->front.iov_base;
msg->front.iov_len = msg_size;
u32 truncate_seq,
u64 truncate_size,
struct timespec *mtime,
- bool use_mempool, int num_reply)
+ bool use_mempool, int num_reply,
+ int page_align)
{
struct ceph_osd_req_op ops[3];
struct ceph_osd_request *req;
calc_layout(osdc, vino, layout, off, plen, req, ops);
req->r_file_layout = *layout; /* keep a copy */
+ /* in case it differs from natural alignment that calc_layout
+ filled in for us */
+ req->r_page_alignment = page_align;
+
ceph_osdc_build_request(req, off, plen, ops,
snapc,
mtime,
struct ceph_vino vino, struct ceph_file_layout *layout,
u64 off, u64 *plen,
u32 truncate_seq, u64 truncate_size,
- struct page **pages, int num_pages)
+ struct page **pages, int num_pages, int page_align)
{
struct ceph_osd_request *req;
int rc = 0;
req = ceph_osdc_new_request(osdc, layout, vino, off, plen,
CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ,
NULL, 0, truncate_seq, truncate_size, NULL,
- false, 1);
+ false, 1, page_align);
if (!req)
return -ENOMEM;
/* it may be a short read due to an object boundary */
req->r_pages = pages;
- dout("readpages final extent is %llu~%llu (%d pages)\n",
- off, *plen, req->r_num_pages);
+ dout("readpages final extent is %llu~%llu (%d pages align %d)\n",
+ off, *plen, req->r_num_pages, page_align);
rc = ceph_osdc_start_request(osdc, req, false);
if (!rc)
{
struct ceph_osd_request *req;
int rc = 0;
+ int page_align = off & ~PAGE_MASK;
BUG_ON(vino.snap != CEPH_NOSNAP);
req = ceph_osdc_new_request(osdc, layout, vino, off, &len,
CEPH_OSD_FLAG_WRITE,
snapc, do_sync,
truncate_seq, truncate_size, mtime,
- nofail, 1);
+ nofail, 1, page_align);
if (!req)
return -ENOMEM;
m = ceph_msg_get(req->r_reply);
if (data_len > 0) {
- unsigned data_off = le16_to_cpu(hdr->data_off);
- int want = calc_pages_for(data_off & ~PAGE_MASK, data_len);
+ int want = calc_pages_for(req->r_page_alignment, data_len);
if (unlikely(req->r_num_pages < want)) {
pr_warning("tid %lld reply %d > expected %d pages\n",
}
m->pages = req->r_pages;
m->nr_pages = req->r_num_pages;
+ m->page_alignment = req->r_page_alignment;
#ifdef CONFIG_BLOCK
m->bio = req->r_bio;
#endif
* build a vector of user pages
*/
struct page **ceph_get_direct_page_vector(const char __user *data,
- int num_pages,
- loff_t off, size_t len)
+ int num_pages)
{
struct page **pages;
int rc;
EXPORT_SYMBOL(sk_chk_filter);
/**
- * sk_filter_rcu_release: Release a socket filter by rcu_head
+ * sk_filter_release_rcu - Release a socket filter by rcu_head
* @rcu: rcu_head that contains the sk_filter to free
*/
-static void sk_filter_rcu_release(struct rcu_head *rcu)
+void sk_filter_release_rcu(struct rcu_head *rcu)
{
struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
- sk_filter_release(fp);
-}
-
-static void sk_filter_delayed_uncharge(struct sock *sk, struct sk_filter *fp)
-{
- unsigned int size = sk_filter_len(fp);
-
- atomic_sub(size, &sk->sk_omem_alloc);
- call_rcu_bh(&fp->rcu, sk_filter_rcu_release);
+ kfree(fp);
}
+EXPORT_SYMBOL(sk_filter_release_rcu);
/**
* sk_attach_filter - attach a socket filter
rcu_assign_pointer(sk->sk_filter, fp);
if (old_fp)
- sk_filter_delayed_uncharge(sk, old_fp);
+ sk_filter_uncharge(sk, old_fp);
return 0;
}
EXPORT_SYMBOL_GPL(sk_attach_filter);
sock_owned_by_user(sk));
if (filter) {
rcu_assign_pointer(sk->sk_filter, NULL);
- sk_filter_delayed_uncharge(sk, filter);
+ sk_filter_uncharge(sk, filter);
ret = 0;
}
return ret;
map = rcu_dereference_raw(queue->rps_map);
- if (map)
+ if (map) {
+ RCU_INIT_POINTER(queue->rps_map, NULL);
call_rcu(&map->rcu, rps_map_release);
+ }
flow_table = rcu_dereference_raw(queue->rps_flow_table);
- if (flow_table)
+ if (flow_table) {
+ RCU_INIT_POINTER(queue->rps_flow_table, NULL);
call_rcu(&flow_table->rcu, rps_dev_flow_table_release);
+ }
if (atomic_dec_and_test(&first->count))
kfree(first);
+ else
+ memset(kobj, 0, sizeof(*kobj));
}
static struct kobj_type rx_queue_ktype = {
nr_table_entries = roundup_pow_of_two(nr_table_entries + 1);
lopt_size += nr_table_entries * sizeof(struct request_sock *);
if (lopt_size > PAGE_SIZE)
- lopt = __vmalloc(lopt_size,
- GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
- PAGE_KERNEL);
+ lopt = vzalloc(lopt_size);
else
lopt = kzalloc(lopt_size, GFP_KERNEL);
if (lopt == NULL)
struct phy_device *phydev;
unsigned int type;
- skb_push(skb, ETH_HLEN);
+ if (skb_headroom(skb) < ETH_HLEN)
+ return false;
+ __skb_push(skb, ETH_HLEN);
type = classify(skb);
- skb_pull(skb, ETH_HLEN);
+ __skb_pull(skb, ETH_HLEN);
switch (type) {
case PTP_CLASS_V1_IPV4:
dccp_update_gsr(sk, seqno);
if (dh->dccph_type != DCCP_PKT_SYNC &&
- (ackno != DCCP_PKT_WITHOUT_ACK_SEQ))
+ ackno != DCCP_PKT_WITHOUT_ACK_SEQ &&
+ after48(ackno, dp->dccps_gar))
dp->dccps_gar = ackno;
} else {
unsigned long now = jiffies;
if (r_len > sizeof(struct linkinfo_dn))
r_len = sizeof(struct linkinfo_dn);
+ memset(&link, 0, sizeof(link));
+
switch(sock->state) {
case SS_CONNECTING:
link.idn_linkstate = LL_CONNECTING;
#include <linux/skbuff.h>
#include <linux/udp.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <net/sock.h>
#include <net/inet_common.h>
#include <linux/stat.h>
#endif
#ifdef CONFIG_ECONET_AUNUDP
struct msghdr udpmsg;
- struct iovec iov[msg->msg_iovlen+1];
+ struct iovec iov[2];
struct aunhdr ah;
struct sockaddr_in udpdest;
__kernel_size_t size;
- int i;
mm_segment_t oldfs;
+ char *userbuf;
#endif
/*
mutex_lock(&econet_mutex);
- if (saddr == NULL) {
- struct econet_sock *eo = ec_sk(sk);
-
- addr.station = eo->station;
- addr.net = eo->net;
- port = eo->port;
- cb = eo->cb;
- } else {
- if (msg->msg_namelen < sizeof(struct sockaddr_ec)) {
- mutex_unlock(&econet_mutex);
- return -EINVAL;
- }
- addr.station = saddr->addr.station;
- addr.net = saddr->addr.net;
- port = saddr->port;
- cb = saddr->cb;
- }
+ if (saddr == NULL || msg->msg_namelen < sizeof(struct sockaddr_ec)) {
+ mutex_unlock(&econet_mutex);
+ return -EINVAL;
+ }
+ addr.station = saddr->addr.station;
+ addr.net = saddr->addr.net;
+ port = saddr->port;
+ cb = saddr->cb;
/* Look for a device with the right network number. */
dev = net2dev_map[addr.net];
}
}
- if (len + 15 > dev->mtu) {
- mutex_unlock(&econet_mutex);
- return -EMSGSIZE;
- }
-
if (dev->type == ARPHRD_ECONET) {
/* Real hardware Econet. We're not worthy etc. */
#ifdef CONFIG_ECONET_NATIVE
unsigned short proto = 0;
int res;
+ if (len + 15 > dev->mtu) {
+ mutex_unlock(&econet_mutex);
+ return -EMSGSIZE;
+ }
+
dev_hold(dev);
skb = sock_alloc_send_skb(sk, len+LL_ALLOCATED_SPACE(dev),
eb = (struct ec_cb *)&skb->cb;
- /* BUG: saddr may be NULL */
eb->cookie = saddr->cookie;
eb->sec = *saddr;
eb->sent = ec_tx_done;
return -ENETDOWN; /* No socket - can't send */
}
+ if (len > 32768) {
+ err = -E2BIG;
+ goto error;
+ }
+
/* Make up a UDP datagram and hand it off to some higher intellect. */
memset(&udpdest, 0, sizeof(udpdest));
/* tack our header on the front of the iovec */
size = sizeof(struct aunhdr);
- /*
- * XXX: that is b0rken. We can't mix userland and kernel pointers
- * in iovec, since on a lot of platforms copy_from_user() will
- * *not* work with the kernel and userland ones at the same time,
- * regardless of what we do with set_fs(). And we are talking about
- * econet-over-ethernet here, so "it's only ARM anyway" doesn't
- * apply. Any suggestions on fixing that code? -- AV
- */
iov[0].iov_base = (void *)&ah;
iov[0].iov_len = size;
- for (i = 0; i < msg->msg_iovlen; i++) {
- void __user *base = msg->msg_iov[i].iov_base;
- size_t iov_len = msg->msg_iov[i].iov_len;
- /* Check it now since we switch to KERNEL_DS later. */
- if (!access_ok(VERIFY_READ, base, iov_len)) {
- mutex_unlock(&econet_mutex);
- return -EFAULT;
- }
- iov[i+1].iov_base = base;
- iov[i+1].iov_len = iov_len;
- size += iov_len;
+
+ userbuf = vmalloc(len);
+ if (userbuf == NULL) {
+ err = -ENOMEM;
+ goto error;
}
+ iov[1].iov_base = userbuf;
+ iov[1].iov_len = len;
+ err = memcpy_fromiovec(userbuf, msg->msg_iov, len);
+ if (err)
+ goto error_free_buf;
+
/* Get a skbuff (no data, just holds our cb information) */
if ((skb = sock_alloc_send_skb(sk, 0,
msg->msg_flags & MSG_DONTWAIT,
- &err)) == NULL) {
- mutex_unlock(&econet_mutex);
- return err;
- }
+ &err)) == NULL)
+ goto error_free_buf;
eb = (struct ec_cb *)&skb->cb;
udpmsg.msg_name = (void *)&udpdest;
udpmsg.msg_namelen = sizeof(udpdest);
udpmsg.msg_iov = &iov[0];
- udpmsg.msg_iovlen = msg->msg_iovlen + 1;
+ udpmsg.msg_iovlen = 2;
udpmsg.msg_control = NULL;
udpmsg.msg_controllen = 0;
udpmsg.msg_flags=0;
oldfs = get_fs(); set_fs(KERNEL_DS); /* More privs :-) */
err = sock_sendmsg(udpsock, &udpmsg, size);
set_fs(oldfs);
+
+error_free_buf:
+ vfree(userbuf);
#else
err = -EPROTOTYPE;
#endif
+ error:
mutex_unlock(&econet_mutex);
return err;
err = 0;
switch (cmd) {
case SIOCSIFADDR:
+ if (!capable(CAP_NET_ADMIN)) {
+ err = -EPERM;
+ break;
+ }
+
edev = dev->ec_ptr;
if (edev == NULL) {
/* Magic up a new one. */
{
struct iphdr *ip = ip_hdr(skb);
unsigned char stn = ntohl(ip->saddr) & 0xff;
+ struct dst_entry *dst = skb_dst(skb);
+ struct ec_device *edev = NULL;
struct sock *sk = NULL;
struct sk_buff *newskb;
- struct ec_device *edev = skb->dev->ec_ptr;
+
+ if (dst)
+ edev = dst->dev->ec_ptr;
if (! edev)
goto bad;
if (size <= PAGE_SIZE)
return kzalloc(size, GFP_KERNEL);
else
- return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+ return vzalloc(size);
}
static void __tnode_vfree(struct work_struct *arg)
/* No need to clone since we're just using its address. */
rt2 = rt;
+ if (!fl.nl_u.ip4_u.saddr)
+ fl.nl_u.ip4_u.saddr = rt->rt_src;
+
err = xfrm_lookup(net, (struct dst_entry **)&rt, &fl, NULL, 0);
switch (err) {
case 0:
}
}
}
- sk_add_bind_node(child, &tb->owners);
- inet_csk(child)->icsk_bind_hash = tb;
+ inet_bind_hash(child, tb, port);
spin_unlock(&head->lock);
return 0;
SNMP_MIB_ITEM("TCPMinTTLDrop", LINUX_MIB_TCPMINTTLDROP),
SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
+ SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW),
SNMP_MIB_SENTINEL
};
static int tcp_retr1_max = 255;
static int ip_local_port_range_min[] = { 1, 1 };
static int ip_local_port_range_max[] = { 65535, 65535 };
+static int tcp_adv_win_scale_min = -31;
+static int tcp_adv_win_scale_max = 31;
/* Update system visible IP port range */
static void set_local_port_range(int range[2])
.data = &sysctl_tcp_adv_win_scale,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = proc_dointvec
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &tcp_adv_win_scale_min,
+ .extra2 = &tcp_adv_win_scale_max,
},
{
.procname = "tcp_tw_reuse",
/* Values greater than interface MTU won't take effect. However
* at the point when this call is done we typically don't yet
* know which interface is going to be used */
- if (val < 64 || val > MAX_TCP_WINDOW) {
+ if (val < TCP_MIN_MSS || val > MAX_TCP_WINDOW) {
err = -EINVAL;
break;
}
}
get_sk:
sk_nulls_for_each_from(sk, node) {
- if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) {
+ if (!net_eq(sock_net(sk), net))
+ continue;
+ if (sk->sk_family == st->family) {
cur = sk;
goto out;
}
* socket up. We've got bigger problems than
* non-graceful socket closings.
*/
- LIMIT_NETDEBUG(KERN_INFO "TCP: time wait bucket table overflow\n");
+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPTIMEWAITOVERFLOW);
}
tcp_update_metrics(sk);
/* when initializing use the value from init_rcv_wnd
* rather than the default from above
*/
- if (init_rcv_wnd &&
- (*rcv_wnd > init_rcv_wnd * mss))
- *rcv_wnd = init_rcv_wnd * mss;
- else if (*rcv_wnd > init_cwnd * mss)
- *rcv_wnd = init_cwnd * mss;
+ if (init_rcv_wnd)
+ *rcv_wnd = min(*rcv_wnd, init_rcv_wnd * mss);
+ else
+ *rcv_wnd = min(*rcv_wnd, init_cwnd * mss);
}
/* Set the clamp no higher than max representable value */
*/
static u8 tcp_cookie_size_check(u8 desired)
{
- if (desired > 0) {
+ int cookie_size;
+
+ if (desired > 0)
/* previously specified */
return desired;
- }
- if (sysctl_tcp_cookie_size <= 0) {
+
+ cookie_size = ACCESS_ONCE(sysctl_tcp_cookie_size);
+ if (cookie_size <= 0)
/* no default specified */
return 0;
- }
- if (sysctl_tcp_cookie_size <= TCP_COOKIE_MIN) {
+
+ if (cookie_size <= TCP_COOKIE_MIN)
/* value too small, specify minimum */
return TCP_COOKIE_MIN;
- }
- if (sysctl_tcp_cookie_size >= TCP_COOKIE_MAX) {
+
+ if (cookie_size >= TCP_COOKIE_MAX)
/* value too large, specify maximum */
return TCP_COOKIE_MAX;
- }
- if (0x1 & sysctl_tcp_cookie_size) {
+
+ if (cookie_size & 1)
/* 8-bit multiple, illegal, fix it */
- return (u8)(sysctl_tcp_cookie_size + 0x1);
- }
- return (u8)sysctl_tcp_cookie_size;
+ cookie_size++;
+
+ return (u8)cookie_size;
}
/* Write previously computed TCP options to the packet.
struct tcp_sock *tp = tcp_sk(sk);
const struct inet_connection_sock *icsk = inet_csk(sk);
u32 send_win, cong_win, limit, in_flight;
+ int win_divisor;
if (TCP_SKB_CB(skb)->flags & TCPHDR_FIN)
goto send_now;
if ((skb != tcp_write_queue_tail(sk)) && (limit >= skb->len))
goto send_now;
- if (sysctl_tcp_tso_win_divisor) {
+ win_divisor = ACCESS_ONCE(sysctl_tcp_tso_win_divisor);
+ if (win_divisor) {
u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache);
/* If at least some fraction of a window is available,
* just use it.
*/
- chunk /= sysctl_tcp_tso_win_divisor;
+ chunk /= win_divisor;
if (limit >= chunk)
goto send_now;
} else {
#endif
#define INFINITY_LIFE_TIME 0xFFFFFFFF
-#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b)))
+
+static inline u32 cstamp_delta(unsigned long cstamp)
+{
+ return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
+}
#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1)
#define ADDRCONF_TIMER_FUZZ (HZ / 4)
ifa->state = INET6_IFADDR_STATE_DEAD;
spin_unlock_bh(&ifa->state_lock);
- if (state == INET6_IFADDR_STATE_DEAD) {
- in6_ifa_put(ifa);
- } else {
+ if (state != INET6_IFADDR_STATE_DEAD) {
__ipv6_ifa_notify(RTM_DELADDR, ifa);
atomic_notifier_call_chain(&inet6addr_chain,
NETDEV_DOWN, ifa);
}
+
+ in6_ifa_put(ifa);
write_lock_bh(&idev->lock);
}
}
{
struct ifa_cacheinfo ci;
- ci.cstamp = (u32)(TIME_DELTA(cstamp, INITIAL_JIFFIES) / HZ * 100
- + TIME_DELTA(cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
- ci.tstamp = (u32)(TIME_DELTA(tstamp, INITIAL_JIFFIES) / HZ * 100
- + TIME_DELTA(tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
+ ci.cstamp = cstamp_delta(cstamp);
+ ci.tstamp = cstamp_delta(tstamp);
ci.ifa_prefered = preferred;
ci.ifa_valid = valid;
array[DEVCONF_AUTOCONF] = cnf->autoconf;
array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits;
array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits;
- array[DEVCONF_RTR_SOLICIT_INTERVAL] = cnf->rtr_solicit_interval;
- array[DEVCONF_RTR_SOLICIT_DELAY] = cnf->rtr_solicit_delay;
+ array[DEVCONF_RTR_SOLICIT_INTERVAL] =
+ jiffies_to_msecs(cnf->rtr_solicit_interval);
+ array[DEVCONF_RTR_SOLICIT_DELAY] =
+ jiffies_to_msecs(cnf->rtr_solicit_delay);
array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version;
#ifdef CONFIG_IPV6_PRIVACY
array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr;
array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo;
#ifdef CONFIG_IPV6_ROUTER_PREF
array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref;
- array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval;
+ array[DEVCONF_RTR_PROBE_INTERVAL] =
+ jiffies_to_msecs(cnf->rtr_probe_interval);
#ifdef CONFIG_IPV6_ROUTE_INFO
array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
#endif
NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags);
ci.max_reasm_len = IPV6_MAXPLEN;
- ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100
- + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
- ci.reachable_time = idev->nd_parms->reachable_time;
- ci.retrans_time = idev->nd_parms->retrans_time;
+ ci.tstamp = cstamp_delta(idev->tstamp);
+ ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time);
+ ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time);
NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
kfree_skb(skb);
goto errout;
}
- rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+ rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFINFO, NULL, GFP_ATOMIC);
return;
errout:
if (err < 0)
- rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
+ rtnl_set_sk_err(net, RTNLGRP_IPV6_IFINFO, err);
}
static inline size_t inet6_prefix_nlmsg_size(void)
sizeof (struct ipv6hdr);
dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr);
+ if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+ dev->mtu-=8;
if (dev->mtu < IPV6_MIN_MTU)
dev->mtu = IPV6_MIN_MTU;
static void ip6_tnl_dev_setup(struct net_device *dev)
{
+ struct ip6_tnl *t;
+
dev->netdev_ops = &ip6_tnl_netdev_ops;
dev->destructor = ip6_dev_free;
dev->type = ARPHRD_TUNNEL6;
dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
+ t = netdev_priv(dev);
+ if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+ dev->mtu-=8;
dev->flags |= IFF_NOARP;
dev->addr_len = sizeof(struct in6_addr);
dev->features |= NETIF_F_NETNS_LOCAL;
return 0;
}
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+ /* no tunnel matched, let upstream know, ipsec may handle it */
rcu_read_unlock();
+ return 1;
out:
kfree_skb(skb);
return 0;
#include <linux/capability.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/smp_lock.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include "irnet_ppp.h" /* Private header */
/* Please put other headers in irnet.h - Thanks */
*/
int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb)
{
+ int ret;
+
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
IRDA_DEBUG(4, "%s()\n", __func__);
+ /* Take shortcut on zero byte packets */
+ if (skb->len == 0) {
+ ret = 0;
+ goto err;
+ }
+
/* Check that nothing bad happens */
- if ((skb->len == 0) || (!self->connected)) {
- IRDA_DEBUG(1, "%s(), No data, or not connected\n",
- __func__);
+ if (!self->connected) {
+ IRDA_WARNING("%s(), Not connected\n", __func__);
+ ret = -ENOTCONN;
goto err;
}
if (skb->len > self->max_seg_size) {
- IRDA_DEBUG(1, "%s(), UData is too large for IrLAP!\n",
- __func__);
+ IRDA_ERROR("%s(), UData is too large for IrLAP!\n", __func__);
+ ret = -EMSGSIZE;
goto err;
}
err:
dev_kfree_skb(skb);
- return -1;
+ return ret;
}
EXPORT_SYMBOL(irttp_udata_request);
IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__,
skb_queue_len(&self->tx_queue));
+ /* Take shortcut on zero byte packets */
+ if (skb->len == 0) {
+ ret = 0;
+ goto err;
+ }
+
/* Check that nothing bad happens */
- if ((skb->len == 0) || (!self->connected)) {
- IRDA_WARNING("%s: No data, or not connected\n", __func__);
+ if (!self->connected) {
+ IRDA_WARNING("%s: Not connected\n", __func__);
ret = -ENOTCONN;
goto err;
}
MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
MODULE_DESCRIPTION("L2TP over IP");
MODULE_VERSION("1.0");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, SOCK_DGRAM, IPPROTO_L2TP);
+
+/* Use the value of SOCK_DGRAM (2) directory, because __stringify does't like
+ * enums
+ */
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP);
goto out;
rc = -ENODEV;
rtnl_lock();
+ rcu_read_lock();
if (sk->sk_bound_dev_if) {
- llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
+ llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if);
if (llc->dev) {
if (!addr->sllc_arphrd)
addr->sllc_arphrd = llc->dev->type;
!llc_mac_match(addr->sllc_mac,
llc->dev->dev_addr)) {
rc = -EINVAL;
- dev_put(llc->dev);
llc->dev = NULL;
}
}
} else
llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd,
addr->sllc_mac);
+ rcu_read_unlock();
rtnl_unlock();
if (!llc->dev)
goto out;
config MAC80211_LEDS
bool "Enable LED triggers"
depends on MAC80211
- select NEW_LEDS
+ depends on LEDS_CLASS
select LEDS_TRIGGERS
---help---
This option enables a few LED triggers for different
break;
case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+ if (is_multicast_ether_addr(mgmt->da) &&
+ !is_broadcast_ether_addr(mgmt->da))
+ return RX_DROP_MONITOR;
+
/* process only for station */
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return RX_DROP_MONITOR;
if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
return;
+ goto out;
}
}
return;
}
+ out:
dev_kfree_skb(skb);
}
list) {
if (!ieee80211_sdata_running(tmp_sdata))
continue;
- if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
+ if (tmp_sdata->vif.type ==
+ NL80211_IFTYPE_MONITOR ||
+ tmp_sdata->vif.type ==
+ NL80211_IFTYPE_AP_VLAN ||
+ tmp_sdata->vif.type ==
+ NL80211_IFTYPE_WDS)
continue;
if (compare_ether_addr(tmp_sdata->vif.addr,
hdr->addr2) == 0) {
int nh_pos, h_pos;
struct sta_info *sta = NULL;
u32 sta_flags = 0;
+ struct sk_buff *tmp_skb;
if (unlikely(skb->len < ETH_HLEN)) {
ret = NETDEV_TX_OK;
goto fail;
}
- nh_pos = skb_network_header(skb) - skb->data;
- h_pos = skb_transport_header(skb) - skb->data;
-
/* convert Ethernet header to proper 802.11 header (based on
* operation mode) */
ethertype = (skb->data[12] << 8) | skb->data[13];
goto fail;
}
+ /*
+ * If the skb is shared we need to obtain our own copy.
+ */
+ if (skb_shared(skb)) {
+ tmp_skb = skb;
+ skb = skb_copy(skb, GFP_ATOMIC);
+ kfree_skb(tmp_skb);
+
+ if (!skb) {
+ ret = NETDEV_TX_OK;
+ goto fail;
+ }
+ }
+
hdr.frame_control = fc;
hdr.duration_id = 0;
hdr.seq_ctrl = 0;
encaps_len = 0;
}
+ nh_pos = skb_network_header(skb) - skb->data;
+ h_pos = skb_transport_header(skb) - skb->data;
+
skb_pull(skb, skip_header_bytes);
nh_pos -= skip_header_bytes;
h_pos -= skip_header_bytes;
menuconfig IP_VS
tristate "IP virtual server support"
depends on NET && INET && NETFILTER
+ depends on (NF_CONNTRACK || NF_CONNTRACK=n)
---help---
IP Virtual Server support will let you build a high-performance
virtual server based on cluster of two or more real servers. This
goto out;
}
- if (args->nr_local > (u64)UINT_MAX) {
+ if (args->nr_local > UIO_MAXIOV) {
ret = -EMSGSIZE;
goto out;
}
struct sctp_association *asoc = NULL;
struct sctp_setpeerprim prim;
struct sctp_chunk *chunk;
+ struct sctp_af *af;
int err;
sp = sctp_sk(sk);
if (!sctp_state(asoc, ESTABLISHED))
return -ENOTCONN;
+ af = sctp_get_af_specific(prim.sspp_addr.ss_family);
+ if (!af)
+ return -EINVAL;
+
+ if (!af->addr_valid((union sctp_addr *)&prim.sspp_addr, sp, NULL))
+ return -EADDRNOTAVAIL;
+
if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr))
return -EADDRNOTAVAIL;
return ret;
}
+/**
+ * kernel_recvmsg - Receive a message from a socket (kernel space)
+ * @sock: The socket to receive the message from
+ * @msg: Received message
+ * @vec: Input s/g array for message data
+ * @num: Size of input s/g array
+ * @size: Number of bytes to read
+ * @flags: Message flags (MSG_DONTWAIT, etc...)
+ *
+ * On return the msg structure contains the scatter/gather array passed in the
+ * vec argument. The array is modified so that it consists of the unfilled
+ * portion of the original array.
+ *
+ * The returned value is the total number of bytes received, or an error.
+ */
int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size, int flags)
{
dprint_status(task);
task->tk_status = 0;
- task->tk_action = call_allocate;
- if (status >= 0 && rpcauth_uptodatecred(task))
- return;
+ task->tk_action = call_refresh;
switch (status) {
- case -EACCES:
- rpc_exit(task, -EACCES);
- return;
- case -ENOMEM:
- rpc_exit(task, -ENOMEM);
+ case 0:
+ if (rpcauth_uptodatecred(task))
+ task->tk_action = call_allocate;
return;
case -ETIMEDOUT:
rpc_delay(task, 3*HZ);
+ case -EAGAIN:
+ status = -EACCES;
+ if (!task->tk_cred_retry)
+ break;
+ task->tk_cred_retry--;
+ dprintk("RPC: %5u %s: retry refresh creds\n",
+ task->tk_pid, __func__);
+ return;
}
- task->tk_action = call_refresh;
+ dprintk("RPC: %5u %s: refresh creds failed with error %d\n",
+ task->tk_pid, __func__, status);
+ rpc_exit(task, status);
}
/*
*/
struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
{
- struct rpc_iostats *new;
- new = kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
- return new;
+ return kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(rpc_alloc_iostats);
*/
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
spin_lock(&svc_xprt_class_lock);
list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
struct svc_xprt *newxprt;
+ unsigned short newport;
if (strcmp(xprt_name, xcl->xcl_name))
continue;
spin_lock_bh(&serv->sv_lock);
list_add(&newxprt->xpt_list, &serv->sv_permsocks);
spin_unlock_bh(&serv->sv_lock);
+ newport = svc_xprt_local_port(newxprt);
clear_bit(XPT_BUSY, &newxprt->xpt_flags);
- return svc_xprt_local_port(newxprt);
+ return newport;
}
err:
spin_unlock(&svc_xprt_class_lock);
{
BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
xprt->xpt_pool = NULL;
+ /* As soon as we clear busy, the xprt could be closed and
+ * 'put', so we need a reference to call svc_xprt_enqueue with:
+ */
+ svc_xprt_get(xprt);
clear_bit(XPT_BUSY, &xprt->xpt_flags);
svc_xprt_enqueue(xprt);
+ svc_xprt_put(xprt);
}
EXPORT_SYMBOL_GPL(svc_xprt_received);
sock_wfree(skb);
}
+#define MAX_RECURSION_LEVEL 4
+
static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
{
int i;
+ unsigned char max_level = 0;
+ int unix_sock_count = 0;
+
+ for (i = scm->fp->count - 1; i >= 0; i--) {
+ struct sock *sk = unix_get_socket(scm->fp->fp[i]);
+
+ if (sk) {
+ unix_sock_count++;
+ max_level = max(max_level,
+ unix_sk(sk)->recursion_level);
+ }
+ }
+ if (unlikely(max_level > MAX_RECURSION_LEVEL))
+ return -ETOOMANYREFS;
/*
* Need to duplicate file references for the sake of garbage
if (!UNIXCB(skb).fp)
return -ENOMEM;
- for (i = scm->fp->count-1; i >= 0; i--)
- unix_inflight(scm->fp->fp[i]);
- return 0;
+ if (unix_sock_count) {
+ for (i = scm->fp->count - 1; i >= 0; i--)
+ unix_inflight(scm->fp->fp[i]);
+ }
+ return max_level;
}
static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
struct sk_buff *skb;
long timeo;
struct scm_cookie tmp_scm;
+ int max_level;
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
goto out;
err = unix_scm_to_skb(siocb->scm, skb, true);
- if (err)
+ if (err < 0)
goto out_free;
+ max_level = err + 1;
unix_get_secdata(siocb->scm, skb);
skb_reset_transport_header(skb);
if (sock_flag(other, SOCK_RCVTSTAMP))
__net_timestamp(skb);
skb_queue_tail(&other->sk_receive_queue, skb);
+ if (max_level > unix_sk(other)->recursion_level)
+ unix_sk(other)->recursion_level = max_level;
unix_state_unlock(other);
other->sk_data_ready(other, len);
sock_put(other);
int sent = 0;
struct scm_cookie tmp_scm;
bool fds_sent = false;
+ int max_level;
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
/* Only send the fds in the first buffer */
err = unix_scm_to_skb(siocb->scm, skb, !fds_sent);
- if (err) {
+ if (err < 0) {
kfree_skb(skb);
goto out_err;
}
+ max_level = err + 1;
fds_sent = true;
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
goto pipe_err_free;
skb_queue_tail(&other->sk_receive_queue, skb);
+ if (max_level > unix_sk(other)->recursion_level)
+ unix_sk(other)->recursion_level = max_level;
unix_state_unlock(other);
other->sk_data_ready(other, size);
sent += size;
unix_state_lock(sk);
skb = skb_dequeue(&sk->sk_receive_queue);
if (skb == NULL) {
+ unix_sk(sk)->recursion_level = 0;
if (copied >= target)
goto unlock;
unsigned int unix_tot_inflight;
-static struct sock *unix_get_socket(struct file *filp)
+struct sock *unix_get_socket(struct file *filp)
{
struct sock *u_sock = NULL;
struct inode *inode = filp->f_path.dentry->d_inode;
}
static bool gc_in_progress = false;
+#define UNIX_INFLIGHT_TRIGGER_GC 16000
void wait_for_unix_gc(void)
{
+ /*
+ * If number of inflight sockets is insane,
+ * force a garbage collect right now.
+ */
+ if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress)
+ unix_gc();
wait_event(unix_gc_wait, gc_in_progress == false);
}
return chan;
}
+static bool can_beacon_sec_chan(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct ieee80211_channel *sec_chan;
+ int diff;
+
+ switch (channel_type) {
+ case NL80211_CHAN_HT40PLUS:
+ diff = 20;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ diff = -20;
+ break;
+ default:
+ return false;
+ }
+
+ sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
+ if (!sec_chan)
+ return false;
+
+ /* we'll need a DFS capability later */
+ if (sec_chan->flags & (IEEE80211_CHAN_DISABLED |
+ IEEE80211_CHAN_PASSIVE_SCAN |
+ IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_RADAR))
+ return false;
+
+ return true;
+}
+
int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, int freq,
enum nl80211_channel_type channel_type)
if (!chan)
return -EINVAL;
+ /* Both channels should be able to initiate communication */
+ if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
+ wdev->iftype == NL80211_IFTYPE_AP ||
+ wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
+ wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
+ wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
+ switch (channel_type) {
+ case NL80211_CHAN_HT40PLUS:
+ case NL80211_CHAN_HT40MINUS:
+ if (!can_beacon_sec_chan(&rdev->wiphy, chan,
+ channel_type)) {
+ printk(KERN_DEBUG
+ "cfg80211: Secondary channel not "
+ "allowed to initiate communication\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
result = rdev->ops->set_channel(&rdev->wiphy,
wdev ? wdev->netdev : NULL,
chan, channel_type);
list_for_each_safe(entry, tmp, &x25_neigh_list) {
nb = list_entry(entry, struct x25_neigh, node);
__x25_remove_neigh(nb);
+ dev_put(nb->dev);
}
write_unlock_bh(&x25_neigh_list_lock);
}
if (sz <= PAGE_SIZE)
n = kzalloc(sz, GFP_KERNEL);
else if (hashdist)
- n = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+ n = vzalloc(sz);
else
n = (struct hlist_head *)
__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
return xc;
error:
- kfree(xc);
+ xfrm_state_put(xc);
return NULL;
}
EXPORT_SYMBOL(xfrm_state_migrate);
# Extract GFP flags from the kernel source
TMPFILE=`mktemp -t gfptranslate-XXXXXX` || exit 1
-grep "^#define __GFP" $SOURCE/include/linux/gfp.h | sed -e 's/(__force gfp_t)//' | sed -e 's/u)/)/' | grep -v GFP_BITS | sed -e 's/)\//) \//' > $TMPFILE
+grep -q ___GFP $SOURCE/include/linux/gfp.h
+if [ $? -eq 0 ]; then
+ grep "^#define ___GFP" $SOURCE/include/linux/gfp.h | sed -e 's/u$//' | grep -v GFP_BITS > $TMPFILE
+else
+ grep "^#define __GFP" $SOURCE/include/linux/gfp.h | sed -e 's/(__force gfp_t)//' | sed -e 's/u)/)/' | grep -v GFP_BITS | sed -e 's/)\//) \//' > $TMPFILE
+fi
# Parse the flags
IFS="
struct menu *list;
struct symbol *sym;
struct property *prompt;
+ struct expr *visibility;
struct expr *dep;
unsigned int flags;
char *help;
void menu_add_entry(struct symbol *sym);
void menu_end_entry(void);
void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
return menu_add_prop(type, prompt, NULL, dep);
}
+void menu_add_visibility(struct expr *expr)
+{
+ current_entry->visibility = expr_alloc_and(current_entry->visibility,
+ expr);
+}
+
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
{
menu_add_prop(type, NULL, expr, dep);
if (!menu->prompt)
return false;
+ if (menu->visibility) {
+ if (expr_calc_value(menu->visibility) == no)
+ return no;
+ }
+
sym = menu->sym;
if (sym) {
sym_calc_value(sym);
string, T_TYPE, TF_COMMAND, S_STRING
select, T_SELECT, TF_COMMAND
range, T_RANGE, TF_COMMAND
+visible, T_VISIBLE, TF_COMMAND
option, T_OPTION, TF_COMMAND
on, T_ON, TF_PARAM
modules, T_OPT_MODULES, TF_OPTION
struct kconf_id;
static struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
-/* maximum key range = 47, duplicates = 0 */
+/* maximum key range = 50, duplicates = 0 */
#ifdef __GNUC__
__inline
{
static unsigned char asso_values[] =
{
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 11, 5,
- 0, 0, 5, 49, 5, 20, 49, 49, 5, 20,
- 5, 0, 30, 49, 0, 15, 0, 10, 0, 49,
- 25, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 40, 5,
+ 0, 0, 5, 52, 0, 20, 52, 52, 10, 20,
+ 5, 0, 35, 52, 0, 30, 0, 15, 0, 52,
+ 15, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52
};
register int hval = len;
char kconf_id_strings_str12[sizeof("default")];
char kconf_id_strings_str13[sizeof("def_bool")];
char kconf_id_strings_str14[sizeof("help")];
- char kconf_id_strings_str15[sizeof("bool")];
char kconf_id_strings_str16[sizeof("config")];
char kconf_id_strings_str17[sizeof("def_tristate")];
- char kconf_id_strings_str18[sizeof("boolean")];
+ char kconf_id_strings_str18[sizeof("hex")];
char kconf_id_strings_str19[sizeof("defconfig_list")];
- char kconf_id_strings_str21[sizeof("string")];
char kconf_id_strings_str22[sizeof("if")];
char kconf_id_strings_str23[sizeof("int")];
- char kconf_id_strings_str26[sizeof("select")];
char kconf_id_strings_str27[sizeof("modules")];
char kconf_id_strings_str28[sizeof("tristate")];
char kconf_id_strings_str29[sizeof("menu")];
- char kconf_id_strings_str31[sizeof("source")];
char kconf_id_strings_str32[sizeof("comment")];
- char kconf_id_strings_str33[sizeof("hex")];
char kconf_id_strings_str35[sizeof("menuconfig")];
- char kconf_id_strings_str36[sizeof("prompt")];
- char kconf_id_strings_str37[sizeof("depends")];
+ char kconf_id_strings_str36[sizeof("string")];
+ char kconf_id_strings_str37[sizeof("visible")];
+ char kconf_id_strings_str41[sizeof("prompt")];
+ char kconf_id_strings_str42[sizeof("depends")];
+ char kconf_id_strings_str44[sizeof("bool")];
+ char kconf_id_strings_str46[sizeof("select")];
+ char kconf_id_strings_str47[sizeof("boolean")];
char kconf_id_strings_str48[sizeof("mainmenu")];
+ char kconf_id_strings_str51[sizeof("source")];
};
static struct kconf_id_strings_t kconf_id_strings_contents =
{
"default",
"def_bool",
"help",
- "bool",
"config",
"def_tristate",
- "boolean",
+ "hex",
"defconfig_list",
- "string",
"if",
"int",
- "select",
"modules",
"tristate",
"menu",
- "source",
"comment",
- "hex",
"menuconfig",
+ "string",
+ "visible",
"prompt",
"depends",
- "mainmenu"
+ "bool",
+ "select",
+ "boolean",
+ "mainmenu",
+ "source"
};
#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
#ifdef __GNUC__
{
enum
{
- TOTAL_KEYWORDS = 31,
+ TOTAL_KEYWORDS = 32,
MIN_WORD_LENGTH = 2,
MAX_WORD_LENGTH = 14,
MIN_HASH_VALUE = 2,
- MAX_HASH_VALUE = 48
+ MAX_HASH_VALUE = 51
};
static struct kconf_id wordlist[] =
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_HELP, TF_COMMAND},
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str15, T_TYPE, TF_COMMAND, S_BOOLEAN},
+ {-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_CONFIG, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE},
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_TYPE, TF_COMMAND, S_BOOLEAN},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_TYPE, TF_COMMAND, S_HEX},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19, T_OPT_DEFCONFIG_LIST,TF_OPTION},
- {-1},
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_TYPE, TF_COMMAND, S_STRING},
+ {-1}, {-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_IF, TF_COMMAND|TF_PARAM},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_INT},
- {-1}, {-1},
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SELECT, TF_COMMAND},
+ {-1}, {-1}, {-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_TYPE, TF_COMMAND, S_TRISTATE},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND},
- {-1},
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SOURCE, TF_COMMAND},
+ {-1}, {-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND},
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_TYPE, TF_COMMAND, S_HEX},
- {-1},
+ {-1}, {-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_MENUCONFIG, TF_COMMAND},
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_PROMPT, TF_COMMAND},
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_DEPENDS, TF_COMMAND},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_TYPE, TF_COMMAND, S_STRING},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_VISIBLE, TF_COMMAND},
+ {-1}, {-1}, {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_PROMPT, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_DEPENDS, TF_COMMAND},
{-1},
- {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48, T_MAINMENU, TF_COMMAND}
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str44, T_TYPE, TF_COMMAND, S_BOOLEAN},
+ {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_SELECT, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48, T_MAINMENU, TF_COMMAND},
+ {-1}, {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_SOURCE, TF_COMMAND}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
T_DEFAULT = 275,
T_SELECT = 276,
T_RANGE = 277,
- T_OPTION = 278,
- T_ON = 279,
- T_WORD = 280,
- T_WORD_QUOTE = 281,
- T_UNEQUAL = 282,
- T_CLOSE_PAREN = 283,
- T_OPEN_PAREN = 284,
- T_EOL = 285,
- T_OR = 286,
- T_AND = 287,
- T_EQUAL = 288,
- T_NOT = 289
+ T_VISIBLE = 278,
+ T_OPTION = 279,
+ T_ON = 280,
+ T_WORD = 281,
+ T_WORD_QUOTE = 282,
+ T_UNEQUAL = 283,
+ T_CLOSE_PAREN = 284,
+ T_OPEN_PAREN = 285,
+ T_EOL = 286,
+ T_OR = 287,
+ T_AND = 288,
+ T_EQUAL = 289,
+ T_NOT = 290
};
#endif
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 11
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 277
+#define YYLAST 290
/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 35
+#define YYNTOKENS 36
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 48
+#define YYNNTS 50
/* YYNRULES -- Number of rules. */
-#define YYNRULES 113
+#define YYNRULES 118
/* YYNRULES -- Number of states. */
-#define YYNSTATES 185
+#define YYNSTATES 191
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
-#define YYMAXUTOK 289
+#define YYMAXUTOK 290
#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35
};
#if YYDEBUG
{
0, 0, 3, 6, 8, 11, 13, 14, 17, 20,
23, 26, 31, 36, 40, 42, 44, 46, 48, 50,
- 52, 54, 56, 58, 60, 62, 64, 66, 70, 73,
- 77, 80, 84, 87, 88, 91, 94, 97, 100, 103,
- 106, 110, 115, 120, 125, 131, 135, 136, 140, 141,
- 144, 148, 151, 153, 157, 158, 161, 164, 167, 170,
- 173, 178, 182, 185, 190, 191, 194, 198, 200, 204,
- 205, 208, 211, 214, 218, 222, 225, 227, 231, 232,
- 235, 238, 241, 245, 249, 252, 255, 258, 259, 262,
- 265, 268, 273, 274, 277, 279, 281, 284, 287, 290,
- 292, 295, 296, 299, 301, 305, 309, 313, 316, 320,
- 324, 326, 328, 329
+ 52, 54, 56, 58, 60, 62, 64, 66, 68, 72,
+ 75, 79, 82, 86, 89, 90, 93, 96, 99, 102,
+ 105, 108, 112, 117, 122, 127, 133, 137, 138, 142,
+ 143, 146, 150, 153, 155, 159, 160, 163, 166, 169,
+ 172, 175, 180, 184, 187, 192, 193, 196, 200, 202,
+ 206, 207, 210, 213, 216, 220, 224, 228, 230, 234,
+ 235, 238, 241, 244, 248, 252, 255, 258, 261, 262,
+ 265, 268, 271, 276, 277, 280, 283, 286, 287, 290,
+ 292, 294, 297, 300, 303, 305, 308, 309, 312, 314,
+ 318, 322, 326, 329, 333, 337, 339, 341, 342
};
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
static const yytype_int8 yyrhs[] =
{
- 36, 0, -1, 78, 37, -1, 37, -1, 62, 38,
- -1, 38, -1, -1, 38, 40, -1, 38, 54, -1,
- 38, 66, -1, 38, 77, -1, 38, 25, 1, 30,
- -1, 38, 39, 1, 30, -1, 38, 1, 30, -1,
+ 37, 0, -1, 81, 38, -1, 38, -1, 63, 39,
+ -1, 39, -1, -1, 39, 41, -1, 39, 55, -1,
+ 39, 67, -1, 39, 80, -1, 39, 26, 1, 31,
+ -1, 39, 40, 1, 31, -1, 39, 1, 31, -1,
16, -1, 18, -1, 19, -1, 21, -1, 17, -1,
- 22, -1, 20, -1, 30, -1, 60, -1, 70, -1,
- 43, -1, 45, -1, 68, -1, 25, 1, 30, -1,
- 1, 30, -1, 10, 25, 30, -1, 42, 46, -1,
- 11, 25, 30, -1, 44, 46, -1, -1, 46, 47,
- -1, 46, 48, -1, 46, 74, -1, 46, 72, -1,
- 46, 41, -1, 46, 30, -1, 19, 75, 30, -1,
- 18, 76, 79, 30, -1, 20, 80, 79, 30, -1,
- 21, 25, 79, 30, -1, 22, 81, 81, 79, 30,
- -1, 23, 49, 30, -1, -1, 49, 25, 50, -1,
- -1, 33, 76, -1, 7, 82, 30, -1, 51, 55,
- -1, 77, -1, 52, 57, 53, -1, -1, 55, 56,
- -1, 55, 74, -1, 55, 72, -1, 55, 30, -1,
- 55, 41, -1, 18, 76, 79, 30, -1, 19, 75,
- 30, -1, 17, 30, -1, 20, 25, 79, 30, -1,
- -1, 57, 40, -1, 14, 80, 78, -1, 77, -1,
- 58, 61, 59, -1, -1, 61, 40, -1, 61, 66,
- -1, 61, 54, -1, 3, 76, 78, -1, 4, 76,
- 30, -1, 63, 73, -1, 77, -1, 64, 67, 65,
- -1, -1, 67, 40, -1, 67, 66, -1, 67, 54,
- -1, 6, 76, 30, -1, 9, 76, 30, -1, 69,
- 73, -1, 12, 30, -1, 71, 13, -1, -1, 73,
- 74, -1, 73, 30, -1, 73, 41, -1, 16, 24,
- 80, 30, -1, -1, 76, 79, -1, 25, -1, 26,
- -1, 5, 30, -1, 8, 30, -1, 15, 30, -1,
- 30, -1, 78, 30, -1, -1, 14, 80, -1, 81,
- -1, 81, 33, 81, -1, 81, 27, 81, -1, 29,
- 80, 28, -1, 34, 80, -1, 80, 31, 80, -1,
- 80, 32, 80, -1, 25, -1, 26, -1, -1, 25,
- -1
+ 22, -1, 20, -1, 23, -1, 31, -1, 61, -1,
+ 71, -1, 44, -1, 46, -1, 69, -1, 26, 1,
+ 31, -1, 1, 31, -1, 10, 26, 31, -1, 43,
+ 47, -1, 11, 26, 31, -1, 45, 47, -1, -1,
+ 47, 48, -1, 47, 49, -1, 47, 75, -1, 47,
+ 73, -1, 47, 42, -1, 47, 31, -1, 19, 78,
+ 31, -1, 18, 79, 82, 31, -1, 20, 83, 82,
+ 31, -1, 21, 26, 82, 31, -1, 22, 84, 84,
+ 82, 31, -1, 24, 50, 31, -1, -1, 50, 26,
+ 51, -1, -1, 34, 79, -1, 7, 85, 31, -1,
+ 52, 56, -1, 80, -1, 53, 58, 54, -1, -1,
+ 56, 57, -1, 56, 75, -1, 56, 73, -1, 56,
+ 31, -1, 56, 42, -1, 18, 79, 82, 31, -1,
+ 19, 78, 31, -1, 17, 31, -1, 20, 26, 82,
+ 31, -1, -1, 58, 41, -1, 14, 83, 81, -1,
+ 80, -1, 59, 62, 60, -1, -1, 62, 41, -1,
+ 62, 67, -1, 62, 55, -1, 3, 79, 81, -1,
+ 4, 79, 31, -1, 64, 76, 74, -1, 80, -1,
+ 65, 68, 66, -1, -1, 68, 41, -1, 68, 67,
+ -1, 68, 55, -1, 6, 79, 31, -1, 9, 79,
+ 31, -1, 70, 74, -1, 12, 31, -1, 72, 13,
+ -1, -1, 74, 75, -1, 74, 31, -1, 74, 42,
+ -1, 16, 25, 83, 31, -1, -1, 76, 77, -1,
+ 76, 31, -1, 23, 82, -1, -1, 79, 82, -1,
+ 26, -1, 27, -1, 5, 31, -1, 8, 31, -1,
+ 15, 31, -1, 31, -1, 81, 31, -1, -1, 14,
+ 83, -1, 84, -1, 84, 34, 84, -1, 84, 28,
+ 84, -1, 30, 83, 29, -1, 35, 83, -1, 83,
+ 32, 83, -1, 83, 33, 83, -1, 26, -1, 27,
+ -1, -1, 26, -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 107, 107, 107, 109, 109, 111, 113, 114, 115,
- 116, 117, 118, 122, 126, 126, 126, 126, 126, 126,
- 126, 130, 131, 132, 133, 134, 135, 139, 140, 146,
- 154, 160, 168, 178, 180, 181, 182, 183, 184, 185,
- 188, 196, 202, 212, 218, 224, 227, 229, 240, 241,
- 246, 255, 260, 268, 271, 273, 274, 275, 276, 277,
- 280, 286, 297, 303, 313, 315, 320, 328, 336, 339,
- 341, 342, 343, 348, 355, 362, 367, 375, 378, 380,
- 381, 382, 385, 393, 400, 407, 413, 420, 422, 423,
- 424, 427, 435, 437, 442, 443, 446, 447, 448, 452,
- 453, 456, 457, 460, 461, 462, 463, 464, 465, 466,
- 469, 470, 473, 474
+ 0, 108, 108, 108, 110, 110, 112, 114, 115, 116,
+ 117, 118, 119, 123, 127, 127, 127, 127, 127, 127,
+ 127, 127, 131, 132, 133, 134, 135, 136, 140, 141,
+ 147, 155, 161, 169, 179, 181, 182, 183, 184, 185,
+ 186, 189, 197, 203, 213, 219, 225, 228, 230, 241,
+ 242, 247, 256, 261, 269, 272, 274, 275, 276, 277,
+ 278, 281, 287, 298, 304, 314, 316, 321, 329, 337,
+ 340, 342, 343, 344, 349, 356, 363, 368, 376, 379,
+ 381, 382, 383, 386, 394, 401, 408, 414, 421, 423,
+ 424, 425, 428, 436, 438, 439, 442, 449, 451, 456,
+ 457, 460, 461, 462, 466, 467, 470, 471, 474, 475,
+ 476, 477, 478, 479, 480, 483, 484, 487, 488
};
#endif
"T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
"T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
"T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE",
- "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
+ "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
"T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
"T_NOT", "$accept", "input", "start", "stmt_list", "option_name",
"common_stmt", "option_error", "config_entry_start", "config_stmt",
"if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu",
"menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt",
"comment", "comment_stmt", "help_start", "help", "depends_list",
- "depends", "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr",
- "symbol", "word_opt", 0
+ "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt",
+ "end", "nl", "if_expr", "expr", "symbol", "word_opt", 0
};
#endif
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287, 288, 289
+ 285, 286, 287, 288, 289, 290
};
# endif
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] =
{
- 0, 35, 36, 36, 37, 37, 38, 38, 38, 38,
- 38, 38, 38, 38, 39, 39, 39, 39, 39, 39,
- 39, 40, 40, 40, 40, 40, 40, 41, 41, 42,
- 43, 44, 45, 46, 46, 46, 46, 46, 46, 46,
- 47, 47, 47, 47, 47, 48, 49, 49, 50, 50,
- 51, 52, 53, 54, 55, 55, 55, 55, 55, 55,
- 56, 56, 56, 56, 57, 57, 58, 59, 60, 61,
- 61, 61, 61, 62, 63, 64, 65, 66, 67, 67,
- 67, 67, 68, 69, 70, 71, 72, 73, 73, 73,
- 73, 74, 75, 75, 76, 76, 77, 77, 77, 78,
- 78, 79, 79, 80, 80, 80, 80, 80, 80, 80,
- 81, 81, 82, 82
+ 0, 36, 37, 37, 38, 38, 39, 39, 39, 39,
+ 39, 39, 39, 39, 40, 40, 40, 40, 40, 40,
+ 40, 40, 41, 41, 41, 41, 41, 41, 42, 42,
+ 43, 44, 45, 46, 47, 47, 47, 47, 47, 47,
+ 47, 48, 48, 48, 48, 48, 49, 50, 50, 51,
+ 51, 52, 53, 54, 55, 56, 56, 56, 56, 56,
+ 56, 57, 57, 57, 57, 58, 58, 59, 60, 61,
+ 62, 62, 62, 62, 63, 64, 65, 66, 67, 68,
+ 68, 68, 68, 69, 70, 71, 72, 73, 74, 74,
+ 74, 74, 75, 76, 76, 76, 77, 78, 78, 79,
+ 79, 80, 80, 80, 81, 81, 82, 82, 83, 83,
+ 83, 83, 83, 83, 83, 84, 84, 85, 85
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
{
0, 2, 2, 1, 2, 1, 0, 2, 2, 2,
2, 4, 4, 3, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 3, 2, 3,
- 2, 3, 2, 0, 2, 2, 2, 2, 2, 2,
- 3, 4, 4, 4, 5, 3, 0, 3, 0, 2,
- 3, 2, 1, 3, 0, 2, 2, 2, 2, 2,
- 4, 3, 2, 4, 0, 2, 3, 1, 3, 0,
- 2, 2, 2, 3, 3, 2, 1, 3, 0, 2,
- 2, 2, 3, 3, 2, 2, 2, 0, 2, 2,
- 2, 4, 0, 2, 1, 1, 2, 2, 2, 1,
- 2, 0, 2, 1, 3, 3, 3, 2, 3, 3,
- 1, 1, 0, 1
+ 1, 1, 1, 1, 1, 1, 1, 1, 3, 2,
+ 3, 2, 3, 2, 0, 2, 2, 2, 2, 2,
+ 2, 3, 4, 4, 4, 5, 3, 0, 3, 0,
+ 2, 3, 2, 1, 3, 0, 2, 2, 2, 2,
+ 2, 4, 3, 2, 4, 0, 2, 3, 1, 3,
+ 0, 2, 2, 2, 3, 3, 3, 1, 3, 0,
+ 2, 2, 2, 3, 3, 2, 2, 2, 0, 2,
+ 2, 2, 4, 0, 2, 2, 2, 0, 2, 1,
+ 1, 2, 2, 2, 1, 2, 0, 2, 1, 3,
+ 3, 3, 2, 3, 3, 1, 1, 0, 1
};
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 6, 0, 99, 0, 3, 0, 6, 6, 94, 95,
- 0, 1, 0, 0, 0, 0, 112, 0, 0, 0,
+ 6, 0, 104, 0, 3, 0, 6, 6, 99, 100,
+ 0, 1, 0, 0, 0, 0, 117, 0, 0, 0,
0, 0, 0, 14, 18, 15, 16, 20, 17, 19,
- 0, 21, 0, 7, 33, 24, 33, 25, 54, 64,
- 8, 69, 22, 87, 78, 9, 26, 87, 23, 10,
- 0, 100, 2, 73, 13, 0, 96, 0, 113, 0,
- 97, 0, 0, 0, 110, 111, 0, 0, 0, 103,
- 98, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 74, 82, 50, 83, 29, 31, 0, 107, 0,
- 0, 66, 0, 0, 11, 12, 0, 0, 0, 0,
- 92, 0, 0, 0, 46, 0, 39, 38, 34, 35,
- 0, 37, 36, 0, 0, 92, 0, 58, 59, 55,
- 57, 56, 65, 53, 52, 70, 72, 68, 71, 67,
- 89, 90, 88, 79, 81, 77, 80, 76, 106, 108,
- 109, 105, 104, 28, 85, 0, 101, 0, 101, 101,
- 101, 0, 0, 0, 86, 62, 101, 0, 101, 0,
- 0, 0, 40, 93, 0, 0, 101, 48, 45, 27,
- 0, 61, 0, 91, 102, 41, 42, 43, 0, 0,
- 47, 60, 63, 44, 49
+ 21, 0, 22, 0, 7, 34, 25, 34, 26, 55,
+ 65, 8, 70, 23, 93, 79, 9, 27, 88, 24,
+ 10, 0, 105, 2, 74, 13, 0, 101, 0, 118,
+ 0, 102, 0, 0, 0, 115, 116, 0, 0, 0,
+ 108, 103, 0, 0, 0, 0, 0, 0, 0, 88,
+ 0, 0, 75, 83, 51, 84, 30, 32, 0, 112,
+ 0, 0, 67, 0, 0, 11, 12, 0, 0, 0,
+ 0, 97, 0, 0, 0, 47, 0, 40, 39, 35,
+ 36, 0, 38, 37, 0, 0, 97, 0, 59, 60,
+ 56, 58, 57, 66, 54, 53, 71, 73, 69, 72,
+ 68, 106, 95, 0, 94, 80, 82, 78, 81, 77,
+ 90, 91, 89, 111, 113, 114, 110, 109, 29, 86,
+ 0, 106, 0, 106, 106, 106, 0, 0, 0, 87,
+ 63, 106, 0, 106, 0, 96, 0, 0, 41, 98,
+ 0, 0, 106, 49, 46, 28, 0, 62, 0, 107,
+ 92, 42, 43, 44, 0, 0, 48, 61, 64, 45,
+ 50
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
- -1, 3, 4, 5, 32, 33, 107, 34, 35, 36,
- 37, 73, 108, 109, 152, 180, 38, 39, 123, 40,
- 75, 119, 76, 41, 127, 42, 77, 6, 43, 44,
- 135, 45, 79, 46, 47, 48, 110, 111, 78, 112,
- 147, 148, 49, 7, 161, 68, 69, 59
+ -1, 3, 4, 5, 33, 34, 108, 35, 36, 37,
+ 38, 74, 109, 110, 157, 186, 39, 40, 124, 41,
+ 76, 120, 77, 42, 128, 43, 78, 6, 44, 45,
+ 137, 46, 80, 47, 48, 49, 111, 112, 81, 113,
+ 79, 134, 152, 153, 50, 7, 165, 69, 70, 60
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -89
+#define YYPACT_NINF -90
static const yytype_int16 yypact[] =
{
- 3, 4, -89, 20, -89, 100, -89, 7, -89, -89,
- -8, -89, 17, 4, 28, 4, 37, 36, 4, 68,
- 87, -18, 69, -89, -89, -89, -89, -89, -89, -89,
- 128, -89, 138, -89, -89, -89, -89, -89, -89, -89,
- -89, -89, -89, -89, -89, -89, -89, -89, -89, -89,
- 127, -89, -89, 110, -89, 126, -89, 136, -89, 137,
- -89, 147, 150, 152, -89, -89, -18, -18, 171, -14,
- -89, 153, 157, 34, 67, 180, 233, 220, 207, 220,
- 154, -89, -89, -89, -89, -89, -89, 0, -89, -18,
- -18, 110, 44, 44, -89, -89, 163, 174, 182, 4,
- 4, -18, 194, 44, -89, 219, -89, -89, -89, -89,
- 223, -89, -89, 203, 4, 4, 215, -89, -89, -89,
- -89, -89, -89, -89, -89, -89, -89, -89, -89, -89,
- -89, -89, -89, -89, -89, -89, -89, -89, -89, 213,
- -89, -89, -89, -89, -89, -18, 232, 227, 232, -5,
- 232, 44, 35, 234, -89, -89, 232, 235, 232, 224,
- -18, 236, -89, -89, 237, 238, 232, 216, -89, -89,
- 240, -89, 241, -89, 71, -89, -89, -89, 242, 4,
- -89, -89, -89, -89, -89
+ 4, 42, -90, 96, -90, 111, -90, 15, -90, -90,
+ 75, -90, 82, 42, 104, 42, 110, 107, 42, 115,
+ 125, -4, 121, -90, -90, -90, -90, -90, -90, -90,
+ -90, 162, -90, 163, -90, -90, -90, -90, -90, -90,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, 139, -90, -90, 138, -90, 142, -90, 143, -90,
+ 152, -90, 164, 167, 168, -90, -90, -4, -4, 77,
+ -18, -90, 177, 185, 33, 71, 195, 247, 236, -2,
+ 236, 171, -90, -90, -90, -90, -90, -90, 41, -90,
+ -4, -4, 138, 97, 97, -90, -90, 186, 187, 194,
+ 42, 42, -4, 196, 97, -90, 219, -90, -90, -90,
+ -90, 210, -90, -90, 204, 42, 42, 199, -90, -90,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, 222, -90, 223, -90, -90, -90, -90, -90, -90,
+ -90, -90, -90, -90, 215, -90, -90, -90, -90, -90,
+ -4, 222, 228, 222, -5, 222, 97, 35, 229, -90,
+ -90, 222, 232, 222, -4, -90, 135, 233, -90, -90,
+ 234, 235, 222, 240, -90, -90, 237, -90, 239, -13,
+ -90, -90, -90, -90, 244, 42, -90, -90, -90, -90,
+ -90
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] =
{
- -89, -89, 255, 267, -89, 47, -57, -89, -89, -89,
- -89, 239, -89, -89, -89, -89, -89, -89, -89, 130,
- -89, -89, -89, -89, -89, -89, -89, -89, -89, -89,
- -89, 181, -89, -89, -89, -89, -89, 199, 229, 16,
- 162, -1, 74, -7, 103, -65, -88, -89
+ -90, -90, 269, 271, -90, 23, -70, -90, -90, -90,
+ -90, 243, -90, -90, -90, -90, -90, -90, -90, -48,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, -20, -90, -90, -90, -90, -90, 206, 205, -68,
+ -90, -90, 169, -1, 27, -7, 118, -66, -89, -90
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule which
number is the opposite. If zero, do what YYDEFACT says.
If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -85
+#define YYTABLE_NINF -86
static const yytype_int16 yytable[] =
{
- 10, 87, 88, 53, 141, 142, 1, 64, 65, 160,
- 1, 66, 55, 92, 57, 151, 67, 61, 118, 93,
- 11, 131, 2, 131, 139, 140, 89, 90, 138, 8,
- 9, 89, 90, 2, -30, 96, 149, 51, -30, -30,
- -30, -30, -30, -30, -30, -30, 97, 54, -30, -30,
- 98, -30, 99, 100, 101, 102, 103, 104, 56, 105,
- 167, 91, 58, 166, 106, 168, 60, -32, 96, 64,
- 65, -32, -32, -32, -32, -32, -32, -32, -32, 97,
- 159, -32, -32, 98, -32, 99, 100, 101, 102, 103,
- 104, 121, 105, 62, 132, 174, 132, 106, 146, 70,
- -5, 12, 89, 90, 13, 14, 15, 16, 17, 18,
- 19, 20, 63, 156, 21, 22, 23, 24, 25, 26,
- 27, 28, 29, 122, 125, 30, 133, -4, 12, 71,
- 31, 13, 14, 15, 16, 17, 18, 19, 20, 72,
- 51, 21, 22, 23, 24, 25, 26, 27, 28, 29,
- 124, 129, 30, 137, -84, 96, 81, 31, -84, -84,
- -84, -84, -84, -84, -84, -84, 82, 83, -84, -84,
- 98, -84, -84, -84, -84, -84, -84, 84, 184, 105,
- 85, 96, 86, 94, 130, -51, -51, 95, -51, -51,
- -51, -51, 97, 143, -51, -51, 98, 113, 114, 115,
- 116, 2, 89, 90, 144, 105, 145, 126, 96, 134,
- 117, -75, -75, -75, -75, -75, -75, -75, -75, 150,
- 153, -75, -75, 98, 13, 14, 15, 16, 17, 18,
- 19, 20, 105, 155, 21, 22, 154, 130, 14, 15,
- 158, 17, 18, 19, 20, 90, 160, 21, 22, 179,
- 31, 163, 164, 165, 173, 89, 90, 162, 128, 170,
- 136, 172, 52, 31, 169, 171, 175, 176, 177, 178,
- 181, 182, 183, 50, 120, 74, 80, 157
+ 10, 88, 89, 54, 146, 147, 119, 1, 122, 164,
+ 93, 141, 56, 142, 58, 156, 94, 62, 1, 90,
+ 91, 131, 65, 66, 144, 145, 67, 90, 91, 132,
+ 127, 68, 136, -31, 97, 2, 154, -31, -31, -31,
+ -31, -31, -31, -31, -31, 98, 52, -31, -31, 99,
+ -31, 100, 101, 102, 103, 104, -31, 105, 129, 106,
+ 138, 173, 92, 141, 107, 142, 174, 172, 8, 9,
+ 143, -33, 97, 90, 91, -33, -33, -33, -33, -33,
+ -33, -33, -33, 98, 166, -33, -33, 99, -33, 100,
+ 101, 102, 103, 104, -33, 105, 11, 106, 179, 151,
+ 123, 126, 107, 135, 125, 130, 2, 139, 2, 90,
+ 91, -5, 12, 55, 161, 13, 14, 15, 16, 17,
+ 18, 19, 20, 65, 66, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 57, 59, 31, 61, -4,
+ 12, 63, 32, 13, 14, 15, 16, 17, 18, 19,
+ 20, 64, 71, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 72, 73, 31, 180, 90, 91, 52,
+ 32, -85, 97, 82, 83, -85, -85, -85, -85, -85,
+ -85, -85, -85, 84, 190, -85, -85, 99, -85, -85,
+ -85, -85, -85, -85, -85, 85, 97, 106, 86, 87,
+ -52, -52, 140, -52, -52, -52, -52, 98, 95, -52,
+ -52, 99, 114, 115, 116, 117, 96, 148, 149, 150,
+ 158, 106, 155, 159, 97, 163, 118, -76, -76, -76,
+ -76, -76, -76, -76, -76, 160, 164, -76, -76, 99,
+ 13, 14, 15, 16, 17, 18, 19, 20, 91, 106,
+ 21, 22, 14, 15, 140, 17, 18, 19, 20, 168,
+ 175, 21, 22, 177, 181, 182, 183, 32, 187, 167,
+ 188, 169, 170, 171, 185, 189, 53, 51, 32, 176,
+ 75, 178, 121, 0, 133, 162, 0, 0, 0, 0,
+ 184
};
-static const yytype_uint8 yycheck[] =
+static const yytype_int16 yycheck[] =
{
- 1, 66, 67, 10, 92, 93, 3, 25, 26, 14,
- 3, 29, 13, 27, 15, 103, 34, 18, 75, 33,
- 0, 78, 30, 80, 89, 90, 31, 32, 28, 25,
- 26, 31, 32, 30, 0, 1, 101, 30, 4, 5,
- 6, 7, 8, 9, 10, 11, 12, 30, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 30, 25,
- 25, 68, 25, 151, 30, 30, 30, 0, 1, 25,
- 26, 4, 5, 6, 7, 8, 9, 10, 11, 12,
- 145, 14, 15, 16, 17, 18, 19, 20, 21, 22,
- 23, 75, 25, 25, 78, 160, 80, 30, 99, 30,
- 0, 1, 31, 32, 4, 5, 6, 7, 8, 9,
- 10, 11, 25, 114, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 76, 77, 25, 79, 0, 1, 1,
- 30, 4, 5, 6, 7, 8, 9, 10, 11, 1,
- 30, 14, 15, 16, 17, 18, 19, 20, 21, 22,
- 76, 77, 25, 79, 0, 1, 30, 30, 4, 5,
- 6, 7, 8, 9, 10, 11, 30, 30, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 30, 179, 25,
- 30, 1, 30, 30, 30, 5, 6, 30, 8, 9,
- 10, 11, 12, 30, 14, 15, 16, 17, 18, 19,
- 20, 30, 31, 32, 30, 25, 24, 77, 1, 79,
- 30, 4, 5, 6, 7, 8, 9, 10, 11, 25,
- 1, 14, 15, 16, 4, 5, 6, 7, 8, 9,
- 10, 11, 25, 30, 14, 15, 13, 30, 5, 6,
- 25, 8, 9, 10, 11, 32, 14, 14, 15, 33,
- 30, 148, 149, 150, 30, 31, 32, 30, 77, 156,
- 79, 158, 7, 30, 30, 30, 30, 30, 30, 166,
- 30, 30, 30, 6, 75, 36, 47, 115
+ 1, 67, 68, 10, 93, 94, 76, 3, 76, 14,
+ 28, 81, 13, 81, 15, 104, 34, 18, 3, 32,
+ 33, 23, 26, 27, 90, 91, 30, 32, 33, 31,
+ 78, 35, 80, 0, 1, 31, 102, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 31, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 78, 26,
+ 80, 26, 69, 133, 31, 133, 31, 156, 26, 27,
+ 29, 0, 1, 32, 33, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 150, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 0, 26, 164, 100,
+ 77, 78, 31, 80, 77, 78, 31, 80, 31, 32,
+ 33, 0, 1, 31, 115, 4, 5, 6, 7, 8,
+ 9, 10, 11, 26, 27, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 31, 26, 26, 31, 0,
+ 1, 26, 31, 4, 5, 6, 7, 8, 9, 10,
+ 11, 26, 31, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 1, 1, 26, 31, 32, 33, 31,
+ 31, 0, 1, 31, 31, 4, 5, 6, 7, 8,
+ 9, 10, 11, 31, 185, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 31, 1, 26, 31, 31,
+ 5, 6, 31, 8, 9, 10, 11, 12, 31, 14,
+ 15, 16, 17, 18, 19, 20, 31, 31, 31, 25,
+ 1, 26, 26, 13, 1, 26, 31, 4, 5, 6,
+ 7, 8, 9, 10, 11, 31, 14, 14, 15, 16,
+ 4, 5, 6, 7, 8, 9, 10, 11, 33, 26,
+ 14, 15, 5, 6, 31, 8, 9, 10, 11, 31,
+ 31, 14, 15, 31, 31, 31, 31, 31, 31, 151,
+ 31, 153, 154, 155, 34, 31, 7, 6, 31, 161,
+ 37, 163, 76, -1, 79, 116, -1, -1, -1, -1,
+ 172
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
static const yytype_uint8 yystos[] =
{
- 0, 3, 30, 36, 37, 38, 62, 78, 25, 26,
- 76, 0, 1, 4, 5, 6, 7, 8, 9, 10,
+ 0, 3, 31, 37, 38, 39, 63, 81, 26, 27,
+ 79, 0, 1, 4, 5, 6, 7, 8, 9, 10,
11, 14, 15, 16, 17, 18, 19, 20, 21, 22,
- 25, 30, 39, 40, 42, 43, 44, 45, 51, 52,
- 54, 58, 60, 63, 64, 66, 68, 69, 70, 77,
- 38, 30, 37, 78, 30, 76, 30, 76, 25, 82,
- 30, 76, 25, 25, 25, 26, 29, 34, 80, 81,
- 30, 1, 1, 46, 46, 55, 57, 61, 73, 67,
- 73, 30, 30, 30, 30, 30, 30, 80, 80, 31,
- 32, 78, 27, 33, 30, 30, 1, 12, 16, 18,
- 19, 20, 21, 22, 23, 25, 30, 41, 47, 48,
- 71, 72, 74, 17, 18, 19, 20, 30, 41, 56,
- 72, 74, 40, 53, 77, 40, 54, 59, 66, 77,
- 30, 41, 74, 40, 54, 65, 66, 77, 28, 80,
- 80, 81, 81, 30, 30, 24, 76, 75, 76, 80,
- 25, 81, 49, 1, 13, 30, 76, 75, 25, 80,
- 14, 79, 30, 79, 79, 79, 81, 25, 30, 30,
- 79, 30, 79, 30, 80, 30, 30, 30, 79, 33,
- 50, 30, 30, 30, 76
+ 23, 26, 31, 40, 41, 43, 44, 45, 46, 52,
+ 53, 55, 59, 61, 64, 65, 67, 69, 70, 71,
+ 80, 39, 31, 38, 81, 31, 79, 31, 79, 26,
+ 85, 31, 79, 26, 26, 26, 27, 30, 35, 83,
+ 84, 31, 1, 1, 47, 47, 56, 58, 62, 76,
+ 68, 74, 31, 31, 31, 31, 31, 31, 83, 83,
+ 32, 33, 81, 28, 34, 31, 31, 1, 12, 16,
+ 18, 19, 20, 21, 22, 24, 26, 31, 42, 48,
+ 49, 72, 73, 75, 17, 18, 19, 20, 31, 42,
+ 57, 73, 75, 41, 54, 80, 41, 55, 60, 67,
+ 80, 23, 31, 74, 77, 41, 55, 66, 67, 80,
+ 31, 42, 75, 29, 83, 83, 84, 84, 31, 31,
+ 25, 79, 78, 79, 83, 26, 84, 50, 1, 13,
+ 31, 79, 78, 26, 14, 82, 83, 82, 31, 82,
+ 82, 82, 84, 26, 31, 31, 82, 31, 82, 83,
+ 31, 31, 31, 31, 82, 34, 51, 31, 31, 31,
+ 79
};
#define yyerrok (yyerrstatus = 0)
switch (yytype)
{
- case 52: /* "choice_entry" */
+ case 53: /* "choice_entry" */
{
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
};
break;
- case 58: /* "if_entry" */
+ case 59: /* "if_entry" */
{
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
};
break;
- case 64: /* "menu_entry" */
+ case 65: /* "menu_entry" */
{
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
{ zconf_error("invalid statement"); ;}
break;
- case 27:
+ case 28:
{ zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;}
break;
- case 28:
+ case 29:
{ zconf_error("invalid option"); ;}
break;
- case 29:
+ case 30:
{
struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
;}
break;
- case 30:
+ case 31:
{
menu_end_entry();
;}
break;
- case 31:
+ case 32:
{
struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
;}
break;
- case 32:
+ case 33:
{
if (current_entry->prompt)
;}
break;
- case 40:
+ case 41:
{
menu_set_type((yyvsp[(1) - (3)].id)->stype);
;}
break;
- case 41:
+ case 42:
{
menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
;}
break;
- case 42:
+ case 43:
{
menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr));
;}
break;
- case 43:
+ case 44:
{
menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
;}
break;
- case 44:
+ case 45:
{
menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr));
;}
break;
- case 47:
+ case 48:
{
struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string)));
;}
break;
- case 48:
+ case 49:
{ (yyval.string) = NULL; ;}
break;
- case 49:
+ case 50:
{ (yyval.string) = (yyvsp[(2) - (2)].string); ;}
break;
- case 50:
+ case 51:
{
struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE);
;}
break;
- case 51:
+ case 52:
{
(yyval.menu) = menu_add_menu();
;}
break;
- case 52:
+ case 53:
{
if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) {
;}
break;
- case 60:
+ case 61:
{
menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
;}
break;
- case 61:
+ case 62:
{
if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) {
;}
break;
- case 62:
+ case 63:
{
current_entry->sym->flags |= SYMBOL_OPTIONAL;
;}
break;
- case 63:
+ case 64:
{
if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) {
;}
break;
- case 66:
+ case 67:
{
printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
;}
break;
- case 67:
+ case 68:
{
if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) {
;}
break;
- case 73:
+ case 74:
{
menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
;}
break;
- case 74:
+ case 75:
{
menu_add_entry(NULL);
;}
break;
- case 75:
+ case 76:
{
(yyval.menu) = menu_add_menu();
;}
break;
- case 76:
+ case 77:
{
if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) {
;}
break;
- case 82:
+ case 83:
{
printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
;}
break;
- case 83:
+ case 84:
{
menu_add_entry(NULL);
;}
break;
- case 84:
+ case 85:
{
menu_end_entry();
;}
break;
- case 85:
+ case 86:
{
printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
;}
break;
- case 86:
+ case 87:
{
current_entry->help = (yyvsp[(2) - (2)].string);
;}
break;
- case 91:
+ case 92:
{
menu_add_dep((yyvsp[(3) - (4)].expr));
;}
break;
- case 93:
+ case 96:
+
+ {
+ menu_add_visibility((yyvsp[(2) - (2)].expr));
+;}
+ break;
+
+ case 98:
{
menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr));
;}
break;
- case 96:
+ case 101:
{ (yyval.id) = (yyvsp[(1) - (2)].id); ;}
break;
- case 97:
+ case 102:
{ (yyval.id) = (yyvsp[(1) - (2)].id); ;}
break;
- case 98:
+ case 103:
{ (yyval.id) = (yyvsp[(1) - (2)].id); ;}
break;
- case 101:
+ case 106:
{ (yyval.expr) = NULL; ;}
break;
- case 102:
+ case 107:
{ (yyval.expr) = (yyvsp[(2) - (2)].expr); ;}
break;
- case 103:
+ case 108:
{ (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;}
break;
- case 104:
+ case 109:
{ (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
break;
- case 105:
+ case 110:
{ (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
break;
- case 106:
+ case 111:
{ (yyval.expr) = (yyvsp[(2) - (3)].expr); ;}
break;
- case 107:
+ case 112:
{ (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;}
break;
- case 108:
+ case 113:
{ (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
break;
- case 109:
+ case 114:
{ (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
break;
- case 110:
+ case 115:
{ (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;}
break;
- case 111:
+ case 116:
{ (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;}
break;
- case 112:
+ case 117:
{ (yyval.string) = NULL; ;}
break;
case T_IF: return "if";
case T_ENDIF: return "endif";
case T_DEPENDS: return "depends";
+ case T_VISIBLE: return "visible";
}
return "<token>";
}
#define YYERROR_VERBOSE
#endif
%}
-%expect 28
+%expect 30
%union
{
%token <id>T_DEFAULT
%token <id>T_SELECT
%token <id>T_RANGE
+%token <id>T_VISIBLE
%token <id>T_OPTION
%token <id>T_ON
%token <string> T_WORD
;
option_name:
- T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT
+ T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
;
common_stmt:
printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
};
-menu_entry: menu depends_list
+menu_entry: menu visibility_list depends_list
{
$$ = menu_add_menu();
};
printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
};
+/* visibility option */
+
+visibility_list:
+ /* empty */
+ | visibility_list visible
+ | visibility_list T_EOL
+;
+
+visible: T_VISIBLE if_expr
+{
+ menu_add_visibility($2);
+};
+
/* prompt statement */
prompt_stmt_opt:
case T_IF: return "if";
case T_ENDIF: return "endif";
case T_DEPENDS: return "depends";
+ case T_VISIBLE: return "visible";
}
return "<token>";
}
## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ##
## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ##
## Copyright (C) 2001 Simon Huggins ##
-## Copyright (C) 2005-2009 Randy Dunlap ##
+## Copyright (C) 2005-2010 Randy Dunlap ##
## ##
## #define enhancements by Armin Kuster <akuster@mvista.com> ##
## Copyright (c) 2000 MontaVista Software, Inc. ##
if ($output_mode eq "html" || $output_mode eq "xml") {
$contents = local_unescape($contents);
# convert data read & converted thru xml_escape() into &xyz; format:
- $contents =~ s/\\\\\\/&/g;
+ $contents =~ s/\\\\\\/\&/g;
}
# print STDERR "contents b4:$contents\n";
eval $dohighlight;
print $args{'type'} . " " . $args{'struct'} . " {\n";
foreach $parameter (@{$args{'parameterlist'}}) {
if ($parameter =~ /^#/) {
- print "$parameter\n";
+ my $prm = $parameter;
+ # convert data read & converted thru xml_escape() into &xyz; format:
+ # This allows us to have #define macros interspersed in a struct.
+ $prm =~ s/\\\\\\/\&/g;
+ print "$prm\n";
next;
}
}
}
+ $param = xml_escape($param);
+
# strip spaces from $param so that it is one continous string
# on @parameterlist;
# this fixes a problem where check_sections() cannot find
return PTR_ERR(pclk);
}
sample_clk = clk_get(&pdev->dev, "sample_clk");
- if (IS_ERR(pclk)) {
+ if (IS_ERR(sample_clk)) {
dev_dbg(&pdev->dev, "no sample clock\n");
- retval = PTR_ERR(pclk);
+ retval = PTR_ERR(sample_clk);
goto out_put_pclk;
}
clk_enable(pclk);
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/string.h>
#include <sound/core.h>
#include <sound/minors.h>
static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file)
{
struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
+ int i;
- substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
- if (substream != NULL) {
- snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
- substream->runtime->oss.prepare = 1;
- }
- substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
- if (substream != NULL) {
+ for (i = 0; i < 2; i++) {
+ substream = pcm_oss_file->streams[i];
+ if (!substream)
+ continue;
+ runtime = substream->runtime;
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
- substream->runtime->oss.prepare = 1;
+ runtime->oss.prepare = 1;
+ runtime->oss.buffer_used = 0;
+ runtime->oss.prev_hw_ptr_period = 0;
+ runtime->oss.period_ptr = 0;
}
return 0;
}
entry->jiffies = jiffies;
entry->pos = pos;
entry->period_size = runtime->period_size;
- entry->buffer_size = runtime->buffer_size;;
+ entry->buffer_size = runtime->buffer_size;
entry->old_hw_ptr = runtime->status->hw_ptr;
entry->hw_ptr_base = runtime->hw_ptr_base;
log->idx = (log->idx + 1) % XRUN_LOG_CNT;
#include <linux/mm.h>
#include <linux/file.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/time.h>
#include <linux/pm_qos_params.h>
#include <linux/uio.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/time.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
if (sound_nblocks >= MAX_MEM_BLOCKS)
sound_nblocks = MAX_MEM_BLOCKS - 1;
- op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations)));
+ op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct audio_operations)));
sound_nblocks++;
if (sound_nblocks >= MAX_MEM_BLOCKS)
sound_nblocks = MAX_MEM_BLOCKS - 1;
sound_unload_audiodev(num);
return -(ENOMEM);
}
- memset((char *) op, 0, sizeof(struct audio_operations));
init_waitqueue_head(&op->in_sleeper);
init_waitqueue_head(&op->out_sleeper);
init_waitqueue_head(&op->poll_sleeper);
/* FIXME: This leaks a mixer_operations struct every time its called
until you unload sound! */
- op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations)));
+ op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct mixer_operations)));
sound_nblocks++;
if (sound_nblocks >= MAX_MEM_BLOCKS)
sound_nblocks = MAX_MEM_BLOCKS - 1;
printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name);
return -ENOMEM;
}
- memset((char *) op, 0, sizeof(struct mixer_operations));
memcpy((char *) op, (char *) driver, driver_size);
strlcpy(op->name, name, sizeof(op->name));
return err;
parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
- midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
+ midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf));
if (midi_in_buf[dev] == NULL)
{
}
midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
- midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
+ midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf));
if (midi_out_buf[dev] == NULL)
{
return 0;
case SNDCTL_COPR_LOAD:
- buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
+ buf = vmalloc(sizeof(copr_buffer));
if (buf == NULL)
return -ENOSPC;
if (copy_from_user(buf, arg, sizeof(copr_buffer))) {
return err;
case SNDCTL_COPR_SENDMSG:
- mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+ mbuf = vmalloc(sizeof(copr_msg));
if (mbuf == NULL)
return -ENOSPC;
if (copy_from_user(mbuf, arg, sizeof(copr_msg))) {
case SNDCTL_COPR_RCVMSG:
err = 0;
- mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+ mbuf = vmalloc(sizeof(copr_msg));
if (mbuf == NULL)
return -ENOSPC;
data = (unsigned short *)mbuf->data;
{
if (sequencer_ok)
return;
- queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ);
+ queue = vmalloc(SEQ_MAX_QUEUE * EV_SZ);
if (queue == NULL)
{
printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n");
return;
}
- iqueue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * IEV_SZ);
+ iqueue = vmalloc(SEQ_MAX_QUEUE * IEV_SZ);
if (iqueue == NULL)
{
printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n");
struct hpi_message hm;
struct hpi_response hr;
struct hpi_adapter *pa;
- pa = (struct hpi_adapter *)pci_get_drvdata(pci_dev);
+ pa = pci_get_drvdata(pci_dev);
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DELETE_ADAPTER);
count_areas = size/2;
addr_area2 = addr+count_areas;
- count_areas--; /* max. index */
snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n",
addr, count_areas, addr_area2, count_areas);
+ count_areas--; /* max. index */
+
/* build combined I/O buffer length word */
lengths = (count_areas << 16) | (count_areas);
spin_lock_irqsave(&chip->reg_lock, flags);
.rate_max = AZF_FREQ_66200,
.channels_min = 1,
.channels_max = 2,
- .buffer_bytes_max = 65536,
- .period_bytes_min = 64,
- .period_bytes_max = 65536,
- .periods_min = 1,
- .periods_max = 1024,
+ .buffer_bytes_max = (64*1024),
+ .period_bytes_min = 1024,
+ .period_bytes_max = (32*1024),
+ /* We simply have two DMA areas (instead of a list of descriptors
+ such as other cards); I believe that this is a fixed hardware
+ attribute and there isn't much driver magic to be done to expand it.
+ Thus indicate that we have at least and at most 2 periods. */
+ .periods_min = 2,
+ .periods_max = 2,
/* FIXME: maybe that card actually has a FIFO?
* Hmm, it seems newer revisions do have one, but we still don't know
* its size... */
chip = snd_timer_chip(timer);
spin_lock_irqsave(&chip->reg_lock, flags);
/* disable timer countdown and interrupt */
- /* FIXME: should we write TIMER_IRQ_ACK here? */
- snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0);
+ /* Hmm, should we write TIMER_IRQ_ACK here?
+ YES indeed, otherwise a rogue timer operation - which prompts
+ ALSA(?) to call repeated stop() in vain, but NOT start() -
+ will never end (value 0x03 is kept shown in control byte).
+ Simply manually poking 0x04 _once_ immediately successfully stops
+ the hardware/ALSA interrupt activity. */
+ snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x04);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_azf3328_dbgcallleave();
return 0;
apcm->substream = substream;
apcm->interrupt = ct_atc_pcm_interrupt;
- runtime->private_data = apcm;
- runtime->private_free = ct_atc_pcm_free_substream;
if (IEC958 == substream->pcm->device) {
runtime->hw = ct_spdif_passthru_playback_hw;
atc->spdif_out_passthru(atc, 1);
}
apcm->timer = ct_timer_instance_new(atc->timer, apcm);
- if (!apcm->timer)
+ if (!apcm->timer) {
+ kfree(apcm);
return -ENOMEM;
+ }
+ runtime->private_data = apcm;
+ runtime->private_free = ct_atc_pcm_free_substream;
return 0;
}
apcm->started = 0;
apcm->substream = substream;
apcm->interrupt = ct_atc_pcm_interrupt;
- runtime->private_data = apcm;
- runtime->private_free = ct_atc_pcm_free_substream;
runtime->hw = ct_pcm_capture_hw;
runtime->hw.rate_max = atc->rsr * atc->msr;
}
apcm->timer = ct_timer_instance_new(atc->timer, apcm);
- if (!apcm->timer)
+ if (!apcm->timer) {
+ kfree(apcm);
return -ENOMEM;
+ }
+ runtime->private_data = apcm;
+ runtime->private_free = ct_atc_pcm_free_substream;
return 0;
}
a->channels = GRAB_BITS(buf, 0, 0, 3);
a->channels++;
+ a->sample_bits = 0;
+ a->max_bitrate = 0;
+
a->format = GRAB_BITS(buf, 0, 3, 4);
switch (a->format) {
case AUDIO_CODING_TYPE_REF_STREAM_HEADER:
case AUDIO_CODING_TYPE_LPCM:
val = GRAB_BITS(buf, 2, 0, 3);
- a->sample_bits = 0;
for (i = 0; i < 3; i++)
if (val & (1 << i))
a->sample_bits |= cea_sample_sizes[i + 1];
{
int i;
- pcm->rates = 0;
- pcm->formats = 0;
- pcm->maxbps = 0;
- pcm->channels_min = -1;
- pcm->channels_max = 0;
+ /* assume basic audio support (the basic audio flag is not in ELD;
+ * however, all audio capable sinks are required to support basic
+ * audio) */
+ pcm->rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+ pcm->formats = SNDRV_PCM_FMTBIT_S16_LE;
+ pcm->maxbps = 16;
+ pcm->channels_max = 2;
for (i = 0; i < eld->sad_count; i++) {
struct cea_sad *a = &eld->sad[i];
pcm->rates |= a->rates;
- if (a->channels < pcm->channels_min)
- pcm->channels_min = a->channels;
if (a->channels > pcm->channels_max)
pcm->channels_max = a->channels;
if (a->format == AUDIO_CODING_TYPE_LPCM) {
- if (a->sample_bits & AC_SUPPCM_BITS_16) {
- pcm->formats |= SNDRV_PCM_FMTBIT_S16_LE;
- if (pcm->maxbps < 16)
- pcm->maxbps = 16;
- }
if (a->sample_bits & AC_SUPPCM_BITS_20) {
pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE;
if (pcm->maxbps < 20)
/* restrict the parameters by the values the codec provides */
pcm->rates &= codec_pars->rates;
pcm->formats &= codec_pars->formats;
- pcm->channels_min = max(pcm->channels_min, codec_pars->channels_min);
pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
}
*/
static struct snd_pci_quirk position_fix_list[] __devinitdata = {
SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1025, 0x026f, "Acer Aspire 5538", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
struct conexant_spec *spec = codec->spec;
unsigned int pinctl;
- snd_printdd("CXT5066: update speaker, hp_present=%d\n",
- spec->hp_present);
+ snd_printdd("CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n",
+ spec->hp_present, spec->cur_eapd);
/* Port A (HP) */
pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0;
pinctl);
/* Port D (HP/LO) */
- pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
- ? spec->port_d_mode : 0;
- /* Mute if Port A is connected on Thinkpad */
- if (spec->thinkpad && (spec->hp_present & 1))
- pinctl = 0;
+ if (spec->dell_automute) {
+ /* DELL AIO Port Rule: PortA> PortD> IntSpk */
+ pinctl = (!(spec->hp_present & 1) && spec->cur_eapd)
+ ? PIN_OUT : 0;
+ } else if (spec->thinkpad) {
+ if (spec->cur_eapd)
+ pinctl = spec->port_d_mode;
+ /* Mute dock line-out if Port A (laptop HP) is present */
+ if (spec->hp_present& 1)
+ pinctl = 0;
+ } else {
+ pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
+ ? spec->port_d_mode : 0;
+ }
snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
pinctl);
pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
pinctl);
-
- if (spec->dell_automute) {
- /* DELL AIO Port Rule: PortA > PortD > IntSpk */
- pinctl = (!(spec->hp_present & 1) && spec->cur_eapd)
- ? PIN_OUT : 0;
- snd_hda_codec_write(codec, 0x1c, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
- }
}
/* turn on/off EAPD (+ mute HP) as a master switch */
static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
- SND_PCI_QUIRK(0x1028, 0x02f5, "Dell",
- CXT5066_DELL_LAPTOP),
+ SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
+ SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP),
SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x21c8, "Thinkpad Edge 11", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD),
return -ENODEV;
} else {
/* fallback to the codec default */
- hinfo->channels_min = codec_pars->channels_min;
hinfo->channels_max = codec_pars->channels_max;
hinfo->rates = codec_pars->rates;
hinfo->formats = codec_pars->formats;
spec->init_amp = ALC_INIT_GPIO3;
break;
case 5:
+ default:
spec->init_amp = ALC_INIT_DEFAULT;
break;
}
{ }
};
+/*
+ *ALC888 Acer Aspire 7730G model
+ */
+
+static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
+/* Bias voltage on for external mic port */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
+/* Front Mic: set to PIN_IN (empty by default) */
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
+/* Enable unsolicited event for HP jack */
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+/* Enable speaker output */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+/* Enable headphone output */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+/*Enable internal subwoofer */
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
+ {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
+ { }
+};
+
/*
* ALC889 Acer Aspire 8930G model
*/
spec->autocfg.speaker_pins[2] = 0x17;
}
+static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ spec->autocfg.hp_pins[0] = 0x15;
+ spec->autocfg.speaker_pins[0] = 0x14;
+ spec->autocfg.speaker_pins[1] = 0x16;
+ spec->autocfg.speaker_pins[2] = 0x17;
+}
+
static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
+ SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
{ }
};
-static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { } /* end */
-};
-
static void alc888_6st_dell_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
- SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
.const_channel_count = 6,
.input_mux = &alc883_capture_source,
.unsol_event = alc_automute_amp_unsol_event,
- .setup = alc888_acer_aspire_6530g_setup,
+ .setup = alc888_acer_aspire_7730g_setup,
.init_hook = alc_automute_amp,
},
[ALC883_MEDION] = {
/* different alc269-variants */
enum {
ALC269_TYPE_NORMAL,
+ ALC269_TYPE_ALC258,
ALC269_TYPE_ALC259,
+ ALC269_TYPE_ALC269VB,
+ ALC269_TYPE_ALC270,
ALC269_TYPE_ALC271X,
};
static int patch_alc269(struct hda_codec *codec)
{
struct alc_spec *spec;
- int board_config;
+ int board_config, coef;
int err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
alc_auto_parse_customize_define(codec);
- if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
+ coef = alc_read_coef_idx(codec, 0);
+ if ((coef & 0x00f0) == 0x0010) {
if (codec->bus->pci->subsystem_vendor == 0x1025 &&
spec->cdefine.platform_type == 1) {
alc_codec_rename(codec, "ALC271X");
spec->codec_variant = ALC269_TYPE_ALC271X;
- } else {
+ } else if ((coef & 0xf000) == 0x1000) {
+ spec->codec_variant = ALC269_TYPE_ALC270;
+ } else if ((coef & 0xf000) == 0x2000) {
alc_codec_rename(codec, "ALC259");
spec->codec_variant = ALC269_TYPE_ALC259;
+ } else if ((coef & 0xf000) == 0x3000) {
+ alc_codec_rename(codec, "ALC258");
+ spec->codec_variant = ALC269_TYPE_ALC258;
+ } else {
+ alc_codec_rename(codec, "ALC269VB");
+ spec->codec_variant = ALC269_TYPE_ALC269VB;
}
} else
alc_fix_pll_init(codec, 0x20, 0x04, 15);
spec->stream_digital_capture = &alc269_pcm_digital_capture;
if (!spec->adc_nids) { /* wasn't filled automatically? use default */
- if (spec->codec_variant != ALC269_TYPE_NORMAL) {
+ if (spec->codec_variant == ALC269_TYPE_NORMAL) {
spec->adc_nids = alc269_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
spec->capsrc_nids = alc269_capsrc_nids;
static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
+ return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
}
return 0x02;
else if (nid >= 0x0c && nid <= 0x0e)
return nid - 0x0c + 0x02;
+ else if (nid == 0x26) /* ALC887-VD has this DAC too */
+ return 0x25;
else
return 0;
}
static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
hda_nid_t dac)
{
- hda_nid_t mix[4];
+ hda_nid_t mix[5];
int i, num;
num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
static struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+ SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
{}
{
if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
kfree(codec->chip_name);
- codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
+ if (codec->vendor_id == 0x10ec0887)
+ codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
+ else
+ codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
if (!codec->chip_name) {
alc_free(codec);
return -ENOMEM;
{ .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
.patch = patch_alc882 },
{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
- { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
+ { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
{ .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
.patch = patch_alc882 },
{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
0x11, 0x20, 0
};
+#define STAC92HD87B_NUM_DMICS 1
+static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = {
+ 0x11, 0
+};
+
#define STAC92HD83XXX_NUM_CAPS 2
static unsigned long stac92hd83xxx_capvols[] = {
HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1,
"Alienware M17x", STAC_ALIENWARE_M17X),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
+ "Alienware M17x", STAC_ALIENWARE_M17X),
{} /* terminator */
};
return err;
}
- if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) {
+ if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1)
snd_hda_add_imux_item(imux, label, index, NULL);
- spec->num_analog_muxes++;
- }
}
return 0;
stac92hd83xxx_brd_tbl[spec->board_config]);
switch (codec->vendor_id) {
+ case 0x111d76d1:
+ case 0x111d76d9:
+ spec->dmic_nids = stac92hd87b_dmic_nids;
+ spec->num_dmics = stac92xx_connected_ports(codec,
+ stac92hd87b_dmic_nids,
+ STAC92HD87B_NUM_DMICS);
+ /* Fall through */
case 0x111d7666:
case 0x111d7667:
case 0x111d7668:
case 0x111d7669:
- case 0x111d76d1:
- case 0x111d76d9:
spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
spec->pin_nids = stac92hd88xxx_pin_nids;
spec->mono_nid = 0;
.name = "Dell Inspiron 8600", /* STAC9750/51 */
.type = AC97_TUNE_HP_ONLY
},
+ {
+ .subvendor = 0x1028,
+ .subdevice = 0x0182,
+ .name = "Dell Latitude D610", /* STAC9750/51 */
+ .type = AC97_TUNE_HP_ONLY
+ },
{
.subvendor = 0x1028,
.subdevice = 0x0186,
#include <sound/hwdep.h>
+#ifndef readl_be
#define readl_be(x) be32_to_cpu(__raw_readl(x))
+#endif
+
+#ifndef writel_be
#define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr)
+#endif
+#ifndef readl_le
#define readl_le(x) le32_to_cpu(__raw_readl(x))
+#endif
+
+#ifndef writel_le
#define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr)
+#endif
#define MIXART_MEM(mgr,x) ((mgr)->mem[0].virt + (x))
#define MIXART_REG(mgr,x) ((mgr)->mem[1].virt + (x))
chip->rsrc[i].start + 1,
rnames[i]) == NULL) {
printk(KERN_ERR "snd: can't request rsrc "
- " %d (%s: 0x%016llx:%016llx)\n",
- i, rnames[i],
- (unsigned long long)chip->rsrc[i].start,
- (unsigned long long)chip->rsrc[i].end);
+ " %d (%s: %pR)\n",
+ i, rnames[i], &chip->rsrc[i]);
err = -ENODEV;
goto __error;
}
chip->rsrc[i].start + 1,
rnames[i]) == NULL) {
printk(KERN_ERR "snd: can't request rsrc "
- " %d (%s: 0x%016llx:%016llx)\n",
- i, rnames[i],
- (unsigned long long)chip->rsrc[i].start,
- (unsigned long long)chip->rsrc[i].end);
+ " %d (%s: %pR)\n",
+ i, rnames[i], &chip->rsrc[i]);
err = -ENODEV;
goto __error;
}
config SND_AT91_SOC_SAM9G20_WM8731
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
- depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC
+ depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC && \
+ AT91_PROGRAMMABLE_CLOCKS
select SND_ATMEL_SOC_SSC
select SND_SOC_WM8731
help
config SND_AT32_SOC_PLAYPAQ
tristate "SoC Audio support for PlayPaq with WM8510"
- depends on SND_ATMEL_SOC && BOARD_PLAYPAQ
+ depends on SND_ATMEL_SOC && BOARD_PLAYPAQ && AT91_PROGRAMMABLE_CLOCKS
select SND_ATMEL_SOC_SSC
select SND_SOC_WM8510
help
}
pllb = clk_get(NULL, "pllb");
- if (IS_ERR(mclk)) {
+ if (IS_ERR(pllb)) {
printk(KERN_ERR "ASoC: Failed to get PLLB\n");
- ret = PTR_ERR(mclk);
+ ret = PTR_ERR(pllb);
goto err_mclk;
}
ret = clk_set_parent(mclk, pllb);
if (!at91sam9g20ek_snd_device) {
printk(KERN_ERR "ASoC: Platform device allocation failed\n");
ret = -ENOMEM;
+ goto err_mclk;
}
platform_set_drvdata(at91sam9g20ek_snd_device,
ret = platform_device_add(at91sam9g20ek_snd_device);
if (ret) {
printk(KERN_ERR "ASoC: Platform device allocation failed\n");
- platform_device_put(at91sam9g20ek_snd_device);
+ goto err_device_add;
}
return ret;
+err_device_add:
+ platform_device_put(at91sam9g20ek_snd_device);
err_mclk:
clk_put(mclk);
mclk = NULL;
return 0;
err1:
- platform_device_del(afeb9260_snd_device);
platform_device_put(afeb9260_snd_device);
return err;
}
#include <sound/max98088.h>
#include "max98088.h"
+enum max98088_type {
+ MAX98088,
+ MAX98089,
+};
+
struct max98088_cdata {
unsigned int rate;
unsigned int fmt;
struct max98088_priv {
u8 reg_cache[M98088_REG_CNT];
+ enum max98088_type devtype;
void *control_data;
struct max98088_pdata *pdata;
unsigned int sysclk;
static int max98088_remove(struct snd_soc_codec *codec)
{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ kfree(max98088->eq_texts);
return 0;
}
if (max98088 == NULL)
return -ENOMEM;
+ max98088->devtype = id->driver_data;
+
i2c_set_clientdata(i2c, max98088);
max98088->control_data = i2c;
max98088->pdata = i2c->dev.platform_data;
}
static const struct i2c_device_id max98088_i2c_id[] = {
- { "max98088", 0 },
+ { "max98088", MAX98088 },
+ { "max98089", MAX98089 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
.reg_cache_size = sizeof(stac9766_reg),
.reg_word_size = sizeof(u16),
.reg_cache_step = 2,
+ .reg_cache_default = stac9766_reg,
};
static __devinit int stac9766_probe(struct platform_device *pdev)
int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio)
{
u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
- u8 val, bit = gpio ? 2: 1;
+ u8 val = 0, bit = gpio ? 2 : 1;
aic3x_read(codec, reg, &val);
return (val >> bit) & 1;
int aic3x_headset_detected(struct snd_soc_codec *codec)
{
- u8 val;
+ u8 val = 0;
aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val);
return (val >> 4) & 1;
}
int aic3x_button_pressed(struct snd_soc_codec *codec)
{
- u8 val;
+ u8 val = 0;
aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val);
return (val >> 5) & 1;
}
if (data->power_state) {
val = i2c_smbus_write_byte_data(tpa6130a2_client, reg, value);
- if (val < 0)
+ if (val < 0) {
dev_err(&tpa6130a2_client->dev, "Write failed\n");
+ return val;
+ }
}
/* Either powered on or off, we save the context */
.resume = uda134x_soc_resume,
.reg_cache_size = sizeof(uda134x_reg),
.reg_word_size = sizeof(u8),
+ .reg_cache_default = uda134x_reg,
.reg_cache_step = 1,
.read = uda134x_read_reg_cache,
.write = uda134x_write,
}
/* MCLK direction */
- if (dir == WM8350_MCLK_DIR_OUT)
+ if (dir == SND_SOC_CLOCK_OUT)
wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2,
WM8350_MCLK_DIR);
else
wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME,
WM8350_OUT2_VU | WM8350_OUT2R_MUTE);
+ /* Make sure AIF tristating is disabled by default */
+ wm8350_clear_bits(wm8350, WM8350_AI_FORMATING, WM8350_AIF_TRI);
+
+ /* Make sure we've got a sane companding setup too */
+ wm8350_clear_bits(wm8350, WM8350_ADC_DAC_COMP,
+ WM8350_DAC_COMP | WM8350_LOOPBACK);
+
/* Make sure jack detect is disabled to start off with */
wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
WM8350_JDL_ENA | WM8350_JDR_ENA);
return -EINVAL;
}
- return 0;
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&wm8523->rate_constraint);
paifa |= 0x8;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
- paifa |= 0x10;
+ paifa |= 0x0;
paifb |= WM8580_AIF_LENGTH_20;
break;
case SNDRV_PCM_FORMAT_S24_LE:
- paifa |= 0x10;
+ paifa |= 0x0;
paifb |= WM8580_AIF_LENGTH_24;
break;
case SNDRV_PCM_FORMAT_S32_LE:
- paifa |= 0x10;
- paifb |= WM8580_AIF_LENGTH_24;
+ paifa |= 0x0;
+ paifb |= WM8580_AIF_LENGTH_32;
break;
default:
return -EINVAL;
snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0);
/* Disable bypass path by default */
- snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0);
+ snd_soc_update_bits(codec, WM8731_APANA, 0x8, 0);
snd_soc_add_controls(codec, wm8731_snd_controls,
ARRAY_SIZE(wm8731_snd_controls));
/* codec private data */
struct wm8776_priv {
enum snd_soc_control_type control_type;
- u16 reg_cache[WM8776_CACHEREGNUM];
int sysclk[2];
};
wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
+ kfree(wm8904->retune_mobile_texts);
+ kfree(wm8904->drc_texts);
return 0;
}
if (fs <= 24000)
reg |= WM8961_DACSLOPE;
else
- reg &= WM8961_DACSLOPE;
+ reg &= ~WM8961_DACSLOPE;
snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
return 0;
freq /= 2;
} else {
dev_dbg(codec->dev, "Using MCLK/1 for %dHz MCLK\n", freq);
- reg &= WM8961_MCLKDIV;
+ reg &= ~WM8961_MCLKDIV;
}
snd_soc_write(codec, WM8961_CLOCKING1, reg);
int mask;
int active;
- mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
+ mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2_MASK);
active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
active &= ~mask;
{
struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
long int time;
+ int ret;
- strict_strtol(buf, 10, &time);
+ ret = strict_strtol(buf, 10, &time);
+ if (ret != 0)
+ return ret;
input_event(wm8962->beep, EV_SND, SND_TONE, time);
return -ENOMEM;
snd_soc_codec_set_drvdata(codec, wm8994);
+ codec->reg_cache = &wm8994->reg_cache;
+
wm8994->pdata = dev_get_platdata(codec->dev->parent);
wm8994->codec = codec;
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
+ kfree(wm8994->retune_mobile_texts);
+ kfree(wm8994->drc_texts);
kfree(wm8994);
return 0;
.resume = wm8994_resume,
.read = wm8994_read,
.write = wm8994_write,
+ .readable_register = wm8994_readable,
+ .volatile_register = wm8994_volatile,
.set_bias_level = wm8994_set_bias_level,
};
SOC_DOUBLE_R("Speaker ZC Switch",
WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
7, 1, 0),
-SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 0, 3, 7, 0,
+SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 3, 0, 7, 0,
spkboost_tlv),
SOC_ENUM("Speaker Reference", speaker_ref),
SOC_ENUM("Speaker Mode", speaker_mode),
}
/* davinci-evm digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link evm_dai = {
+static struct snd_soc_dai_link dm6446_evm_dai = {
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
- .cpu_dai_name = "davinci-mcasp.0",
+ .cpu_dai_name = "davinci-mcbsp",
.codec_dai_name = "tlv320aic3x-hifi",
- .codec_name = "tlv320aic3x-codec.0-001a",
+ .codec_name = "tlv320aic3x-codec.1-001b",
+ .platform_name = "davinci-pcm-audio",
+ .init = evm_aic3x_init,
+ .ops = &evm_ops,
+};
+
+static struct snd_soc_dai_link dm355_evm_dai = {
+ .name = "TLV320AIC3X",
+ .stream_name = "AIC3X",
+ .cpu_dai_name = "davinci-mcbsp.1",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .codec_name = "tlv320aic3x-codec.1-001b",
.platform_name = "davinci-pcm-audio",
.init = evm_aic3x_init,
.ops = &evm_ops,
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
- .cpu_dai_name = "davinci-i2s",
+ .cpu_dai_name = "davinci-mcbsp",
.codec_dai_name = "tlv320aic3x-hifi",
.init = evm_aic3x_init,
- .codec_name = "tlv320aic3x-codec.0-001a",
+ .codec_name = "tlv320aic3x-codec.1-0018",
.ops = &evm_ops,
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
.name = "Voice Codec - CQ93VC",
.ops = &evm_ops,
};
-/* davinci dm6446, dm355 evm audio machine driver */
-static struct snd_soc_card snd_soc_card_evm = {
- .name = "DaVinci EVM",
- .dai_link = &evm_dai,
+/* davinci dm6446 evm audio machine driver */
+static struct snd_soc_card dm6446_snd_soc_card_evm = {
+ .name = "DaVinci DM6446 EVM",
+ .dai_link = &dm6446_evm_dai,
+ .num_links = 1,
+};
+
+/* davinci dm355 evm audio machine driver */
+static struct snd_soc_card dm355_snd_soc_card_evm = {
+ .name = "DaVinci DM355 EVM",
+ .dai_link = &dm355_evm_dai,
.num_links = 1,
};
int ret;
if (machine_is_davinci_evm()) {
- evm_snd_dev_data = &snd_soc_card_evm;
+ evm_snd_dev_data = &dm6446_snd_soc_card_evm;
index = 0;
} else if (machine_is_davinci_dm355_evm()) {
- evm_snd_dev_data = &snd_soc_card_evm;
+ evm_snd_dev_data = &dm355_snd_soc_card_evm;
index = 1;
} else if (machine_is_davinci_dm365_evm()) {
evm_snd_dev_data = &dm365_snd_soc_card_evm;
snd_pcm_format_t fmt;
unsigned element_cnt = 1;
- dai->capture_dma_data = dev->dma_params;
- dai->playback_dma_data = dev->dma_params;
-
/* general line settings */
spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
return ret;
}
+static int davinci_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
+ return 0;
+}
+
static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000
static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
+ .startup = davinci_i2s_startup,
.shutdown = davinci_i2s_shutdown,
.prepare = davinci_i2s_prepare,
.trigger = davinci_i2s_trigger,
.probe = davinci_i2s_probe,
.remove = davinci_i2s_remove,
.driver = {
- .name = "davinci-i2s",
+ .name = "davinci-mcbsp",
.owner = THIS_MODULE,
},
};
int word_length;
u8 fifo_level;
- cpu_dai->capture_dma_data = dev->dma_params;
- cpu_dai->playback_dma_data = dev->dma_params;
-
davinci_hw_common_param(dev, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
fifo_level = dev->txnumevt;
return ret;
}
+static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
+ return 0;
+}
+
static struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
+ .startup = davinci_mcasp_startup,
.trigger = davinci_mcasp_trigger,
.hw_params = davinci_mcasp_hw_params,
.set_fmt = davinci_mcasp_set_dai_fmt,
static struct snd_soc_dai_link sffsdr_dai = {
.name = "PCM3008", /* Codec name */
.stream_name = "PCM3008 HiFi",
- .cpu_dai_name = "davinci-asp.0",
+ .cpu_dai_name = "davinci-mcbsp",
.codec_dai_name = "pcm3008-hifi",
.codec_name = "pcm3008-codec",
.platform_name = "davinci-pcm-audio",
&davinci_vcif_dev->dma_params[substream->stream];
u32 w;
- dai->capture_dma_data = davinci_vcif_dev->dma_params;
- dai->playback_dma_data = davinci_vcif_dev->dma_params;
-
/* Restart the codec before setup */
davinci_vcif_stop(substream);
davinci_vcif_start(substream);
return ret;
}
+static int davinci_vcif_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
+ return 0;
+}
+
#define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000
static struct snd_soc_dai_ops davinci_vcif_dai_ops = {
+ .startup = davinci_vcif_startup,
.trigger = davinci_vcif_trigger,
.hw_params = davinci_vcif_hw_params,
};
static int davinci_vcif_remove(struct platform_device *pdev)
{
+ struct davinci_vcif_dev *davinci_vcif_dev = dev_get_drvdata(&pdev->dev);
+
snd_soc_unregister_dai(&pdev->dev);
+ kfree(davinci_vcif_dev);
return 0;
}
ret = platform_device_add(simone_snd_ac97_device);
if (ret)
- goto fail;
+ goto fail1;
simone_snd_device = platform_device_alloc("soc-audio", -1);
if (!simone_snd_device) {
ret = -ENOMEM;
- goto fail;
+ goto fail2;
}
platform_set_drvdata(simone_snd_device, &snd_soc_simone);
ret = platform_device_add(simone_snd_device);
- if (ret) {
- platform_device_put(simone_snd_device);
- goto fail;
- }
+ if (ret)
+ goto fail3;
- return ret;
+ return 0;
-fail:
+fail3:
+ platform_device_put(simone_snd_device);
+fail2:
+ platform_device_del(simone_snd_ac97_device);
+fail1:
platform_device_put(simone_snd_ac97_device);
return ret;
}
rc = platform_device_add(pdev);
if (rc) {
pr_err("efika_fabric_init: platform_device_add() failed\n");
+ platform_device_put(pdev);
return -ENODEV;
}
return 0;
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <sound/soc.h>
rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
if (rc != 0) {
pr_err("Failed to register DAI\n");
- return 0;
+ return rc;
}
psc_dma = dev_get_drvdata(&op->dev);
dev_err(&pdev->dev, "platform device add failed\n");
goto error;
}
+ dev_set_drvdata(&pdev->dev, sound_device);
of_node_put(codec_np);
dev_err(&pdev->dev, "platform device add failed\n");
goto error;
}
+ dev_set_drvdata(&pdev->dev, sound_device);
of_node_put(codec_np);
rc = platform_device_add(pdev);
if (rc) {
pr_err("pcm030_fabric_init: platform_device_add() failed\n");
+ platform_device_put(pdev);
return -ENODEV;
}
return 0;
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
static struct snd_soc_dai_link eukrea_tlv320_dai = {
.name = "tlv320aic23",
.stream_name = "TLV320AIC23",
- .codec_dai = "tlv320aic23-hifi",
+ .codec_dai_name = "tlv320aic23-hifi",
.platform_name = "imx-pcm-audio.0",
.codec_name = "tlv320aic23-codec.0-001a",
- .cpu_dai = "imx-ssi.0",
+ .cpu_dai_name = "imx-ssi.0",
.ops = &eukrea_tlv320_snd_ops,
};
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/dmaengine.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <mach/dma-mx1-mx2.h>
+#include <mach/dma.h>
#include "imx-ssi.h"
struct imx_pcm_runtime_data {
- int sg_count;
- struct scatterlist *sg_list;
- int period;
+ int period_bytes;
int periods;
- unsigned long dma_addr;
int dma;
- struct snd_pcm_substream *substream;
unsigned long offset;
unsigned long size;
- unsigned long period_cnt;
void *buf;
int period_time;
+ struct dma_async_tx_descriptor *desc;
+ struct dma_chan *dma_chan;
+ struct imx_dma_data dma_data;
};
-/* Called by the DMA framework when a period has elapsed */
-static void imx_ssi_dma_progression(int channel, void *data,
- struct scatterlist *sg)
+static void audio_dma_irq(void *data)
{
- struct snd_pcm_substream *substream = data;
+ struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
- if (!sg)
- return;
-
- runtime = iprtd->substream->runtime;
+ iprtd->offset += iprtd->period_bytes;
+ iprtd->offset %= iprtd->period_bytes * iprtd->periods;
- iprtd->offset = sg->dma_address - runtime->dma_addr;
-
- snd_pcm_period_elapsed(iprtd->substream);
+ snd_pcm_period_elapsed(substream);
}
-static void imx_ssi_dma_callback(int channel, void *data)
+static bool filter(struct dma_chan *chan, void *param)
{
- pr_err("%s shouldn't be called\n", __func__);
-}
+ struct imx_pcm_runtime_data *iprtd = param;
-static void snd_imx_dma_err_callback(int channel, void *data, int err)
-{
- struct snd_pcm_substream *substream = data;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct imx_pcm_dma_params *dma_params =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct imx_pcm_runtime_data *iprtd = runtime->private_data;
- int ret;
+ if (!imx_dma_is_general_purpose(chan))
+ return false;
- pr_err("DMA timeout on channel %d -%s%s%s%s\n",
- channel,
- err & IMX_DMA_ERR_BURST ? " burst" : "",
- err & IMX_DMA_ERR_REQUEST ? " request" : "",
- err & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
- err & IMX_DMA_ERR_BUFFER ? " buffer" : "");
+ chan->private = &iprtd->dma_data;
- imx_dma_disable(iprtd->dma);
- ret = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
- IMX_DMA_LENGTH_LOOP, dma_params->dma_addr,
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- DMA_MODE_WRITE : DMA_MODE_READ);
- if (!ret)
- imx_dma_enable(iprtd->dma);
+ return true;
}
-static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
+static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct imx_pcm_dma_params *dma_params;
struct snd_pcm_runtime *runtime = substream->runtime;
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+ struct dma_slave_config slave_config;
+ dma_cap_mask_t mask;
+ enum dma_slave_buswidth buswidth;
int ret;
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
- iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
- if (iprtd->dma < 0) {
- pr_err("Failed to claim the audio DMA\n");
- return -ENODEV;
- }
+ iprtd->dma_data.peripheral_type = IMX_DMATYPE_SSI;
+ iprtd->dma_data.priority = DMA_PRIO_HIGH;
+ iprtd->dma_data.dma_request = dma_params->dma;
- ret = imx_dma_setup_handlers(iprtd->dma,
- imx_ssi_dma_callback,
- snd_imx_dma_err_callback, substream);
- if (ret)
- goto out;
+ /* Try to grab a DMA channel */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ iprtd->dma_chan = dma_request_channel(mask, filter, iprtd);
+ if (!iprtd->dma_chan)
+ return -EINVAL;
- ret = imx_dma_setup_progression_handler(iprtd->dma,
- imx_ssi_dma_progression);
- if (ret) {
- pr_err("Failed to setup the DMA handler\n");
- goto out;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ break;
+ default:
+ return 0;
}
- ret = imx_dma_config_channel(iprtd->dma,
- IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
- IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
- dma_params->dma, 1);
- if (ret < 0) {
- pr_err("Cannot configure DMA channel: %d\n", ret);
- goto out;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ slave_config.direction = DMA_TO_DEVICE;
+ slave_config.dst_addr = dma_params->dma_addr;
+ slave_config.dst_addr_width = buswidth;
+ slave_config.dst_maxburst = dma_params->burstsize;
+ } else {
+ slave_config.direction = DMA_FROM_DEVICE;
+ slave_config.src_addr = dma_params->dma_addr;
+ slave_config.src_addr_width = buswidth;
+ slave_config.src_maxburst = dma_params->burstsize;
}
- imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2);
+ ret = dmaengine_slave_config(iprtd->dma_chan, &slave_config);
+ if (ret)
+ return ret;
return 0;
-out:
- imx_dma_free(iprtd->dma);
- return ret;
}
static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
- int i;
unsigned long dma_addr;
+ struct dma_chan *chan;
+ struct imx_pcm_dma_params *dma_params;
+ int ret;
- imx_ssi_dma_alloc(substream);
+ dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ ret = imx_ssi_dma_alloc(substream, params);
+ if (ret)
+ return ret;
+ chan = iprtd->dma_chan;
iprtd->size = params_buffer_bytes(params);
iprtd->periods = params_periods(params);
- iprtd->period = params_period_bytes(params);
+ iprtd->period_bytes = params_period_bytes(params);
iprtd->offset = 0;
iprtd->period_time = HZ / (params_rate(params) /
params_period_size(params));
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
- if (iprtd->sg_count != iprtd->periods) {
- kfree(iprtd->sg_list);
-
- iprtd->sg_list = kcalloc(iprtd->periods + 1,
- sizeof(struct scatterlist), GFP_KERNEL);
- if (!iprtd->sg_list)
- return -ENOMEM;
- iprtd->sg_count = iprtd->periods + 1;
- }
-
- sg_init_table(iprtd->sg_list, iprtd->sg_count);
dma_addr = runtime->dma_addr;
- for (i = 0; i < iprtd->periods; i++) {
- iprtd->sg_list[i].page_link = 0;
- iprtd->sg_list[i].offset = 0;
- iprtd->sg_list[i].dma_address = dma_addr;
- iprtd->sg_list[i].length = iprtd->period;
- dma_addr += iprtd->period;
+ iprtd->buf = (unsigned int *)substream->dma_buffer.area;
+
+ iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr,
+ iprtd->period_bytes * iprtd->periods,
+ iprtd->period_bytes,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ if (!iprtd->desc) {
+ dev_err(&chan->dev->device, "cannot prepare slave dma\n");
+ return -EINVAL;
}
- /* close the loop */
- iprtd->sg_list[iprtd->sg_count - 1].offset = 0;
- iprtd->sg_list[iprtd->sg_count - 1].length = 0;
- iprtd->sg_list[iprtd->sg_count - 1].page_link =
- ((unsigned long) iprtd->sg_list | 0x01) & ~0x02;
+ iprtd->desc->callback = audio_dma_irq;
+ iprtd->desc->callback_param = substream;
+
return 0;
}
struct snd_pcm_runtime *runtime = substream->runtime;
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
- if (iprtd->dma >= 0) {
- imx_dma_free(iprtd->dma);
- iprtd->dma = -EINVAL;
+ if (iprtd->dma_chan) {
+ dma_release_channel(iprtd->dma_chan);
+ iprtd->dma_chan = NULL;
}
- kfree(iprtd->sg_list);
- iprtd->sg_list = NULL;
-
return 0;
}
static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct imx_pcm_dma_params *dma_params;
- struct imx_pcm_runtime_data *iprtd = runtime->private_data;
- int err;
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
- iprtd->substream = substream;
- iprtd->buf = (unsigned int *)substream->dma_buffer.area;
- iprtd->period_cnt = 0;
-
- pr_debug("%s: buf: %p period: %d periods: %d\n",
- __func__, iprtd->buf, iprtd->period, iprtd->periods);
-
- err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
- IMX_DMA_LENGTH_LOOP, dma_params->dma_addr,
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- DMA_MODE_WRITE : DMA_MODE_READ);
- if (err)
- return err;
-
return 0;
}
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- imx_dma_enable(iprtd->dma);
+ dmaengine_submit(iprtd->desc);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- imx_dma_disable(iprtd->dma);
+ dmaengine_terminate_all(iprtd->dma_chan);
break;
default:
struct snd_pcm_runtime *runtime = substream->runtime;
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+ pr_debug("%s: %ld %ld\n", __func__, iprtd->offset,
+ bytes_to_frames(substream->runtime, iprtd->offset));
+
return bytes_to_frames(substream->runtime, iprtd->offset);
}
.channels_max = 2,
.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
.period_bytes_min = 128,
- .period_bytes_max = 16 * 1024,
+ .period_bytes_max = 65535, /* Limited by SDMA engine */
.periods_min = 2,
.periods_max = 255,
.fifo_size = 0,
}
snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
+
+ return 0;
+}
+
+static int snd_imx_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+
+ kfree(iprtd);
+
return 0;
}
static struct snd_pcm_ops imx_pcm_ops = {
.open = snd_imx_open,
+ .close = snd_imx_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_imx_pcm_hw_params,
.hw_free = snd_imx_pcm_hw_free,
.name = "imx-pcm-audio",
.owner = THIS_MODULE,
},
-
.probe = imx_soc_platform_probe,
.remove = __devexit_p(imx_soc_platform_remove),
};
platform_driver_unregister(&imx_pcm_driver);
}
module_exit(snd_imx_pcm_exit);
-
}
EXPORT_SYMBOL_GPL(imx_pcm_free);
+static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
+{
+ struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
+ uint32_t val;
+
+ snd_soc_dai_set_drvdata(dai, ssi);
+
+ val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
+ SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
+ writel(val, ssi->base + SSI_SFCSR);
+
+ return 0;
+}
+
static struct snd_soc_dai_driver imx_ssi_dai = {
+ .probe = imx_ssi_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
.ops = &imx_ssi_pcm_dai_ops,
};
-static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
-{
- struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
- uint32_t val;
-
- snd_soc_dai_set_drvdata(dai, ssi);
-
- val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
- SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
- writel(val, ssi->base + SSI_SFCSR);
-
- return 0;
-}
-
static struct snd_soc_dai_driver imx_ac97_dai = {
.probe = imx_ssi_dai_probe,
.ac97_control = 1,
goto failed_register;
}
- ssi->soc_platform_pdev = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
- if (!ssi->soc_platform_pdev)
+ ssi->soc_platform_pdev_fiq = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
+ if (!ssi->soc_platform_pdev_fiq) {
+ ret = -ENOMEM;
+ goto failed_pdev_fiq_alloc;
+ }
+
+ platform_set_drvdata(ssi->soc_platform_pdev_fiq, ssi);
+ ret = platform_device_add(ssi->soc_platform_pdev_fiq);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform device\n");
+ goto failed_pdev_fiq_add;
+ }
+
+ ssi->soc_platform_pdev = platform_device_alloc("imx-pcm-audio", pdev->id);
+ if (!ssi->soc_platform_pdev) {
+ ret = -ENOMEM;
goto failed_pdev_alloc;
+ }
+
platform_set_drvdata(ssi->soc_platform_pdev, ssi);
ret = platform_device_add(ssi->soc_platform_pdev);
if (ret) {
failed_pdev_add:
platform_device_put(ssi->soc_platform_pdev);
failed_pdev_alloc:
+ platform_device_del(ssi->soc_platform_pdev_fiq);
+failed_pdev_fiq_add:
+ platform_device_put(ssi->soc_platform_pdev_fiq);
+failed_pdev_fiq_alloc:
snd_soc_unregister_dai(&pdev->dev);
failed_register:
failed_ac97:
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct imx_ssi *ssi = platform_get_drvdata(pdev);
- platform_device_del(ssi->soc_platform_pdev);
- platform_device_put(ssi->soc_platform_pdev);
+ platform_device_unregister(ssi->soc_platform_pdev);
+ platform_device_unregister(ssi->soc_platform_pdev_fiq);
snd_soc_unregister_dai(&pdev->dev);
#define DRV_NAME "imx-ssi"
+#include <linux/dmaengine.h>
+#include <mach/dma.h>
+
struct imx_pcm_dma_params {
int dma;
unsigned long dma_addr;
int enabled;
struct platform_device *soc_platform_pdev;
+ struct platform_device *soc_platform_pdev_fiq;
};
struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
#include <sound/soc-dapm.h>
#include <asm/mach-types.h>
-#include "../codecs/wm9712.h"
-#include "imx-ssi.h"
-
static struct snd_soc_card imx_phycore;
static struct snd_soc_ops imx_phycore_hifi_ops = {
};
static struct snd_soc_card imx_phycore = {
- .name = "PhyCORE-audio",
+ .name = "PhyCORE-ac97-audio",
.dai_link = imx_phycore_dai_ac97,
.num_links = ARRAY_SIZE(imx_phycore_dai_ac97),
};
+static struct platform_device *imx_phycore_snd_ac97_device;
static struct platform_device *imx_phycore_snd_device;
static int __init imx_phycore_init(void)
/* return happy. We might run on a totally different machine */
return 0;
- imx_phycore_snd_device = platform_device_alloc("soc-audio", -1);
- if (!imx_phycore_snd_device)
+ imx_phycore_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+ if (!imx_phycore_snd_ac97_device)
return -ENOMEM;
- platform_set_drvdata(imx_phycore_snd_device, &imx_phycore);
- ret = platform_device_add(imx_phycore_snd_device);
+ platform_set_drvdata(imx_phycore_snd_ac97_device, &imx_phycore);
+ ret = platform_device_add(imx_phycore_snd_ac97_device);
+ if (ret)
+ goto fail1;
imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1);
- if (!imx_phycore_snd_device)
- return -ENOMEM;
+ if (!imx_phycore_snd_device) {
+ ret = -ENOMEM;
+ goto fail2;
+ }
ret = platform_device_add(imx_phycore_snd_device);
if (ret) {
printk(KERN_ERR "ASoC: Platform device allocation failed\n");
- platform_device_put(imx_phycore_snd_device);
+ goto fail3;
}
+ return 0;
+
+fail3:
+ platform_device_put(imx_phycore_snd_device);
+fail2:
+ platform_device_del(imx_phycore_snd_ac97_device);
+fail1:
+ platform_device_put(imx_phycore_snd_ac97_device);
return ret;
}
static void __exit imx_phycore_exit(void)
{
platform_device_unregister(imx_phycore_snd_device);
+ platform_device_unregister(imx_phycore_snd_ac97_device);
}
late_initcall(imx_phycore_init);
mutex_lock(&ac97_mutex);
val = nuc900_checkready();
- if (!!val) {
+ if (val) {
dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
goto out;
}
mutex_lock(&ac97_mutex);
tmp = nuc900_checkready();
- if (!!tmp)
+ if (tmp)
dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
/* clear the R_WB bit and write register index */
udelay(100);
val = nuc900_checkready();
- if (!!val)
+ if (val)
dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
mutex_unlock(&ac97_mutex);
return ret;
}
-static int nuc900_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int nuc900_ac97_probe(struct snd_soc_dai *dai)
{
struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
unsigned long val;
return 0;
}
-static void nuc900_ac97_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int nuc900_ac97_remove(struct snd_soc_dai *dai)
{
struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
clk_disable(nuc900_audio->clk);
+ return 0;
}
static struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
.channels_max = 2,
},
.ops = &nuc900_ac97_dai_ops,
-}
+};
static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
{
static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
{
-
snd_soc_unregister_dai(&pdev->dev);
clk_put(nuc900_ac97_data->clk);
release_mem_region(nuc900_ac97_data->res->start,
resource_size(nuc900_ac97_data->res));
+ kfree(nuc900_ac97_data);
nuc900_ac97_data = NULL;
return 0;
};
+extern struct nuc900_audio *nuc900_ac97_data;
+
#endif /*end _NUC900_AUDIO_H */
unsigned long flags;
int ret = 0;
- spin_lock_irqsave(&nuc900_audio->lock, flags);
-
ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
if (ret < 0)
return ret;
+ spin_lock_irqsave(&nuc900_audio->lock, flags);
+
nuc900_audio->substream = substream;
nuc900_audio->dma_addr[substream->stream] = runtime->dma_addr;
nuc900_audio->buffersize[substream->stream] =
struct snd_pcm_runtime *runtime = substream->runtime;
struct nuc900_audio *nuc900_audio = runtime->private_data;
unsigned long flags, val;
+ int ret = 0;
spin_lock_irqsave(&nuc900_audio->lock, flags);
AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
spin_unlock_irqrestore(&nuc900_audio->lock, flags);
- return 0;
+ return ret;
}
static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd)
.ops = &nuc900_dma_ops,
.pcm_new = nuc900_dma_new,
.pcm_free = nuc900_dma_free_dma_buffers,
-}
+};
static int __devinit nuc900_soc_platform_probe(struct platform_device *pdev)
{
config SND_OMAP_SOC_N810
tristate "SoC Audio support for Nokia N810"
depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C
+ depends on OMAP_MUX
select SND_OMAP_SOC_MCBSP
- select OMAP_MUX
select SND_SOC_TLV320AIC3X
help
Say Y if you want to add support for SoC audio on Nokia N810.
case OMAP_MCBSP_CLKR_SRC_CLKR:
+ if (cpu_class_is_omap1())
+ break;
omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR);
break;
case OMAP_MCBSP_CLKR_SRC_CLKX:
+ if (cpu_class_is_omap1())
+ break;
omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX);
break;
case OMAP_MCBSP_FSR_SRC_FSR:
+ if (cpu_class_is_omap1())
+ break;
omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR);
break;
case OMAP_MCBSP_FSR_SRC_FSX:
+ if (cpu_class_is_omap1())
+ break;
omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX);
break;
default:
pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n",
dev_name(&omap3pandora_snd_device->dev),
PTR_ERR(omap3pandora_dac_reg));
+ ret = PTR_ERR(omap3pandora_dac_reg);
goto fail3;
}
tlv320aic23_mclk = clk_get(dev, "mclk");
if (IS_ERR(tlv320aic23_mclk)) {
printk(KERN_ERR "Could not get mclk clock\n");
- return -ENODEV;
+ err = PTR_ERR(tlv320aic23_mclk);
+ goto err2;
}
/*
if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) {
printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
err = -ECANCELED;
- goto err1;
+ goto err3;
}
}
(uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
return 0;
-err1:
+
+err3:
clk_put(tlv320aic23_mclk);
+err2:
platform_device_del(osk_snd_device);
+err1:
platform_device_put(osk_snd_device);
return err;
static void __exit osk_soc_exit(void)
{
+ clk_put(tlv320aic23_mclk);
platform_device_unregister(osk_snd_device);
}
config SND_PXA2XX_SOC
tristate "SoC Audio for the Intel PXA2xx chip"
depends on ARCH_PXA
+ select SND_ARM
select SND_PXA2XX_LIB
help
Say Y or M if you want to add support for codecs attached to
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
+ mutex_lock(&codec->mutex);
+
/* check the jack status at stream startup */
corgi_ext_control(codec);
+
+ mutex_unlock(&codec->mutex);
+
return 0;
}
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
+ mutex_lock(&codec->mutex);
+
/* check the jack status at stream startup */
magician_ext_control(codec);
+ mutex_unlock(&codec->mutex);
+
return 0;
}
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
+ mutex_lock(&codec->mutex);
+
/* check the jack status at stream startup */
poodle_ext_control(codec);
+
+ mutex_unlock(&codec->mutex);
+
return 0;
}
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
+ mutex_lock(&codec->mutex);
+
/* check the jack status at stream startup */
spitz_ext_control(codec);
+
+ mutex_unlock(&codec->mutex);
+
return 0;
}
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
+ mutex_lock(&codec->mutex);
+
/* check the jack status at stream startup */
tosa_ext_control(codec);
+
+ mutex_unlock(&codec->mutex);
+
return 0;
}
tristate "SoC Audio for the Samsung S3CXXXX chips"
depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210
select S3C64XX_DMA if ARCH_S3C64XX
+ select S3C2410_DMA if ARCH_S3C2410
help
Say Y or M if you want to add support for codecs attached to
the S3C24XX AC97 or I2S interfaces. You will also need to
16000,
44100,
48000,
- 88200,
};
static struct snd_pcm_hw_constraint_list hw_rates = {
};
static struct platform_device *s3c24xx_snd_device;
-static struct clk *xtal;
static int rx1950_startup(struct snd_pcm_substream *substream)
{
case 44100:
case 88200:
clk_source = S3C24XX_CLKSRC_MPLL;
- fs_mode = S3C2410_IISMOD_256FS;
- div = clk_get_rate(xtal) / (256 * rate);
- if (clk_get_rate(xtal) % (256 * rate) > (128 * rate))
- div++;
+ fs_mode = S3C2410_IISMOD_384FS;
+ div = 1;
break;
default:
printk(KERN_ERR "%s: rate %d is not supported\n",
/* set MCLK division for sample rate */
ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
- S3C2410_IISMOD_384FS);
+ fs_mode);
if (ret < 0)
return ret;
goto err_plat_add;
}
- xtal = clk_get(&s3c24xx_snd_device->dev, "xtal");
-
- if (IS_ERR(xtal)) {
- ret = PTR_ERR(xtal);
- platform_device_unregister(s3c24xx_snd_device);
- goto err_clk;
- }
-
return 0;
-err_clk:
err_plat_add:
err_plat_alloc:
err_gpio_conf:
platform_device_unregister(s3c24xx_snd_device);
snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
hp_jack_gpios);
- clk_put(xtal);
gpio_free(S3C2410_GPA(1));
}
}
mout_epll = clk_get(NULL, "mout_epll");
- if (IS_ERR(fout_epll)) {
+ if (IS_ERR(mout_epll)) {
printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
__func__);
ret = -EINVAL;
}
sclk_spdif = clk_get(NULL, "sclk_spdif");
- if (IS_ERR(fout_epll)) {
+ if (IS_ERR(sclk_spdif)) {
printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
__func__);
ret = -EINVAL;
.rate_max = 1562500,
},
.ops = &s6000_i2s_dai_ops,
-}
+};
static int __devinit s6000_i2s_probe(struct platform_device *pdev)
{
}
res = request_irq(params->irq, s6000_pcm_irq, IRQF_SHARED,
- s6000_soc_platform.name, pcm);
+ "s6000-audio", pcm);
if (res) {
printk(KERN_ERR "s6000-pcm couldn't get IRQ\n");
return res;
snd_soc_dapm_sync(codec);
- snd_ctl_add(codec->snd_card, snd_ctl_new1(&audio_out_mux, codec));
+ snd_ctl_add(codec->card->snd_card, snd_ctl_new1(&audio_out_mux, codec));
return 0;
}
struct fsi_stream playback;
struct fsi_stream capture;
+ long rate;
+
u32 mst_ctrl;
};
{
struct fsi_priv *fsi = fsi_get_priv(substream);
int is_play = fsi_is_play(substream);
+ struct fsi_master *master = fsi_get_master(fsi);
+ int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
fsi_irq_disable(fsi, is_play);
fsi_clk_ctrl(fsi, 0);
+ set_rate = master->info->set_rate;
+ if (set_rate && fsi->rate)
+ set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
+ fsi->rate = 0;
+
pm_runtime_put_sync(dai->dev);
}
{
struct fsi_priv *fsi = fsi_get_priv(substream);
struct fsi_master *master = fsi_get_master(fsi);
- int (*set_rate)(int is_porta, int rate) = master->info->set_rate;
+ int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
int fsi_ver = master->core->ver;
- int is_play = fsi_is_play(substream);
+ long rate = params_rate(params);
int ret;
- /* if slave mode, set_rate is not needed */
- if (!fsi_is_master_mode(fsi, is_play))
+ set_rate = master->info->set_rate;
+ if (!set_rate)
return 0;
- /* it is error if no set_rate */
- if (!set_rate)
- return -EIO;
+ ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1);
+ if (ret < 0) /* error */
+ return ret;
- ret = set_rate(fsi_is_port_a(fsi), params_rate(params));
+ fsi->rate = rate;
if (ret > 0) {
u32 data = 0;
static int __devexit sh4_soc_dai_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai));
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai));
return 0;
}
#ifdef CONFIG_SND_SOC_AC97_BUS
/* register any AC97 codecs */
for (i = 0; i < card->num_rtd; i++) {
- ret = soc_register_ac97_dai_link(&card->rtd[i]);
- if (ret < 0) {
- printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
- goto probe_dai_err;
- }
+ ret = soc_register_ac97_dai_link(&card->rtd[i]);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
+ while (--i >= 0)
+ soc_unregister_ac97_dai_link(&card->rtd[i]);
+ goto probe_dai_err;
}
+ }
#endif
card->instantiated = 1;
for (i = 0; i < count; i++) {
dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
- if (dai == NULL)
- return -ENOMEM;
+ if (dai == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
/* create DAI component name */
dai->name = fmt_multiple_name(dev, &dai_drv[i]);
pr_debug("Registered DAI '%s'\n", dai->name);
}
+ mutex_lock(&client_mutex);
snd_soc_instantiate_cards();
+ mutex_unlock(&client_mutex);
return 0;
err:
return 0;
error:
- for (i--; i >= 0; i--)
- snd_soc_unregister_dai(dev);
-
if (codec->reg_cache)
kfree(codec->reg_cache);
kfree(codec->name);
struct snd_soc_dapm_widget *b,
int sort[])
{
- if (a->codec != b->codec)
- return (unsigned long)a - (unsigned long)b;
if (sort[a->id] != sort[b->id])
return sort[a->id] - sort[b->id];
if (a->reg != b->reg)
return a->reg - b->reg;
+ if (a->codec != b->codec)
+ return (unsigned long)a->codec - (unsigned long)b->codec;
return 0;
}
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sound.h>
if (max_tries < 1)
max_tries = 1;
- /* ssc_div must be a power of 2. */
+ /* ssc_div must be even. */
ssc_div = (ssc_div + 1) & ~1UL;
if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) {
if (child_pid > 0)
kill(child_pid, SIGTERM);
- if (signr == -1)
+ if (signr == -1 || signr == SIGUSR1)
return;
signal(signr, SIG_DFL);
atexit(sig_atexit);
signal(SIGCHLD, sig_handler);
signal(SIGINT, sig_handler);
+ signal(SIGUSR1, sig_handler);
if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
perror("failed to create pipes");
execvp(argv[0], (char **)argv);
perror(argv[0]);
+ kill(getppid(), SIGUSR1);
exit(-1);
}
if (err < 0)
err = event__synthesize_kernel_mmap(process_synthesized_event,
session, machine, "_stext");
- if (err < 0) {
- pr_err("Couldn't record kernel reference relocation symbol.\n");
- return err;
- }
+ if (err < 0)
+ pr_err("Couldn't record kernel reference relocation symbol\n"
+ "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
+ "Check /proc/kallsyms permission or run as root.\n");
err = event__synthesize_modules(process_synthesized_event,
session, machine);
- if (err < 0) {
- pr_err("Couldn't record kernel reference relocation symbol.\n");
- return err;
- }
+ if (err < 0)
+ pr_err("Couldn't record kernel module information.\n"
+ "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
+ "Check /proc/modules permission or run as root.\n");
+
if (perf_guest)
perf_session__process_machines(session, event__synthesize_guest_os);
}
}
- if (quiet)
+ if (quiet || signr == SIGUSR1)
return 0;
fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
/*
* We set id to -1 if the data file doesn't contain sample
- * ids. Check for this and avoid walking through the entire
- * list of ids which may be large.
+ * ids. This can happen when the data file contains one type
+ * of event and in that case, the header can still store the
+ * event attribute information. Check for this and avoid
+ * walking through the entire list of ids which may be large.
*/
- if (id == -1ULL)
+ if (id == -1ULL) {
+ if (header->attrs > 0)
+ return &header->attr[0]->attr;
return NULL;
+ }
for (i = 0; i < header->attrs; i++) {
struct perf_header_attr *attr = header->attr[i];
{
struct rb_node **p = &self->rb_node;
struct rb_node *parent = NULL;
- struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
+ struct symbol_name_rb_node *symn, *s;
+
+ symn = container_of(sym, struct symbol_name_rb_node, sym);
while (*p != NULL) {
parent = *p;
struct machine *machine = kmaps->machine;
struct map *curr_map = map;
struct symbol *pos;
- int count = 0;
+ int count = 0, moved = 0;
struct rb_root *root = &self->symbols[map->type];
struct rb_node *next = rb_first(root);
int kernel_range = 0;
char dso_name[PATH_MAX];
struct dso *dso;
+ if (count == 0) {
+ curr_map = map;
+ goto filter_symbol;
+ }
+
if (self->kernel == DSO_TYPE_GUEST_KERNEL)
snprintf(dso_name, sizeof(dso_name),
"[guest.kernel].%d",
map_groups__insert(kmaps, curr_map);
++kernel_range;
}
-
+filter_symbol:
if (filter && filter(curr_map, pos)) {
discard_symbol: rb_erase(&pos->rb_node, root);
symbol__delete(pos);
if (curr_map != map) {
rb_erase(&pos->rb_node, root);
symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
- }
- count++;
+ ++moved;
+ } else
+ ++count;
}
}
dso__set_loaded(curr_map->dso, curr_map->type);
}
- return count;
+ return count + moved;
}
int dso__load_kallsyms(struct dso *self, const char *filename,
return kernel;
}
+struct process_args {
+ u64 start;
+};
+
+static int symbol__in_kernel(void *arg, const char *name,
+ char type __used, u64 start)
+{
+ struct process_args *args = arg;
+
+ if (strchr(name, '['))
+ return 0;
+
+ args->start = start;
+ return 1;
+}
+
+/* Figure out the start address of kernel map from /proc/kallsyms */
+static u64 machine__get_kernel_start_addr(struct machine *machine)
+{
+ const char *filename;
+ char path[PATH_MAX];
+ struct process_args args;
+
+ if (machine__is_host(machine)) {
+ filename = "/proc/kallsyms";
+ } else {
+ if (machine__is_default_guest(machine))
+ filename = (char *)symbol_conf.default_guest_kallsyms;
+ else {
+ sprintf(path, "%s/proc/kallsyms", machine->root_dir);
+ filename = path;
+ }
+ }
+
+ if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
+ return 0;
+
+ return args.start;
+}
+
int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
{
enum map_type type;
+ u64 start = machine__get_kernel_start_addr(self);
for (type = 0; type < MAP__NR_TYPES; ++type) {
struct kmap *kmap;
- self->vmlinux_maps[type] = map__new2(0, kernel, type);
+ self->vmlinux_maps[type] = map__new2(start, kernel, type);
if (self->vmlinux_maps[type] == NULL)
return -1;
*/
#include <linux/stringify.h>
+#include <asm-generic/vmlinux.lds.h>
.section .init.ramfs,"a"
__irf_start:
.incbin __stringify(INITRAMFS_IMAGE)
__irf_end:
.section .init.ramfs.info,"a"
-.globl __initramfs_size
-__initramfs_size:
+.globl VMLINUX_SYMBOL(__initramfs_size)
+VMLINUX_SYMBOL(__initramfs_size):
#ifdef CONFIG_64BIT
.quad __irf_end - __irf_start
#else